Friend asked me about source edit 'show player storage in Quest Log'. I thought I can make it better. I decided to add 'creatureevent' that returns modified 'mission description from quests.xml'
Few source changes and you can generate quest description (Quest Log) for X player in LUA.
Tested on TFS 0.3.6, should work with 0.4/0.2 after small changes.
In file creatureevent.cpp:
Under:
Paste:
Under:
Paste:
Under:
Paste:
At end of file paste:
In file creatureevent.h:
Under:
Paste:
Under:
Paste:
In file luascript.cpp:
Under:
Paste:
In file luascript.h:
Under:
Paste:
In file quests.cpp:
Under:
Paste:
IN PLACE OF:
Paste:
COMPILE AND THAT PART IS DONE
In data/creaturescripts/creaturescripts.xml
Add:
Create file data/creaturescripts/scripts/questdescription.lua
Paste in it:
AND IT'S READY TO USE!
Time for some examples of code in data/XML/quests.xml
Normal descriptions will work as they worked before. If you want use LUA code then first 3 letters of description must be LUA and then LUA code that MUST return string
You must remember that in your LUA code you cannot use "
Show if player has all required items or he still needs some (shows how many left):
Show how many dragons player killed (from storage):
Few source changes and you can generate quest description (Quest Log) for X player in LUA.
Tested on TFS 0.3.6, should work with 0.4/0.2 after small changes.
In file creatureevent.cpp:
Under:
Code:
else if(tmpStr == "preparedeath")
m_type = CREATURE_EVENT_PREPAREDEATH;
Code:
else if(tmpStr == "questdescription")
m_type = CREATURE_EVENT_QUEST_DESCRIPTION;
Under:
Code:
case CREATURE_EVENT_PREPAREDEATH:
return "onPrepareDeath";
Code:
case CREATURE_EVENT_QUEST_DESCRIPTION:
return "getQuestDescription";
Under:
Code:
case CREATURE_EVENT_PREPAREDEATH:
return "cid, deathList";
Code:
case CREATURE_EVENT_QUEST_DESCRIPTION:
return "cid, description";
At end of file paste:
Code:
uint32_t CreatureEvent::executeGetQuestDescription(Creature* creature, std::string& description)
{
//getQuestDescription(cid, description)
if(m_interface->reserveEnv())
{
ScriptEnviroment* env = m_interface->getEnv();
if(m_scripted == EVENT_SCRIPT_BUFFER)
{
env->setRealPos(creature->getPosition());
std::stringstream scriptstream;
scriptstream << "local cid = " << env->addThing(creature) << std::endl;
scriptstream << "local description = " << description << std::endl;
scriptstream << m_scriptData;
if(m_interface->loadBuffer(scriptstream.str()))
{
lua_State* L = m_interface->getState();
description = m_interface->getGlobalString(L, "_result", "");
}
m_interface->releaseEnv();
return 1;
}
else
{
#ifdef __DEBUG_LUASCRIPTS__
std::stringstream desc;
desc << creature->getName();
env->setEventDesc(desc.str());
#endif
env->setScriptId(m_scriptId, m_interface);
env->setRealPos(creature->getPosition());
lua_State* L = m_interface->getState();
m_interface->pushFunction(m_scriptId);
lua_pushnumber(L, env->addThing(creature));
lua_pushstring(L, description.c_str());
description = m_interface->callFunction2(2);
m_interface->releaseEnv();
return 1;
}
}
else
{
std::cout << "[Error - CreatureEvent::executeGetQuestDescription] Call stack overflow." << std::endl;
return 0;
}
}
In file creatureevent.h:
Under:
Code:
CREATURE_EVENT_DEATH,
Code:
CREATURE_EVENT_QUEST_DESCRIPTION,
Under:
Code:
uint32_t executePrepareDeath(Creature* creature, DeathList deathList);
Code:
uint32_t executeGetQuestDescription(Creature* creature, std::string& description);
In file luascript.cpp:
Under:
Code:
bool LuaScriptInterface::callFunction(uint32_t params)
{
int32_t size = lua_gettop(m_luaState), handler = lua_gettop(m_luaState) - params;
lua_pushcfunction(m_luaState, handleFunction);
bool result = false;
lua_insert(m_luaState, handler);
if(lua_pcall(m_luaState, params, 1, handler))
LuaScriptInterface::error(NULL, LuaScriptInterface::popString(m_luaState));
else
result = (int32_t)LuaScriptInterface::popBoolean(m_luaState);
lua_remove(m_luaState, handler);
if((lua_gettop(m_luaState) + (int32_t)params + 1) != size)
LuaScriptInterface::error(NULL, "Stack size changed!");
return result;
}
Code:
std::string LuaScriptInterface::callFunction2(uint32_t params)
{
int32_t size = lua_gettop(m_luaState), handler = lua_gettop(m_luaState) - params;
lua_pushcfunction(m_luaState, handleFunction);
std::string result = "";
lua_insert(m_luaState, handler);
if(lua_pcall(m_luaState, params, 1, handler))
LuaScriptInterface::error(NULL, LuaScriptInterface::popString(m_luaState));
else
result = LuaScriptInterface::popString(m_luaState);
lua_remove(m_luaState, handler);
if((lua_gettop(m_luaState) + (int32_t)params + 1) != size)
LuaScriptInterface::error(NULL, "Stack size changed!");
return result;
}
In file luascript.h:
Under:
Code:
std::string callFunction2(uint32_t params);
Code:
static int32_t handleFunction(lua_State* L);
In file quests.cpp:
Under:
Code:
#include "tools.h"
Code:
#include "creatureevent.h"
IN PLACE OF:
Code:
std::string Mission::getDescription(Player* player)
{
std::string value;
if(!player->getStorage(storageId, value))
return "Couldn't retrieve a valid player storage, please report to a gamemaster.";
if(state.size())
{
std::string ret = state;
replaceString(ret, "|STATE|", value);
return ret;
}
if(atoi(value.c_str()) >= endValue)
return states.rbegin()->second;
for(int32_t i = endValue; i >= startValue; --i)
{
if(!player->getStorage(storageId, value) || atoi(value.c_str()) != i)
continue;
std::string ret = states[i - startValue];
replaceString(ret, "|STATE|", value);
return ret;
}
return "Couldn't retrieve any mission description, please report to a gamemaster.";
}
Code:
std::string Mission::getDescription(Player* player)
{
std::string value;
if(!player->getStorage(storageId, value))
return "Couldn't retrieve a valid player storage, please report to a gamemaster.";
if(state.size())
{
std::string ret = state;
replaceString(ret, "|STATE|", value);
CreatureEventList questDescriptionEvents = player->getCreatureEvents(CREATURE_EVENT_QUEST_DESCRIPTION);
for(CreatureEventList::iterator it = questDescriptionEvents.begin(); it != questDescriptionEvents.end(); ++it)
{
if(player)
{
(*it)->executeGetQuestDescription(player, ret);
}
}
return ret;
}
if(atoi(value.c_str()) >= endValue)
{
std::string ret = states.rbegin()->second;
CreatureEventList questDescriptionEvents = player->getCreatureEvents(CREATURE_EVENT_QUEST_DESCRIPTION);
for(CreatureEventList::iterator it = questDescriptionEvents.begin(); it != questDescriptionEvents.end(); ++it)
{
if(player)
{
(*it)->executeGetQuestDescription(player, ret);
}
}
return ret;
}
for(int32_t i = endValue; i >= startValue; --i)
{
if(!player->getStorage(storageId, value) || atoi(value.c_str()) != i)
continue;
std::string ret = states[i - startValue];
replaceString(ret, "|STATE|", value);
CreatureEventList questDescriptionEvents = player->getCreatureEvents(CREATURE_EVENT_QUEST_DESCRIPTION);
for(CreatureEventList::iterator it = questDescriptionEvents.begin(); it != questDescriptionEvents.end(); ++it)
{
if(player)
{
(*it)->executeGetQuestDescription(player, ret);
}
}
return ret;
}
return "Couldn't retrieve any mission description, please report to a gamemaster.";
}
COMPILE AND THAT PART IS DONE
In data/creaturescripts/creaturescripts.xml
Add:
Code:
<event type="login" name="QuestLogin" event="script" value="questdescription.lua"/>
<event type="questdescription" name="QuestDescription" event="script" value="questdescription.lua"/>
Create file data/creaturescripts/scripts/questdescription.lua
Paste in it:
Code:
function onLogin(cid)
registerCreatureEvent(cid, "QuestDescription")
return true
end
function getQuestDescription(cid, description)
if(string.sub(description,1,3) == "LUA") then
function luaExecuter(...)
local v = tostring(arg[2])
if v:len() > 0 then
return v
else
return "LUA DESCRIPTION - NO RETURN VALUE"
end
end
return luaExecuter(pcall(loadstring('local cid = ' .. cid .. ' ' .. string.sub(description,4))))
else
return description
end
end
AND IT'S READY TO USE!
Time for some examples of code in data/XML/quests.xml
Normal descriptions will work as they worked before. If you want use LUA code then first 3 letters of description must be LUA and then LUA code that MUST return string
You must remember that in your LUA code you cannot use "
Show if player has all required items or he still needs some (shows how many left):
Code:
<missionstate id="1" description="LUA if(getCreatureStorage(cid,123) >= 5) then return 'Yes! You collected all required items, now you can go to NPC.' else return 'No! You still need ' .. (5 - getCreatureStorage(cid,123)) .. ' required items' end" />
Code:
<missionstate id="1" description="LUA return 'You killed ' .. getCreatureStorage(cid,12345) .. ' dragons!' " />