summaryrefslogtreecommitdiff
path: root/src/game-server/quest.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/game-server/quest.cpp')
-rw-r--r--src/game-server/quest.cpp138
1 files changed, 138 insertions, 0 deletions
diff --git a/src/game-server/quest.cpp b/src/game-server/quest.cpp
new file mode 100644
index 00000000..f6675127
--- /dev/null
+++ b/src/game-server/quest.cpp
@@ -0,0 +1,138 @@
+/*
+ * The Mana World Server
+ * Copyright 2007 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#include <algorithm>
+#include <list>
+#include <map>
+#include <string>
+
+#include "game-server/quest.hpp"
+
+#include "defines.h"
+#include "game-server/accountconnection.hpp"
+#include "game-server/character.hpp"
+#include "game-server/deathlistener.hpp"
+#include "utils/logger.h"
+
+typedef std::list< QuestCallback > QuestCallbacks;
+typedef std::map< std::string, QuestCallbacks > PendingVariables;
+
+struct PendingQuest
+{
+ Character *character;
+ PendingVariables variables;
+};
+
+typedef std::map< int, PendingQuest > PendingQuests;
+
+static PendingQuests pendingQuests;
+
+bool getQuestVar(Character *ch, std::string const &name, std::string &value)
+{
+ std::map< std::string, std::string >::iterator
+ i = ch->questCache.find(name);
+ if (i == ch->questCache.end()) return false;
+ value = i->second;
+ return true;
+}
+
+void setQuestVar(Character *ch, std::string const &name,
+ std::string const &value)
+{
+ std::map< std::string, std::string >::iterator
+ i = ch->questCache.lower_bound(name);
+ if (i == ch->questCache.end() || i->first != name)
+ {
+ ch->questCache.insert(i, std::make_pair(name, value));
+ }
+ else if (i->second == value)
+ {
+ return;
+ }
+ else
+ {
+ i->second = value;
+ }
+ accountHandler->updateQuestVar(ch, name, value);
+}
+
+/**
+ * Listener for deleting related quests when a character disappears.
+ */
+struct QuestDeathListener: DeathListener
+{
+ void deleted(Being *b)
+ {
+ int id = static_cast< Character * >(b)->getDatabaseID();
+ pendingQuests.erase(id);
+ }
+};
+
+static QuestDeathListener questDeathListener;
+
+void recoverQuestVar(Character *ch, std::string const &name,
+ QuestCallback const &f)
+{
+ int id = ch->getDatabaseID();
+ PendingQuests::iterator i = pendingQuests.lower_bound(id);
+ if (i == pendingQuests.end() || i->first != id)
+ {
+ i = pendingQuests.insert(i, std::make_pair(id, PendingQuest()));
+ i->second.character = ch;
+ /* Register a listener, because we cannot afford to get invalid
+ pointers, when we finally recover the variable. */
+ ch->addDeathListener(&questDeathListener);
+ }
+ i->second.variables[name].push_back(f);
+ accountHandler->requestQuestVar(ch, name);
+}
+
+void recoveredQuestVar(int id, std::string const &name,
+ std::string const &value)
+{
+ PendingQuests::iterator i = pendingQuests.find(id);
+ if (i == pendingQuests.end()) return;
+ PendingVariables &variables = i->second.variables;
+ PendingVariables::iterator j = variables.find(name);
+ if (j == variables.end())
+ {
+ LOG_ERROR("Account server recovered an unexpected quest variable.");
+ return;
+ }
+
+ Character *ch = i->second.character;
+ ch->questCache[name] = value;
+
+ // Call the registered callbacks.
+ for (QuestCallbacks::const_iterator k = j->second.begin(),
+ k_end = j->second.end(); k != k_end; ++k)
+ {
+ k->handler(ch, name, value, k->data);
+ }
+
+ variables.erase(j);
+ if (variables.empty())
+ {
+ pendingQuests.erase(i);
+ }
+}