server/game/src/questnpc.cpp

972 lines
25 KiB
C++
Raw Normal View History

2022-03-05 12:44:06 +02:00
#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;
2022-03-05 12:44:06 +02:00
// 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);
2023-05-01 08:10:00 +03:00
strlcpy(buf + is, pde->d_name, sizeof(buf) - is);
2022-03-05 12:44:06 +02:00
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()));
2022-03-05 12:44:06 +02:00
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);
}
}