From 020bb7c43135289a801f411f75c8c588e94ff31b Mon Sep 17 00:00:00 2001
From: Andrei Karas <akaras@inbox.ru>
Date: Mon, 26 Sep 2016 19:22:28 +0300
Subject: Add support for quest fields in quests window.

Quest attributes: {@@var1}, {@@var2}, {@@var3}, {@@time}
---
 src/CMakeLists.txt               |  1 +
 src/Makefile.am                  |  1 +
 src/gui/windows/questswindow.cpp | 51 +++++++++++++++++++++++++-------------
 src/gui/windows/questswindow.h   | 12 ++++++---
 src/gui/windows/skilldialog.cpp  |  2 +-
 src/gui/windows/skilldialog.h    |  2 +-
 src/net/eathena/questrecv.cpp    |  2 --
 src/resources/questvar.h         | 53 ++++++++++++++++++++++++++++++++++++++++
 8 files changed, 99 insertions(+), 25 deletions(-)
 create mode 100644 src/resources/questvar.h

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 64677c3b0..d71075615 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -721,6 +721,7 @@ SET(SRCS
     resources/questeffect.h
     resources/questitem.h
     resources/questitemtext.h
+    resources/questvar.h
     enums/resources/questtype.h
     resources/db/palettedb.cpp
     resources/db/palettedb.h
diff --git a/src/Makefile.am b/src/Makefile.am
index 3c5a51275..15a8d2865 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -393,6 +393,7 @@ SRC += events/actionevent.h \
 	      resources/questeffect.h \
 	      resources/questitem.h \
 	      resources/questitemtext.h \
+	      resources/questvar.h \
 	      enums/resources/questtype.h \
 	      resources/resource.cpp \
 	      resources/resource.h \
diff --git a/src/gui/windows/questswindow.cpp b/src/gui/windows/questswindow.cpp
index 308d38da5..9e07285d8 100644
--- a/src/gui/windows/questswindow.cpp
+++ b/src/gui/windows/questswindow.cpp
@@ -189,7 +189,7 @@ void QuestsWindow::loadXmlFile(const std::string &fileName,
             const int id = XML::getProperty(varNode, "id", 0);
             if (id < 0)
                 continue;
-            mVars[id] = 0;
+            mVars[id] = QuestVar();
             for_each_xml_child_node(questNode, varNode)
             {
                 if (xmlNameEqual(questNode, "quest"))
@@ -298,6 +298,7 @@ void QuestsWindow::loadQuest(const int var, const XmlNodePtr node)
                 std::string()));
         }
     }
+    quest->var = var;
     mQuests[var].push_back(quest);
 }
 
@@ -338,11 +339,11 @@ void QuestsWindow::action(const ActionEvent &event)
 
 void QuestsWindow::updateQuest(const int var,
                                const int val1,
-                               const int val2 A_UNUSED,
-                               const int val3 A_UNUSED,
-                               const int time A_UNUSED)
+                               const int val2,
+                               const int val3,
+                               const int time1)
 {
-    mVars[var] = val1;
+    mVars[var] = QuestVar(val1, val2, val3, time1);
 }
 
 void QuestsWindow::rebuild(const bool playSound)
@@ -357,10 +358,10 @@ void QuestsWindow::rebuild(const bool playSound)
     int updatedQuest = -1;
     int newCompleteStatus = -1;
 
-    FOR_EACH (IntMapCIter, it, mVars)
+    FOR_EACH (NpcQuestVarMapCIter, it, mVars)
     {
         const int var = (*it).first;
-        const int val = (*it).second;
+        const QuestVar &val = (*it).second;
         const std::vector<QuestItem*> &quests = mQuests[var];
         FOR_EACH (std::vector<QuestItem*>::const_iterator, it2, quests)
         {
@@ -368,14 +369,20 @@ void QuestsWindow::rebuild(const bool playSound)
                 continue;
             QuestItem *const quest = *it2;
             // complete quest
-            if (quest->complete.find(val) != quest->complete.end())
+            if (quest->complete.find(val.var1) != quest->complete.end())
+            {
                 complete.push_back(quest);
+            }
             // incomplete quest
-            else if (quest->incomplete.find(val) != quest->incomplete.end())
+            else if (quest->incomplete.find(val.var1) != quest->incomplete.end())
+            {
                 incomplete.push_back(quest);
+            }
             // hidden quest
             else
+            {
                 hidden.push_back(quest);
+            }
         }
     }
 
@@ -465,39 +472,49 @@ void QuestsWindow::showQuest(const QuestItem *const quest)
         return;
 
     const std::vector<QuestItemText> &texts = quest->texts;
+    const QuestVar &var = mVars[quest->var];
+    const std::string var1 = toString(var.var1);
+    const std::string var2 = toString(var.var2);
+    const std::string var3 = toString(var.var3);
+    const std::string timeStr = timeDiffToString(var.time1).c_str();
     mText->clearRows();
     FOR_EACH (std::vector<QuestItemText>::const_iterator, it, texts)
     {
         const QuestItemText &data = *it;
+        std::string text = data.text;
+        replaceAll(text, "{@@var1}", var1);
+        replaceAll(text, "{@@var2}", var2);
+        replaceAll(text, "{@@var3}", var3);
+        replaceAll(text, "{@@time}", timeStr);
         switch (data.type)
         {
             case QuestType::TEXT:
             default:
-                mText->addRow(data.text);
+                mText->addRow(text);
                 break;
             case QuestType::NAME:
-                mText->addRow(std::string("[").append(data.text).append("]"));
+                mText->addRow(std::string("[").append(text).append("]"));
                 break;
             case QuestType::REWARD:
                 mText->addRow(std::string(
                     // TRANSLATORS: quest reward
                     _("Reward:")).append(
                     " ").append(
-                    data.text));
+                    text));
                 break;
             case QuestType::GIVER:
                 mText->addRow(std::string(
                     // TRANSLATORS: quest giver name
                     _("Quest Giver:")).append(
                     " ").append(
-                    data.text));
+                    text));
                 break;
             case QuestType::NPC:
                 mText->addRow(std::string(
                     // TRANSLATORS: quest npc name
                     _("Npc:")).append(
                     " ").append(
-                    data.text));
+                    text));
                 break;
             case QuestType::COORDINATES:
                 mText->addRow(std::string(
@@ -506,7 +523,7 @@ void QuestsWindow::showQuest(const QuestItem *const quest)
                     _("Coordinates:"),
                     data.data1.c_str(),
                     data.data2.c_str(),
-                    data.text.c_str())));
+                    text.c_str())));
                 break;
         }
     }
@@ -543,11 +560,11 @@ void QuestsWindow::updateEffects()
         const QuestEffect *const effect = *it;
         if (effect)
         {
-            const IntMapCIter varIt = mVars.find(effect->var);
+            const NpcQuestVarMapCIter varIt = mVars.find(effect->var);
             if (varIt != mVars.end())
             {
                 const std::set<int> &vals = effect->values;
-                if (vals.find(mVars[effect->var]) != vals.end())
+                if (vals.find(mVars[effect->var].var1) != vals.end())
                     mNpcEffects[effect->id] = effect;
             }
         }
diff --git a/src/gui/windows/questswindow.h b/src/gui/windows/questswindow.h
index 08ef852d9..78e5b609c 100644
--- a/src/gui/windows/questswindow.h
+++ b/src/gui/windows/questswindow.h
@@ -27,10 +27,12 @@
 
 #include "gui/widgets/window.h"
 
+#include "listeners/actionlistener.h"
+
 #include "utils/intmap.h"
 #include "utils/xml.h"
 
-#include "listeners/actionlistener.h"
+#include "resources/questvar.h"
 
 class Being;
 class Button;
@@ -46,6 +48,8 @@ struct QuestItem;
 
 typedef std::map<BeingTypeId, const QuestEffect*> NpcQuestEffectMap;
 typedef NpcQuestEffectMap::const_iterator NpcQuestEffectMapCIter;
+typedef std::map<int, QuestVar> NpcQuestVarMap;
+typedef NpcQuestVarMap::const_iterator NpcQuestVarMapCIter;
 
 class QuestsWindow final : public Window,
                            public ActionListener
@@ -63,7 +67,7 @@ class QuestsWindow final : public Window,
                          const int val1,
                          const int val2,
                          const int val3,
-                         const int time);
+                         const int time1);
 
         void rebuild(const bool playSound);
 
@@ -92,8 +96,8 @@ class QuestsWindow final : public Window,
         Button *mCloseButton A_NONNULLPOINTER;
         Image *mCompleteIcon;
         Image *mIncompleteIcon;
-        // quest variables: var, value
-        IntMap mVars;
+        // quest variables: var, (val1, val2, val3, time)
+        NpcQuestVarMap mVars;
         // quests: var, quests
         std::map<int, std::vector<QuestItem*> > mQuests;
         std::vector<QuestEffect*> mAllEffects;
diff --git a/src/gui/windows/skilldialog.cpp b/src/gui/windows/skilldialog.cpp
index 6aa4c8afb..7e474a982 100644
--- a/src/gui/windows/skilldialog.cpp
+++ b/src/gui/windows/skilldialog.cpp
@@ -686,7 +686,7 @@ void SkillDialog::updateQuest(const int var,
                               const int val1,
                               const int val2 A_UNUSED,
                               const int val3 A_UNUSED,
-                              const int time A_UNUSED)
+                              const int time1 A_UNUSED)
 {
     const int id = var + SKILL_VAR_MIN_ID;
     const SkillMap::const_iterator it = mSkills.find(id);
diff --git a/src/gui/windows/skilldialog.h b/src/gui/windows/skilldialog.h
index 3bd5f1d4a..5a4a89afe 100644
--- a/src/gui/windows/skilldialog.h
+++ b/src/gui/windows/skilldialog.h
@@ -128,7 +128,7 @@ class SkillDialog final : public Window,
                          const int val1,
                          const int val2,
                          const int val3,
-                         const int time);
+                         const int time1);
 
         void playUpdateEffect(const int id) const;
 
diff --git a/src/net/eathena/questrecv.cpp b/src/net/eathena/questrecv.cpp
index 88f804330..1a2ae5311 100644
--- a/src/net/eathena/questrecv.cpp
+++ b/src/net/eathena/questrecv.cpp
@@ -66,7 +66,6 @@ void QuestRecv::processAddQuest2(Net::MessageIn &msg)
     const int var = msg.readInt32("quest id");
     msg.readUInt8("state");
     const int val1 = msg.readInt32("count1");
-    // +++ need use all this fields
     const int val2 = msg.readInt32("count2");
     const int val3 = msg.readInt32("count3");
     const int time = msg.readInt32("time");
@@ -116,7 +115,6 @@ void QuestRecv::processAddQuests2(Net::MessageIn &msg)
         const int var = msg.readInt32("quest id");
         msg.readUInt8("state");
         const int val1 = msg.readInt32("count1");
-        // +++ need use all this fields
         const int val2 = msg.readInt32("count2");
         const int val3 = msg.readInt32("count3");
         const int time = msg.readInt32("time");
diff --git a/src/resources/questvar.h b/src/resources/questvar.h
new file mode 100644
index 000000000..73897e09b
--- /dev/null
+++ b/src/resources/questvar.h
@@ -0,0 +1,53 @@
+/*
+ *  The ManaPlus Client
+ *  Copyright (C) 2016  The ManaPlus Developers
+ *
+ *  This file is part of The ManaPlus Client.
+ *
+ *  This program 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.
+ *
+ *  This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef RESOURCES_QUESTVAR_H
+#define RESOURCES_QUESTVAR_H
+
+#include "localconsts.h"
+
+struct QuestVar final
+{
+    QuestVar() :
+        var1(0),
+        var2(0),
+        var3(0),
+        time1(0)
+    {
+    }
+
+    QuestVar(const int v1,
+             const int v2,
+             const int v3,
+             const int t) :
+        var1(v1),
+        var2(v2),
+        var3(v3),
+        time1(t)
+    {
+    }
+
+    int var1;
+    int var2;
+    int var3;
+    int time1;
+};
+
+#endif  // RESOURCES_QUESTVAR_H
-- 
cgit v1.2.3-70-g09d2