server/game/src/questnpc.cpp

972 lines
25 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "stdafx.h"
#include <fstream>
#include <sstream>
#include "questmanager.h"
#include "profiler.h"
#include "config.h"
#include "char.h"
// questpc.h: PC::typedef Quest
// questpc.h: PC::typedef map<unsigned int, QuestState> QuestInfo;
// typedef
namespace quest
{
NPC::NPC()
{
m_vnum = 0;
}
NPC::~NPC()
{
}
void NPC::Set(unsigned int vnum, const string & script_name)
{
m_vnum = vnum;
char buf[PATH_MAX];
CQuestManager::TEventNameMap::iterator itEventName = CQuestManager::instance().m_mapEventName.begin();
while (itEventName != CQuestManager::instance().m_mapEventName.end())
{
typeof(itEventName) it = itEventName;
++itEventName;
for (itertype(g_setQuestObjectDir) itObjectDir = g_setQuestObjectDir.begin(); itObjectDir != g_setQuestObjectDir.end(); ++itObjectDir)
{
int is = snprintf(buf, sizeof(buf), "%s/%s/%s/", itObjectDir->c_str(), script_name.c_str(), it->first.c_str());
if (is < 0 || is >= (int) sizeof(buf))
is = sizeof(buf) - 1;
//sys_log(0, "XXX %s", buf);
int event_index = it->second;
DIR * pdir = opendir(buf);
if (!pdir)
continue;
dirent * pde;
while ((pde = readdir(pdir)))
{
if (pde->d_name[0] == '.')
continue;
if (!strncasecmp(pde->d_name, "CVS", 3))
continue;
sys_log(1, "QUEST reading %s", pde->d_name);
strlcpy(buf + is, pde->d_name, sizeof(buf) - is);
LoadStateScript(event_index, buf, pde->d_name);
}
closedir(pdir);
}
}
}
void NPC::LoadStateScript(int event_index, const char* filename, const char* script_name)
{
ifstream inf(filename);
const string s(script_name);
size_t i = s.find('.');
CQuestManager & q = CQuestManager::instance();
//
// script_name examples:
// christmas_tree.start -> argument not exist
//
// guild_manage.start.0.script -> argument exist
// guild_manage.start.0.when
// guild_manage.start.0.arg
///////////////////////////////////////////////////////////////////////////
// Quest name
const string stQuestName = s.substr(0, i);
int quest_index = q.GetQuestIndexByName(stQuestName);
if (quest_index == 0)
{
fprintf(stderr, "cannot find quest index for %s\n", stQuestName.c_str());
assert(!"cannot find quest index");
return;
}
///////////////////////////////////////////////////////////////////////////
// State name
string stStateName;
size_t j = i;
i = s.find('.', i + 1);
if (i == s.npos)
stStateName = s.substr(j + 1, s.npos);
else
stStateName = s.substr(j + 1, i - j - 1);
int state_index = q.GetQuestStateIndex(stQuestName, stStateName);
///////////////////////////////////////////////////////////////////////////
sys_log(0, "QUEST loading %s : %s [STATE] %s",
filename, stQuestName.c_str(), stStateName.c_str());
if (i == s.npos)
{
// like in example: christmas_tree.start
istreambuf_iterator<char> ib(inf), ie;
copy(ib, ie, back_inserter(m_mapOwnQuest[event_index][quest_index][q.GetQuestStateIndex(stQuestName, stStateName)].m_code));
}
else
{
//
// like in example: guild_manage.start.0.blah
// NOTE : currently, only CHAT script uses argument
//
///////////////////////////////////////////////////////////////////////////
// <20><><EFBFBD><EFBFBD> Index (<28><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD>Ƿ<EFBFBD> <20>ִ<EFBFBD> <20><><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD> index <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>)
j = i;
i = s.find('.', i + 1);
if (i == s.npos)
{
sys_err("invalid QUEST STATE index [%s] [%s]",filename, script_name);
return;
}
const int index = strtol(s.substr(j + 1, i - j - 1).c_str(), NULL, 10);
///////////////////////////////////////////////////////////////////////////
// Type name
j = i;
i = s.find('.', i + 1);
if (i != s.npos)
{
sys_err("invalid QUEST STATE name [%s] [%s]",filename, script_name);
return;
}
const string type_name = s.substr(j + 1, i - j - 1);
///////////////////////////////////////////////////////////////////////////
istreambuf_iterator<char> ib(inf), ie;
m_mapOwnArgQuest[event_index][quest_index][state_index].resize(std::max<size_t>(index + 1, m_mapOwnArgQuest[event_index][quest_index][state_index].size()));
if (type_name == "when")
{
copy(ib, ie, back_inserter(m_mapOwnArgQuest[event_index][quest_index][state_index][index].when_condition));
}
else if (type_name == "arg")
{
string s;
getline(inf, s);
m_mapOwnArgQuest[event_index][quest_index][state_index][index].arg.clear();
for (string::iterator it = s.begin(); it != s.end(); ++it)
{
m_mapOwnArgQuest[event_index][quest_index][state_index][index].arg+=*it;
}
}
else if (type_name == "script")
{
copy(ib, ie, back_inserter(m_mapOwnArgQuest[event_index][quest_index][state_index][index].script.m_code));
m_mapOwnArgQuest[event_index][quest_index][state_index][index].quest_index = quest_index;
m_mapOwnArgQuest[event_index][quest_index][state_index][index].state_index = state_index;
}
}
}
bool NPC::OnEnterState(PC& pc, DWORD quest_index, int state)
{
return ExecuteEventScript(pc, QUEST_ENTER_STATE_EVENT, quest_index, state);
}
bool NPC::OnLeaveState(PC& pc, DWORD quest_index, int state)
{
return ExecuteEventScript(pc, QUEST_LEAVE_STATE_EVENT, quest_index, state);
}
bool NPC::OnLetter(PC& pc, DWORD quest_index, int state)
{
return ExecuteEventScript(pc, QUEST_LETTER_EVENT, quest_index, state);
}
bool NPC::OnTarget(PC & pc, DWORD dwQuestIndex, const char * c_pszTargetName, const char * c_pszVerb, bool & bRet)
{
sys_log(1, "OnTarget begin %s verb %s qi %u", c_pszTargetName, c_pszVerb, dwQuestIndex);
bRet = false;
PC::QuestInfoIterator itPCQuest = pc.quest_find(dwQuestIndex);
if (itPCQuest == pc.quest_end())
{
sys_log(1, "no quest");
return false;
}
int iState = itPCQuest->second.st;
AArgQuestScriptType & r = m_mapOwnArgQuest[QUEST_TARGET_EVENT][dwQuestIndex];
AArgQuestScriptType::iterator it = r.find(iState);
if (it == r.end())
{
sys_log(1, "no target event, state %d", iState);
return false;
}
vector<AArgScript>::iterator it_vec = it->second.begin();
int iTargetLen = strlen(c_pszTargetName);
while (it_vec != it->second.end())
{
AArgScript & argScript = *(it_vec++);
const char * c_pszArg = argScript.arg.c_str();
sys_log(1, "OnTarget compare %s %d", c_pszArg, argScript.arg.length());
if (strncmp(c_pszArg, c_pszTargetName, iTargetLen))
continue;
const char * c_pszArgVerb = strchr(c_pszArg, '.');
if (!c_pszArgVerb)
continue;
if (strcmp(++c_pszArgVerb, c_pszVerb))
continue;
if (argScript.when_condition.size() > 0)
sys_log(1, "OnTarget when %s size %d", &argScript.when_condition[0], argScript.when_condition.size());
if (argScript.when_condition.size() != 0 && !IsScriptTrue(&argScript.when_condition[0], argScript.when_condition.size()))
continue;
sys_log(1, "OnTarget execute qi %u st %d code %s", dwQuestIndex, iState, (const char *) argScript.script.GetCode());
bRet = CQuestManager::ExecuteQuestScript(pc, dwQuestIndex, iState, argScript.script.GetCode(), argScript.script.GetSize());
bRet = true;
return true;
}
return false;
}
bool NPC::OnAttrIn(PC& pc)
{
return HandleEvent(pc, QUEST_ATTR_IN_EVENT);
}
bool NPC::OnAttrOut(PC& pc)
{
return HandleEvent(pc, QUEST_ATTR_OUT_EVENT);
}
bool NPC::OnTakeItem(PC& pc)
{
return HandleEvent(pc, QUEST_ITEM_TAKE_EVENT);
}
bool NPC::OnUseItem(PC& pc, bool bReceiveAll)
{
if (bReceiveAll)
return HandleReceiveAllEvent(pc, QUEST_ITEM_USE_EVENT);
else
return HandleEvent(pc, QUEST_ITEM_USE_EVENT);
}
bool NPC::OnSIGUse(PC& pc, bool bReceiveAll)
{
if (bReceiveAll)
return HandleReceiveAllEvent(pc, QUEST_SIG_USE_EVENT);
else
return HandleEvent(pc, QUEST_SIG_USE_EVENT);
}
bool NPC::OnClick(PC& pc)
{
return HandleEvent(pc, QUEST_CLICK_EVENT);
}
bool NPC::OnServerTimer(PC& pc)
{
return HandleReceiveAllEvent(pc, QUEST_SERVER_TIMER_EVENT);
}
bool NPC::OnTimer(PC& pc)
{
return HandleEvent(pc, QUEST_TIMER_EVENT);
}
bool NPC::OnKill(PC & pc)
{
//PROF_UNIT puOnKill("quest::NPC::OnKill");
if (m_vnum)
{
//PROF_UNIT puOnKill1("onk1");
return HandleEvent(pc, QUEST_KILL_EVENT);
}
else
{
//PROF_UNIT puOnKill2("onk2");
return HandleReceiveAllEvent(pc, QUEST_KILL_EVENT);
}
}
bool NPC::OnPartyKill(PC & pc)
{
if (m_vnum)
{
return HandleEvent(pc, QUEST_PARTY_KILL_EVENT);
}
else
{
return HandleReceiveAllEvent(pc, QUEST_PARTY_KILL_EVENT);
}
}
bool NPC::OnLevelUp(PC& pc)
{
return HandleReceiveAllEvent(pc, QUEST_LEVELUP_EVENT);
}
bool NPC::OnLogin(PC& pc, const char * c_pszQuestName)
{
/*
if (c_pszQuestName)
{
DWORD dwQI = CQuestManager::instance().GetQuestIndexByName(c_pszQuestName);
if (dwQI)
{
std::string stQuestName(c_pszQuestName);
CQuestManager & q = CQuestManager::instance();
QuestMapType::iterator qmit = m_mapOwnQuest[QUEST_LOGIN_EVENT].begin();
while (qmit != m_mapOwnQuest[QUEST_LOGIN_EVENT].end())
{
if (qmit->first != dwQI)
{
++qmit;
continue;
}
int iState = pc.GetFlag(stQuestName + "__status");
AQuestScriptType::iterator qsit;
if ((qsit = qmit->second.find(iState)) != qmit->second.end())
{
return q.ExecuteQuestScript(pc, stQuestName, iState, qsit->second.GetCode(), qsit->second.GetSize(), NULL, true);
}
++qmit;
}
sys_err("Cannot find any code for %s", c_pszQuestName);
}
else
sys_err("Cannot find quest index by %s", c_pszQuestName);
}
*/
bool bRet = HandleReceiveAllNoWaitEvent(pc, QUEST_LOGIN_EVENT);
HandleReceiveAllEvent(pc, QUEST_LETTER_EVENT);
return bRet;
}
bool NPC::OnLogout(PC& pc)
{
return HandleReceiveAllEvent(pc, QUEST_LOGOUT_EVENT);
}
bool NPC::OnUnmount(PC& pc)
{
return HandleReceiveAllEvent(pc, QUEST_UNMOUNT_EVENT);
}
struct FuncMissHandleEvent
{
std::vector <DWORD> vdwNewStartQuestIndices;
int size;
FuncMissHandleEvent() : vdwNewStartQuestIndices(0), size(0)
{}
bool Matched()
{
return vdwNewStartQuestIndices.size() != 0;
}
void operator()(PC::QuestInfoIterator& itPCQuest, NPC::QuestMapType::iterator& itQuestMap)
{
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
DWORD dwQuestIndex = itQuestMap->first;
if (NPC::HasStartState(itQuestMap->second) && CQuestManager::instance().CanStartQuest(dwQuestIndex))
{
size++;
vdwNewStartQuestIndices.push_back(dwQuestIndex);
}
}
};
struct FuncMatchHandleEvent
{
bool bMatched;
std::vector <DWORD> vdwQuesIndices;
std::vector <int> viPCStates;
std::vector <const char*> vcodes;
std::vector <int> vcode_sizes;
int size;
//DWORD dwQuestIndex;
//int iPCState;
//const char* code;
//int code_size;
FuncMatchHandleEvent()
: bMatched(false), vdwQuesIndices(0), viPCStates(0), vcodes(0), vcode_sizes(0), size(0)
{}
bool Matched()
{
return bMatched;
}
void operator()(PC::QuestInfoIterator& itPCQuest, NPC::QuestMapType::iterator& itQuestMap)
{
NPC::AQuestScriptType::iterator itQuestScript;
int iState = itPCQuest->second.st;
if ((itQuestScript = itQuestMap->second.find(iState)) != itQuestMap->second.end())
{
bMatched = true;
size++;
vdwQuesIndices.push_back(itQuestMap->first);
viPCStates.push_back(iState);
vcodes.push_back(itQuestScript->second.GetCode());
vcode_sizes.push_back(itQuestScript->second.GetSize());
}
}
};
bool NPC::HandleEvent(PC& pc, int EventIndex)
{
if (EventIndex < 0 || EventIndex >= QUEST_EVENT_COUNT)
{
sys_err("QUEST invalid EventIndex : %d", EventIndex);
return false;
}
if (pc.IsRunning())
{
if (test_server)
{
CQuestManager & mgr = CQuestManager::instance();
sys_err("QUEST There's suspended quest state, can't run new quest state (quest: %s pc: %s)",
pc.GetCurrentQuestName().c_str(),
mgr.GetCurrentCharacterPtr() ? mgr.GetCurrentCharacterPtr()->GetName() : "<none>");
}
return false;
}
FuncMissHandleEvent fMiss;
FuncMatchHandleEvent fMatch;
MatchingQuest(pc, m_mapOwnQuest[EventIndex], fMatch, fMiss);
bool r = false;
if (fMatch.Matched())
{
for (int i = 0; i < fMatch.size; i++)
{
if ( i != 0 ) {
//2012.05.14 <<3C><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>> : <20><><EFBFBD><EFBFBD>Ʈ <20>Ŵ<EFBFBD><C5B4><EFBFBD><EFBFBD><EFBFBD> m_pCurrentPC<50><43> <20>ٲ<EFBFBD><D9B2><EFBFBD> <20><><EFBFBD><20>߻<EFBFBD><DFBB>Ͽ<EFBFBD>,
//<2F>ΰ<EFBFBD> <20>̻<EFBFBD><CCBB><EFBFBD> <20><>ũ<EFBFBD><C5A9>Ʈ<EFBFBD><C6AE> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20>ι<EFBFBD>° <20><><EFBFBD>ʹ<EFBFBD> <20><><EFBFBD><EFBFBD>Ʈ <20>Ŵ<EFBFBD><C5B4><EFBFBD><EFBFBD><EFBFBD> PC <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>Ѵ<EFBFBD>.
PC * pPC = CQuestManager::instance().GetPC(pc.GetID());
}
CQuestManager::ExecuteQuestScript(pc, fMatch.vdwQuesIndices[i], fMatch.viPCStates[i],
fMatch.vcodes[i], fMatch.vcode_sizes[i]);
}
r = true;
}
if (fMiss.Matched())
{
QuestMapType& rmapEventOwnQuest = m_mapOwnQuest[EventIndex];
for (int i = 0; i < fMiss.size; i++)
{
AStateScriptType& script = rmapEventOwnQuest[fMiss.vdwNewStartQuestIndices[i]][0];
CQuestManager::ExecuteQuestScript(pc, fMiss.vdwNewStartQuestIndices[i], 0, script.GetCode(), script.GetSize());
}
r = true;
}
else
{
return r;
}
return true;
}
struct FuncMissHandleReceiveAllEvent
{
bool bHandled;
FuncMissHandleReceiveAllEvent()
{
bHandled = false;
}
void operator() (PC::QuestInfoIterator& itPCQuest, NPC::QuestMapType::iterator& itQuestMap)
{
DWORD dwQuestIndex = itQuestMap->first;
if (NPC::HasStartState(itQuestMap->second) && CQuestManager::instance().CanStartQuest(dwQuestIndex))
{
const NPC::AQuestScriptType & QuestScript = itQuestMap->second;
itertype(QuestScript) it = QuestScript.find(QUEST_START_STATE_INDEX);
if (it != QuestScript.end())
{
bHandled = true;
CQuestManager::ExecuteQuestScript(
*CQuestManager::instance().GetCurrentPC(),
dwQuestIndex,
QUEST_START_STATE_INDEX,
it->second.GetCode(),
it->second.GetSize());
}
}
}
};
struct FuncMatchHandleReceiveAllEvent
{
bool bHandled;
FuncMatchHandleReceiveAllEvent()
{
bHandled = false;
}
void operator() (PC::QuestInfoIterator& itPCQuest, NPC::QuestMapType::iterator& itQuestMap)
{
const NPC::AQuestScriptType& QuestScript = itQuestMap->second;
int iPCState = itPCQuest->second.st;
itertype(QuestScript) itQuestScript = QuestScript.find(iPCState);
if (itQuestScript != QuestScript.end())
{
bHandled = true;
CQuestManager::ExecuteQuestScript(
*CQuestManager::instance().GetCurrentPC(),
itQuestMap->first,
iPCState,
itQuestScript->second.GetCode(),
itQuestScript->second.GetSize());
}
}
};
bool NPC::HandleReceiveAllEvent(PC& pc, int EventIndex)
{
if (EventIndex < 0 || EventIndex >= QUEST_EVENT_COUNT)
{
sys_err("QUEST invalid EventIndex : %d", EventIndex);
return false;
}
if (pc.IsRunning())
{
if (test_server)
{
CQuestManager & mgr = CQuestManager::instance();
sys_err("QUEST There's suspended quest state, can't run new quest state (quest: %s pc: %s)",
pc.GetCurrentQuestName().c_str(),
mgr.GetCurrentCharacterPtr() ? mgr.GetCurrentCharacterPtr()->GetName() : "<none>");
}
return false;
}
FuncMissHandleReceiveAllEvent fMiss;
FuncMatchHandleReceiveAllEvent fMatch;
MatchingQuest(pc, m_mapOwnQuest[EventIndex], fMatch, fMiss);
return fMiss.bHandled || fMatch.bHandled;
}
struct FuncDoNothing
{
void operator()(PC::QuestInfoIterator& itPCQuest, NPC::QuestMapType::iterator& itQuestMap)
{
}
};
struct FuncMissHandleReceiveAllNoWaitEvent
{
bool bHandled;
FuncMissHandleReceiveAllNoWaitEvent()
{
bHandled = false;
}
void operator()(PC::QuestInfoIterator& itPCQuest, NPC::QuestMapType::iterator& itQuestMap)
{
DWORD dwQuestIndex = itQuestMap->first;
if (NPC::HasStartState(itQuestMap->second) && CQuestManager::instance().CanStartQuest(dwQuestIndex))
{
const NPC::AQuestScriptType& QuestScript = itQuestMap->second;
itertype(QuestScript) it = QuestScript.find(QUEST_START_STATE_INDEX);
if (it != QuestScript.end())
{
bHandled = true;
PC* pPC = CQuestManager::instance().GetCurrentPC();
if (CQuestManager::ExecuteQuestScript(
*pPC,
dwQuestIndex,
QUEST_START_STATE_INDEX,
it->second.GetCode(),
it->second.GetSize()))
{
sys_err("QUEST NOT END RUNNING on Login/Logout - %s",
CQuestManager::instance().GetQuestNameByIndex(itQuestMap->first).c_str());
QuestState& rqs = *pPC->GetRunningQuestState();
CQuestManager::instance().CloseState(rqs);
pPC->EndRunning();
}
}
}
}
};
struct FuncMatchHandleReceiveAllNoWaitEvent
{
bool bHandled;
FuncMatchHandleReceiveAllNoWaitEvent()
{
bHandled = false;
}
void operator()(PC::QuestInfoIterator & itPCQuest, NPC::QuestMapType::iterator & itQuestMap)
{
const NPC::AQuestScriptType & QuestScript = itQuestMap->second;
int iPCState = itPCQuest->second.st;
itertype(QuestScript) itQuestScript = QuestScript.find(iPCState);
if (itQuestScript != QuestScript.end())
{
PC * pPC = CQuestManager::instance().GetCurrentPC();
if (CQuestManager::ExecuteQuestScript(
*pPC,
itQuestMap->first,
iPCState,
itQuestScript->second.GetCode(),
itQuestScript->second.GetSize()))
{
sys_err("QUEST NOT END RUNNING on Login/Logout - %s",
CQuestManager::instance().GetQuestNameByIndex(itQuestMap->first).c_str());
QuestState& rqs = *pPC->GetRunningQuestState();
CQuestManager::instance().CloseState(rqs);
pPC->EndRunning();
}
bHandled = true;
}
}
};
bool NPC::HandleReceiveAllNoWaitEvent(PC& pc, int EventIndex)
{
//cerr << EventIndex << endl;
if (EventIndex<0 || EventIndex>=QUEST_EVENT_COUNT)
{
sys_err("QUEST invalid EventIndex : %d", EventIndex);
return false;
}
/*
if (pc.IsRunning())
{
if (test_server)
{
CQuestManager & mgr = CQuestManager::instance();
sys_err("QUEST There's suspended quest state, can't run new quest state (quest: %s pc: %s)",
pc.GetCurrentQuestName().c_str(),
mgr.GetCurrentCharacterPtr() ? mgr.GetCurrentCharacterPtr()->GetName() : "<none>");
}
return false;
}
*/
//FuncDoNothing fMiss;
FuncMissHandleReceiveAllNoWaitEvent fMiss;
FuncMatchHandleReceiveAllNoWaitEvent fMatch;
QuestMapType& rmapEventOwnQuest = m_mapOwnQuest[EventIndex];
MatchingQuest(pc, rmapEventOwnQuest, fMatch, fMiss);
return fMatch.bHandled || fMiss.bHandled;
}
bool NPC::OnInfo(PC & pc, unsigned int quest_index)
{
const int EventIndex = QUEST_INFO_EVENT;
if (pc.IsRunning())
{
if (test_server)
{
CQuestManager & mgr = CQuestManager::instance();
sys_err("QUEST There's suspended quest state, can't run new quest state (quest: %s pc: %s)",
pc.GetCurrentQuestName().c_str(),
mgr.GetCurrentCharacterPtr() ? mgr.GetCurrentCharacterPtr()->GetName() : "<none>");
}
return false;
}
PC::QuestInfoIterator itPCQuest = pc.quest_find(quest_index);
if (pc.quest_end() == itPCQuest)
{
sys_err("QUEST no quest by (quest %u)", quest_index);
return false;
}
QuestMapType & rmapEventOwnQuest = m_mapOwnQuest[EventIndex];
QuestMapType::iterator itQuestMap = rmapEventOwnQuest.find(quest_index);
const char * questName = CQuestManager::instance().GetQuestNameByIndex(quest_index).c_str();
if (itQuestMap == rmapEventOwnQuest.end())
{
sys_err("QUEST no info event (quest %s)", questName);
return false;
}
AQuestScriptType::iterator itQuestScript = itQuestMap->second.find(itPCQuest->second.st);
if (itQuestScript == itQuestMap->second.end())
{
sys_err("QUEST no info script by state %d (quest %s)", itPCQuest->second.st, questName);
return false;
}
CQuestManager::ExecuteQuestScript(pc, quest_index, itPCQuest->second.st, itQuestScript->second.GetCode(), itQuestScript->second.GetSize());
return true;
}
bool NPC::OnButton(PC & pc, unsigned int quest_index)
{
const int EventIndex = QUEST_BUTTON_EVENT;
if (pc.IsRunning())
{
if (test_server)
{
CQuestManager & mgr = CQuestManager::instance();
sys_err("QUEST There's suspended quest state, can't run new quest state (quest: %s pc: %s)",
pc.GetCurrentQuestName().c_str(),
mgr.GetCurrentCharacterPtr() ? mgr.GetCurrentCharacterPtr()->GetName() : "<none>");
}
return false;
}
PC::QuestInfoIterator itPCQuest = pc.quest_find(quest_index);
QuestMapType & rmapEventOwnQuest = m_mapOwnQuest[EventIndex];
QuestMapType::iterator itQuestMap = rmapEventOwnQuest.find(quest_index);
// <20>׷<EFBFBD> <20><><EFBFBD><EFBFBD>Ʈ<EFBFBD><C6AE> <20><><EFBFBD><EFBFBD>
if (itQuestMap == rmapEventOwnQuest.end())
return false;
int iState = 0;
if (itPCQuest != pc.quest_end())
{
iState = itPCQuest->second.st;
}
else
{
// <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>ұ<EFBFBD><D2B1><EFBFBD>?
if (CQuestManager::instance().CanStartQuest(itQuestMap->first, pc) && HasStartState(itQuestMap->second))
iState = 0;
else
return false;
}
AQuestScriptType::iterator itQuestScript=itQuestMap->second.find(iState);
if (itQuestScript==itQuestMap->second.end())
return false;
CQuestManager::ExecuteQuestScript(pc, quest_index, iState, itQuestScript->second.GetCode(), itQuestScript->second.GetSize());
return true;
}
struct FuncMissChatEvent
{
FuncMissChatEvent(vector<AArgScript*>& rAvailScript)
: rAvailScript(rAvailScript)
{}
void operator()(PC::QuestInfoIterator& itPCQuest, NPC::ArgQuestMapType::iterator& itQuestMap)
{
if (CQuestManager::instance().CanStartQuest(itQuestMap->first) && NPC::HasStartState(itQuestMap->second))
{
size_t i;
for (i = 0; i < itQuestMap->second[QUEST_START_STATE_INDEX].size(); ++i)
{
if (itQuestMap->second[QUEST_START_STATE_INDEX][i].when_condition.size() == 0 ||
IsScriptTrue(&itQuestMap->second[QUEST_START_STATE_INDEX][i].when_condition[0], itQuestMap->second[QUEST_START_STATE_INDEX][i].when_condition.size()))
rAvailScript.push_back(&itQuestMap->second[QUEST_START_STATE_INDEX][i]);
}
}
}
vector<AArgScript*>& rAvailScript;
};
struct FuncMatchChatEvent
{
FuncMatchChatEvent(vector<AArgScript*>& rAvailScript)
: rAvailScript(rAvailScript)
{}
void operator()(PC::QuestInfoIterator& itPCQuest, NPC::ArgQuestMapType::iterator& itQuestMap)
{
int iState = itPCQuest->second.st;
map<int,vector<AArgScript> >::iterator itQuestScript = itQuestMap->second.find(iState);
if (itQuestScript != itQuestMap->second.end())
{
size_t i;
for (i = 0; i < itQuestMap->second[iState].size(); i++)
{
if ( itQuestMap->second[iState][i].when_condition.size() == 0 ||
IsScriptTrue(&itQuestMap->second[iState][i].when_condition[0], itQuestMap->second[iState][i].when_condition.size()))
rAvailScript.push_back(&itQuestMap->second[iState][i]);
}
}
}
vector<AArgScript*>& rAvailScript;
};
bool NPC::OnChat(PC& pc)
{
if (pc.IsRunning())
{
if (test_server)
{
CQuestManager & mgr = CQuestManager::instance();
sys_err("QUEST There's suspended quest state, can't run new quest state (quest: %s pc: %s)",
pc.GetCurrentQuestName().c_str(),
mgr.GetCurrentCharacterPtr() ? mgr.GetCurrentCharacterPtr()->GetName() : "<none>");
}
return false;
}
const int EventIndex = QUEST_CHAT_EVENT;
vector<AArgScript*> AvailScript;
FuncMatchChatEvent fMatch(AvailScript);
FuncMissChatEvent fMiss(AvailScript);
MatchingQuest(pc, m_mapOwnArgQuest[EventIndex], fMatch, fMiss);
if (AvailScript.empty())
return false;
{
ostringstream os;
os << "select(";
os << '"' << ScriptToString(AvailScript[0]->arg.c_str()) << '"';
for (size_t i = 1; i < AvailScript.size(); i++)
{
os << ",\"" << ScriptToString(AvailScript[i]->arg.c_str()) << '"';
}
os << ", '"<<LC_TEXT("<EFBFBD>ݱ<EFBFBD>")<<"'";
os << ")";
CQuestManager::ExecuteQuestScript(pc, "QUEST_CHAT_TEMP_QUEST", 0, os.str().c_str(), os.str().size(), &AvailScript, false);
}
return true;
}
bool NPC::HasChat()
{
return !m_mapOwnArgQuest[QUEST_CHAT_EVENT].empty();
}
bool NPC::ExecuteEventScript(PC& pc, int EventIndex, DWORD dwQuestIndex, int iState)
{
QuestMapType& rQuest = m_mapOwnQuest[EventIndex];
itertype(rQuest) itQuest = rQuest.find(dwQuestIndex);
if (itQuest == rQuest.end())
{
sys_log(0, "ExecuteEventScript ei %d qi %u is %d - NO QUEST", EventIndex, dwQuestIndex, iState);
return false;
}
AQuestScriptType& rScript = itQuest->second;
itertype(itQuest->second) itState = rScript.find(iState);
if (itState == rScript.end())
{
sys_log(0, "ExecuteEventScript ei %d qi %u is %d - NO STATE", EventIndex, dwQuestIndex, iState);
return false;
}
sys_log(0, "ExecuteEventScript ei %d qi %u is %d", EventIndex, dwQuestIndex, iState);
CQuestManager::instance().SetCurrentEventIndex(EventIndex);
return CQuestManager::ExecuteQuestScript(pc, dwQuestIndex, iState, itState->second.GetCode(), itState->second.GetSize());
}
bool NPC::OnPickupItem(PC& pc)
{
if (m_vnum == 0)
return HandleReceiveAllEvent(pc, QUEST_ITEM_PICK_EVENT);
else
return HandleEvent(pc, QUEST_ITEM_PICK_EVENT);
}
//<2F><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20>׽<EFBFBD>Ʈ
bool NPC::OnItemInformer(PC& pc, unsigned int vnum)
{
return HandleEvent(pc, QUEST_ITEM_INFORMER_EVENT);
}
}