server/game/src/questpc.cpp

727 lines
18 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 "constants.h"
#include "questmanager.h"
#include "packet.h"
#include "buffer_manager.h"
#include "char.h"
#include "desc_client.h"
#include "questevent.h"
extern int test_server;
namespace quest
{
PC::PC() :
m_bIsGivenReward(false),
m_bShouldSendDone(false),
m_dwID(0),
m_RunningQuestState(0),
m_iSendToClient(0),
m_bLoaded(false),
m_iLastState(0),
m_dwWaitConfirmFromPID(0),
m_bConfirmWait(false)
{
}
PC::~PC()
{
Destroy();
}
void PC::Destroy()
{
ClearTimer();
}
void PC::SetID(DWORD dwID)
{
m_dwID = dwID;
m_bShouldSendDone = false;
}
const string & PC::GetCurrentQuestName() const
{
return m_stCurQuest;
}
int PC::GetCurrentQuestIndex()
{
return CQuestManager::instance().GetQuestIndexByName(GetCurrentQuestName());
}
void PC::SetFlag(const string& name, int value, bool bSkipSave)
{
if ( test_server )
sys_log(0, "QUEST Setting flag %s %d", name.c_str(),value);
else
sys_log(1, "QUEST Setting flag %s %d", name.c_str(),value);
if (value == 0)
{
DeleteFlag(name);
return;
}
TFlagMap::iterator it = m_FlagMap.find(name);
if (it == m_FlagMap.end())
m_FlagMap.insert(make_pair(name, value));
else if (it->second != value)
it->second = value;
else
bSkipSave = true;
if (!bSkipSave)
SaveFlag(name, value);
}
bool PC::DeleteFlag(const string & name)
{
TFlagMap::iterator it = m_FlagMap.find(name);
if (it != m_FlagMap.end())
{
m_FlagMap.erase(it);
SaveFlag(name, 0);
return true;
}
return false;
}
int PC::GetFlag(const string & name)
{
TFlagMap::iterator it = m_FlagMap.find(name);
if (it != m_FlagMap.end())
{
sys_log(1, "QUEST getting flag %s %d", name.c_str(),it->second);
return it->second;
}
return 0;
}
void PC::SaveFlag(const string & name, int value)
{
TFlagMap::iterator it = m_FlagSaveMap.find(name);
if (it == m_FlagSaveMap.end())
m_FlagSaveMap.insert(make_pair(name, value));
else if (it->second != value)
it->second = value;
}
// only from lua call
void PC::SetCurrentQuestStateName(const string& state_name)
{
SetFlag(m_stCurQuest + ".__status", CQuestManager::Instance().GetQuestStateIndex(m_stCurQuest,state_name));
}
void PC::SetQuestState(const string& quest_name, const string& state_name)
{
SetQuestState(quest_name, CQuestManager::Instance().GetQuestStateIndex(quest_name, state_name));
}
void PC::SetQuestState(const string& quest_name, int new_state_index)
{
int iNowState = GetFlag(quest_name + ".__status");
if (iNowState != new_state_index)
AddQuestStateChange(quest_name, iNowState, new_state_index);
}
void PC::AddQuestStateChange(const string& quest_name, int prev_state, int next_state)
{
DWORD dwQuestIndex = CQuestManager::instance().GetQuestIndexByName(quest_name);
sys_log(0, "QUEST reserve Quest State Change quest %s[%u] from %d to %d", quest_name.c_str(), dwQuestIndex, prev_state, next_state);
m_QuestStateChange.push_back(TQuestStateChangeInfo(dwQuestIndex, prev_state, next_state));
}
void PC::SetQuest(const string& quest_name, QuestState& qs)
{
//sys_log(0, "PC SetQuest %s", quest_name.c_str());
unsigned int qi = CQuestManager::instance().GetQuestIndexByName(quest_name);
QuestInfo::iterator it = m_QuestInfo.find(qi);
if (it == m_QuestInfo.end())
m_QuestInfo.insert(make_pair(qi, qs));
else
it->second = qs;
m_stCurQuest = quest_name;
m_RunningQuestState = &m_QuestInfo[qi];
m_iSendToClient = 0;
m_iLastState = qs.st;
SetFlag(quest_name + ".__status", qs.st);
//m_RunningQuestState->iIndex = GetCurrentQuestBeginFlag();
m_RunningQuestState->iIndex = qi;
m_bShouldSendDone = false;
//if (GetCurrentQuestBeginFlag())
//{
//m_bSendToClient = true;
//}
}
void PC::AddTimer(const string & name, LPEVENT pEvent)
{
RemoveTimer(name);
m_TimerMap.insert(make_pair(name, pEvent));
sys_log(0, "QUEST add timer %p %d", get_pointer(pEvent), m_TimerMap.size());
}
void PC::RemoveTimerNotCancel(const string & name)
{
TTimerMap::iterator it = m_TimerMap.find(name);
if (it != m_TimerMap.end())
{
sys_log(0, "QUEST remove with no cancel %p", get_pointer(it->second));
m_TimerMap.erase(it);
}
sys_log(1, "QUEST timer map size %d by RemoveTimerNotCancel", m_TimerMap.size());
}
void PC::RemoveTimer(const string & name)
{
TTimerMap::iterator it = m_TimerMap.find(name);
if (it != m_TimerMap.end())
{
sys_log(0, "QUEST remove timer %p", get_pointer(it->second));
CancelTimerEvent(&it->second);
m_TimerMap.erase(it);
}
sys_log(1, "QUEST timer map size %d by RemoveTimer", m_TimerMap.size());
}
void PC::ClearTimer()
{
sys_log(0, "QUEST clear timer %d", m_TimerMap.size());
TTimerMap::iterator it = m_TimerMap.begin();
while (it != m_TimerMap.end())
{
CancelTimerEvent(&it->second);
++it;
}
m_TimerMap.clear();
}
void PC::SetCurrentQuestStartFlag()
{
if (!GetCurrentQuestBeginFlag())
{
SetCurrentQuestBeginFlag();
}
}
void PC::SetCurrentQuestDoneFlag()
{
if (GetCurrentQuestBeginFlag())
{
ClearCurrentQuestBeginFlag();
}
}
void PC::SendQuestInfoPakcet()
{
assert(m_iSendToClient);
assert(m_RunningQuestState);
packet_quest_info qi;
qi.header = HEADER_GC_QUEST_INFO;
qi.size = sizeof(struct packet_quest_info);
qi.index = m_RunningQuestState->iIndex;
qi.flag = m_iSendToClient;
TEMP_BUFFER buf;
buf.write(&qi, sizeof(qi));
if (m_iSendToClient & QUEST_SEND_ISBEGIN)
{
BYTE temp = m_RunningQuestState->bStart?1:0;
buf.write(&temp,1);
qi.size+=1;
sys_log(1, "QUEST BeginFlag %d", (int)temp);
}
if (m_iSendToClient & QUEST_SEND_TITLE)
{
m_RunningQuestState->_title.reserve(30+1);
buf.write(m_RunningQuestState->_title.c_str(), 30+1);
qi.size+=30+1;
sys_log(1, "QUEST Title %s", m_RunningQuestState->_title.c_str());
}
if (m_iSendToClient & QUEST_SEND_CLOCK_NAME)
{
m_RunningQuestState->_clock_name.reserve(16+1);
buf.write(m_RunningQuestState->_clock_name.c_str(), 16+1);
qi.size+=16+1;
sys_log(1, "QUEST Clock Name %s", m_RunningQuestState->_clock_name.c_str());
}
if (m_iSendToClient & QUEST_SEND_CLOCK_VALUE)
{
buf.write(&m_RunningQuestState->_clock_value, sizeof(int));
qi.size+=4;
sys_log(1, "QUEST Clock Value %d", m_RunningQuestState->_clock_value);
}
if (m_iSendToClient & QUEST_SEND_COUNTER_NAME)
{
m_RunningQuestState->_counter_name.reserve(16+1);
buf.write(m_RunningQuestState->_counter_name.c_str(), 16+1);
qi.size+=16+1;
sys_log(1, "QUEST Counter Name %s", m_RunningQuestState->_counter_name.c_str());
}
if (m_iSendToClient & QUEST_SEND_COUNTER_VALUE)
{
buf.write(&m_RunningQuestState->_counter_value, sizeof(int));
qi.size+=4;
sys_log(1, "QUEST Counter Value %d", m_RunningQuestState->_counter_value);
}
if (m_iSendToClient & QUEST_SEND_ICON_FILE)
{
m_RunningQuestState->_icon_file.reserve(24+1);
buf.write(m_RunningQuestState->_icon_file.c_str(), 24+1);
qi.size+=24+1;
sys_log(1, "QUEST Icon File %s", m_RunningQuestState->_icon_file.c_str());
}
CQuestManager::instance().GetCurrentCharacterPtr()->GetDesc()->Packet(buf.read_peek(),buf.size());
m_iSendToClient = 0;
}
void PC::EndRunning()
{
// unlocked locked npc
{
LPCHARACTER npc = CQuestManager::instance().GetCurrentNPCCharacterPtr();
LPCHARACTER ch = CQuestManager::instance().GetCurrentCharacterPtr();
// npc <20>־<EFBFBD><D6BE><EFBFBD> <20><><EFBFBD><EFBFBD>
if (npc && !npc->IsPC())
{
// <20><> <20><><EFBFBD>Ǿ<EFBFBD><C7BE><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
if (ch->GetPlayerID() == npc->GetQuestNPCID())
{
npc->SetQuestNPCID(0);
sys_log(0, "QUEST NPC lock isn't unlocked : pid %u", ch->GetPlayerID());
CQuestManager::instance().WriteRunningStateToSyserr();
}
}
}
// commit data
if (HasReward())
{
Save();
LPCHARACTER ch = CQuestManager::instance().GetCurrentCharacterPtr();
if (ch != NULL) {
Reward(ch);
ch->Save();
}
}
m_bIsGivenReward = false;
if (m_iSendToClient)
{
sys_log(1, "QUEST end running %d", m_iSendToClient);
SendQuestInfoPakcet();
}
if (m_RunningQuestState == NULL) {
sys_log(0, "Entered PC::EndRunning() with invalid running quest state");
return;
}
QuestState * pOldState = m_RunningQuestState;
int iNowState = m_RunningQuestState->st;
m_RunningQuestState = 0;
if (m_iLastState != iNowState)
{
LPCHARACTER ch = CQuestManager::instance().GetCurrentCharacterPtr();
DWORD dwQuestIndex = CQuestManager::instance().GetQuestIndexByName(m_stCurQuest);
if (ch)
{
SetFlag(m_stCurQuest + ".__status", m_iLastState);
CQuestManager::instance().LeaveState(ch->GetPlayerID(), dwQuestIndex, m_iLastState);
pOldState->st = iNowState;
SetFlag(m_stCurQuest + ".__status", iNowState);
CQuestManager::instance().EnterState(ch->GetPlayerID(), dwQuestIndex, iNowState);
if (GetFlag(m_stCurQuest + ".__status") == iNowState)
CQuestManager::instance().Letter(ch->GetPlayerID(), dwQuestIndex, iNowState);
}
}
DoQuestStateChange();
}
void PC::DoQuestStateChange()
{
LPCHARACTER ch = CQuestManager::instance().GetCurrentCharacterPtr();
std::vector<TQuestStateChangeInfo> vecQuestStateChange;
m_QuestStateChange.swap(vecQuestStateChange);
for (DWORD i=0; i<vecQuestStateChange.size(); ++i)
{
const TQuestStateChangeInfo& rInfo = vecQuestStateChange[i];
if (rInfo.quest_idx == 0)
continue;
DWORD dwQuestIdx = rInfo.quest_idx;
QuestInfoIterator it = quest_find(dwQuestIdx);
const string stQuestName = CQuestManager::instance().GetQuestNameByIndex(dwQuestIdx);
if (it == quest_end())
{
QuestState qs;
qs.st = 0;
m_QuestInfo.insert(make_pair(dwQuestIdx, qs));
SetFlag(stQuestName + ".__status", 0);
it = quest_find(dwQuestIdx);
}
sys_log(0, "QUEST change reserved Quest State Change quest %u from %d to %d (%d %d)", dwQuestIdx, rInfo.prev_state, rInfo.next_state, it->second.st, rInfo.prev_state );
assert(it->second.st == rInfo.prev_state);
CQuestManager::instance().LeaveState(ch->GetPlayerID(), dwQuestIdx, rInfo.prev_state);
it->second.st = rInfo.next_state;
SetFlag(stQuestName + ".__status", rInfo.next_state);
CQuestManager::instance().EnterState(ch->GetPlayerID(), dwQuestIdx, rInfo.next_state);
if (GetFlag(stQuestName + ".__status")==rInfo.next_state)
CQuestManager::instance().Letter(ch->GetPlayerID(), dwQuestIdx, rInfo.next_state);
}
}
void PC::CancelRunning()
{
// cancel data
m_RunningQuestState = 0;
m_iSendToClient = 0;
m_bShouldSendDone = false;
}
void PC::SetSendFlag(int idx)
{
m_iSendToClient |= idx;
}
void PC::ClearCurrentQuestBeginFlag()
{
//cerr << "iIndex " << m_RunningQuestState->iIndex << endl;
SetSendFlag(QUEST_SEND_ISBEGIN);
m_RunningQuestState->bStart = false;
//SetFlag(m_stCurQuest+".__isbegin", 0);
}
void PC::SetCurrentQuestBeginFlag()
{
CQuestManager& q = CQuestManager::instance();
int iQuestIndex = q.GetQuestIndexByName(m_stCurQuest);
m_RunningQuestState->bStart = true;
m_RunningQuestState->iIndex = iQuestIndex;
SetSendFlag(QUEST_SEND_ISBEGIN);
//SetFlag(m_stCurQuest+".__isbegin", iQuestIndex);
}
int PC::GetCurrentQuestBeginFlag()
{
return m_RunningQuestState?m_RunningQuestState->iIndex:0;
//return GetFlag(m_stCurQuest+".__isbegin");
}
void PC::SetCurrentQuestTitle(const string& title)
{
SetSendFlag(QUEST_SEND_TITLE);
m_RunningQuestState->_title = title;
}
void PC::SetQuestTitle(const string& quest, const string& title)
{
//SetSendFlag(QUEST_SEND_TITLE);
QuestInfo::iterator it = m_QuestInfo.find(CQuestManager::instance().GetQuestIndexByName(quest));
if (it != m_QuestInfo.end())
{
//(*it)->_title = title;
QuestState* old = m_RunningQuestState;
int old2 = m_iSendToClient;
std::string oldquestname = m_stCurQuest;
m_stCurQuest = quest;
m_RunningQuestState = &it->second;
m_iSendToClient = QUEST_SEND_TITLE;
m_RunningQuestState->iIndex = GetCurrentQuestBeginFlag();
SetCurrentQuestTitle(title);
SendQuestInfoPakcet();
m_stCurQuest = oldquestname;
m_RunningQuestState = old;
m_iSendToClient = old2;
}
}
void PC::SetCurrentQuestClockName(const string& name)
{
SetSendFlag(QUEST_SEND_CLOCK_NAME);
m_RunningQuestState->_clock_name = name;
}
void PC::SetCurrentQuestClockValue(int value)
{
SetSendFlag(QUEST_SEND_CLOCK_VALUE);
m_RunningQuestState->_clock_value = value;
}
void PC::SetCurrentQuestCounterName(const string& name)
{
SetSendFlag(QUEST_SEND_COUNTER_NAME);
m_RunningQuestState->_counter_name = name;
}
void PC::SetCurrentQuestCounterValue(int value)
{
SetSendFlag(QUEST_SEND_COUNTER_VALUE);
m_RunningQuestState->_counter_value = value;
}
void PC::SetCurrentQuestIconFile(const string& icon_file)
{
SetSendFlag(QUEST_SEND_ICON_FILE);
m_RunningQuestState->_icon_file = icon_file;
}
void PC::Save()
{
if (m_FlagSaveMap.empty())
return;
static std::vector<TQuestTable> s_table;
s_table.resize(m_FlagSaveMap.size());
int i = 0;
TFlagMap::iterator it = m_FlagSaveMap.begin();
while (it != m_FlagSaveMap.end())
{
const std::string & stComp = it->first;
int lValue = it->second;
++it;
int iPos = stComp.find(".");
if (iPos < 0)
{
sys_err("quest::PC::Save : cannot find . in FlagMap");
continue;
}
string stName;
stName.assign(stComp, 0, iPos);
string stState;
stState.assign(stComp, iPos + 1, stComp.length());
if (stName.length() == 0 || stState.length() == 0)
{
sys_err("quest::PC::Save : invalid quest data: %s", stComp.c_str());
continue;
}
sys_log(1, "QUEST Save Flag %s, %s %d (%d)", stName.c_str(), stState.c_str(), lValue, i);
if (stName.length() >= QUEST_NAME_MAX_LEN)
{
sys_err("quest::PC::Save : quest name overflow");
continue;
}
if (stState.length() >= QUEST_STATE_MAX_LEN)
{
sys_err("quest::PC::Save : quest state overflow");
continue;
}
TQuestTable & r = s_table[i++];
r.dwPID = m_dwID;
strncpy(r.szName, stName.c_str(), sizeof(r.szName));
strncpy(r.szState, stState.c_str(), sizeof(r.szState));
r.lValue = lValue;
}
if (i > 0)
{
sys_log(1, "QuestPC::Save %d", i);
db_clientdesc->DBPacketHeader(HEADER_GD_QUEST_SAVE, 0, sizeof(TQuestTable) * i);
db_clientdesc->Packet(&s_table[0], sizeof(TQuestTable) * i);
}
m_FlagSaveMap.clear();
}
bool PC::HasQuest(const string & quest_name)
{
unsigned int qi = CQuestManager::instance().GetQuestIndexByName(quest_name);
return m_QuestInfo.find(qi)!=m_QuestInfo.end();
}
QuestState & PC::GetQuest(const string & quest_name)
{
unsigned int qi = CQuestManager::instance().GetQuestIndexByName(quest_name);
return m_QuestInfo[qi];
}
void PC::GiveItem(const string& label, DWORD dwVnum, int count)
{
sys_log(1, "QUEST GiveItem %s %d %d", label.c_str(),dwVnum,count);
if (!GetFlag(m_stCurQuest+"."+label))
{
m_vRewardData.push_back(RewardData(RewardData::REWARD_TYPE_ITEM, dwVnum, count));
//SetFlag(m_stCurQuest+"."+label,1);
}
else
m_bIsGivenReward = true;
}
void PC::GiveExp(const string& label, DWORD exp)
{
sys_log(1, "QUEST GiveExp %s %d", label.c_str(),exp);
if (!GetFlag(m_stCurQuest+"."+label))
{
m_vRewardData.push_back(RewardData(RewardData::REWARD_TYPE_EXP, exp));
//SetFlag(m_stCurQuest+"."+label,1);
}
else
m_bIsGivenReward = true;
}
void PC::Reward(LPCHARACTER ch)
{
if (m_bIsGivenReward)
{
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<<3C><><EFBFBD><EFBFBD>Ʈ> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20>־<EFBFBD> <20>ٽ<EFBFBD> <20><><EFBFBD><EFBFBD> <20>ʽ<EFBFBD><CABD>ϴ<EFBFBD>."));
m_bIsGivenReward = false;
}
for (vector<RewardData>::iterator it = m_vRewardData.begin(); it != m_vRewardData.end(); ++it)
{
switch (it->type)
{
case RewardData::REWARD_TYPE_EXP:
sys_log(0, "EXP cur %d add %d next %d",ch->GetExp(), it->value1, ch->GetNextExp());
if (ch->GetExp() + it->value1 > ch->GetNextExp())
ch->PointChange(POINT_EXP, ch->GetNextExp() - 1 - ch->GetExp());
else
ch->PointChange(POINT_EXP, it->value1);
break;
case RewardData::REWARD_TYPE_ITEM:
ch->AutoGiveItem(it->value1, it->value2);
break;
case RewardData::REWARD_TYPE_NONE:
default:
sys_err("Invalid RewardData type");
break;
}
}
m_vRewardData.clear();
}
void PC::Build()
{
itertype(m_FlagMap) it;
for (it = m_FlagMap.begin(); it != m_FlagMap.end(); ++it)
{
if (it->first.size()>9 && it->first.compare(it->first.size()-9,9, ".__status") == 0)
{
DWORD dwQuestIndex = CQuestManager::instance().GetQuestIndexByName(it->first.substr(0, it->first.size()-9));
int state = it->second;
QuestState qs;
qs.st = state;
m_QuestInfo.insert(make_pair(dwQuestIndex, qs));
}
}
}
void PC::ClearQuest(const string& quest_name)
{
string quest_name_with_dot = quest_name + '.';
for (itertype(m_FlagMap) it = m_FlagMap.begin(); it!= m_FlagMap.end();)
{
itertype(m_FlagMap) itNow = it++;
if (itNow->second != 0 && itNow->first.compare(0, quest_name_with_dot.size(), quest_name_with_dot) == 0)
{
//m_FlagMap.erase(itNow);
SetFlag(itNow->first, 0);
}
}
ClearTimer();
quest::PC::QuestInfoIterator it = quest_begin();
unsigned int questindex = quest::CQuestManager::instance().GetQuestIndexByName(quest_name);
while (it!= quest_end())
{
if (it->first == questindex)
{
it->second.st = 0;
break;
}
++it;
}
}
void PC::SendFlagList(LPCHARACTER ch)
{
for (itertype(m_FlagMap) it = m_FlagMap.begin(); it!= m_FlagMap.end(); ++it)
{
if (it->first.size()>9 && it->first.compare(it->first.size()-9,9, ".__status") == 0)
{
const string quest_name = it->first.substr(0, it->first.size()-9);
const char* state_name = CQuestManager::instance().GetQuestStateName(quest_name, it->second);
ch->ChatPacket(CHAT_TYPE_INFO, "%s %s (%d)", quest_name.c_str(), state_name, it->second);
}
else
{
ch->ChatPacket(CHAT_TYPE_INFO, "%s %d", it->first.c_str(), it->second);
}
}
}
}