00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <cassert>
00023 #include <list>
00024 #include <map>
00025 #include <string>
00026
00027 #include "game-server/quest.hpp"
00028
00029 #include "defines.h"
00030 #include "game-server/accountconnection.hpp"
00031 #include "game-server/character.hpp"
00032 #include "game-server/eventlistener.hpp"
00033 #include "utils/logger.h"
00034
00035 typedef std::list< QuestCallback > QuestCallbacks;
00036 typedef std::map< std::string, QuestCallbacks > PendingVariables;
00037
00038 struct PendingQuest
00039 {
00040 Character *character;
00041 PendingVariables variables;
00042 };
00043
00044 typedef std::map< int, PendingQuest > PendingQuests;
00045
00046 static PendingQuests pendingQuests;
00047
00048 bool getQuestVar(Character *ch, const std::string &name, std::string &value)
00049 {
00050 std::map< std::string, std::string >::iterator
00051 i = ch->questCache.find(name);
00052 if (i == ch->questCache.end()) return false;
00053 value = i->second;
00054 return true;
00055 }
00056
00057 void setQuestVar(Character *ch, const std::string &name,
00058 const std::string &value)
00059 {
00060 std::map< std::string, std::string >::iterator
00061 i = ch->questCache.lower_bound(name);
00062 if (i == ch->questCache.end() || i->first != name)
00063 {
00064 ch->questCache.insert(i, std::make_pair(name, value));
00065 }
00066 else if (i->second == value)
00067 {
00068 return;
00069 }
00070 else
00071 {
00072 i->second = value;
00073 }
00074 accountHandler->updateQuestVar(ch, name, value);
00075 }
00076
00080 struct QuestDeathListener: EventDispatch
00081 {
00082 static void partialRemove(const EventListener *, Thing *);
00083
00084 static void fullRemove(const EventListener *, Character *);
00085
00086 QuestDeathListener()
00087 {
00088 removed = &partialRemove;
00089 disconnected = &fullRemove;
00090 }
00091 };
00092
00093 static QuestDeathListener questDeathDummy;
00094 static EventListener questDeathListener(&questDeathDummy);
00095
00096 void QuestDeathListener::partialRemove(const EventListener *, Thing *t)
00097 {
00098 int id = static_cast< Character * >(t)->getDatabaseID();
00099 PendingVariables &variables = pendingQuests[id].variables;
00100
00101 for (PendingVariables::iterator i = variables.begin(),
00102 i_end = variables.end(); i != i_end; ++i)
00103 {
00104 i->second.clear();
00105 }
00106
00107 }
00108
00109 void QuestDeathListener::fullRemove(const EventListener *, Character *ch)
00110 {
00111 ch->removeListener(&questDeathListener);
00112
00113 pendingQuests.erase(ch->getDatabaseID());
00114 }
00115
00116 void recoverQuestVar(Character *ch, const std::string &name,
00117 const QuestCallback &f)
00118 {
00119 assert(ch->questCache.find(name) == ch->questCache.end());
00120 int id = ch->getDatabaseID();
00121 PendingQuests::iterator i = pendingQuests.lower_bound(id);
00122 if (i == pendingQuests.end() || i->first != id)
00123 {
00124 i = pendingQuests.insert(i, std::make_pair(id, PendingQuest()));
00125 i->second.character = ch;
00126
00127
00128 ch->addListener(&questDeathListener);
00129 }
00130 i->second.variables[name].push_back(f);
00131 accountHandler->requestQuestVar(ch, name);
00132 }
00133
00134 void recoveredQuestVar(int id, const std::string &name,
00135 const std::string &value)
00136 {
00137 PendingQuests::iterator i = pendingQuests.find(id);
00138 if (i == pendingQuests.end()) return;
00139
00140 Character *ch = i->second.character;
00141 ch->removeListener(&questDeathListener);
00142
00143 PendingVariables &variables = i->second.variables;
00144 PendingVariables::iterator j = variables.find(name);
00145 if (j == variables.end())
00146 {
00147 LOG_ERROR("Account server recovered an unexpected quest variable.");
00148 return;
00149 }
00150
00151 ch->questCache[name] = value;
00152
00153
00154 for (QuestCallbacks::const_iterator k = j->second.begin(),
00155 k_end = j->second.end(); k != k_end; ++k)
00156 {
00157 k->handler(ch, name, value, k->data);
00158 }
00159
00160 variables.erase(j);
00161 if (variables.empty())
00162 {
00163 pendingQuests.erase(i);
00164 }
00165 }