diff options
-rw-r--r-- | src/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/gui/windows/questswindow.cpp | 206 | ||||
-rw-r--r-- | src/gui/windows/questswindow.h | 18 | ||||
-rw-r--r-- | src/resources/db/questdb.cpp | 243 | ||||
-rw-r--r-- | src/resources/db/questdb.h | 53 | ||||
-rw-r--r-- | src/resources/questvar.h | 5 |
7 files changed, 328 insertions, 201 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 750e38e8e..89d6f2595 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -751,6 +751,8 @@ SET(SRCS resources/db/palettedb.h resources/db/petdb.cpp resources/db/petdb.h + resources/db/questdb.cpp + resources/db/questdb.h resources/db/skillunitdb.cpp resources/db/skillunitdb.h resources/resource.cpp diff --git a/src/Makefile.am b/src/Makefile.am index 51c49cb99..92b08af58 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1316,6 +1316,8 @@ SRC = ${BASE_SRC} \ resources/db/palettedb.h \ resources/db/petdb.cpp \ resources/db/petdb.h \ + resources/db/questdb.cpp \ + resources/db/questdb.h \ resources/db/skillunitdb.cpp \ resources/db/skillunitdb.h \ resources/db/sounddb.cpp \ diff --git a/src/gui/windows/questswindow.cpp b/src/gui/windows/questswindow.cpp index e0bb3305d..ab204d1f8 100644 --- a/src/gui/windows/questswindow.cpp +++ b/src/gui/windows/questswindow.cpp @@ -46,15 +46,14 @@ #include "gui/widgets/scrollarea.h" #include "utils/delete2.h" -#include "utils/dtor.h" #include "utils/gettext.h" -#include "utils/translation/podict.h" - #include "resources/beingcommon.h" #include "resources/questeffect.h" #include "resources/questitem.h" +#include "resources/db/questdb.h" + #include "resources/map/map.h" #include "debug.h" @@ -81,10 +80,10 @@ QuestsWindow::QuestsWindow() : mCloseButton(new Button(this, _("Close"), "close", this)), mCompleteIcon(Theme::getImageFromThemeXml("complete_icon.xml", "")), mIncompleteIcon(Theme::getImageFromThemeXml("incomplete_icon.xml", "")), - mVars(), - mQuests(), - mAllEffects(), mMapEffects(), + mVars(nullptr), + mQuests(nullptr), + mAllEffects(nullptr), mNpcEffects(), mQuestLinks(), mNewQuestEffectId(paths.getIntValue("newQuestEffectId")), @@ -129,30 +128,19 @@ QuestsWindow::QuestsWindow() : loadWindowState(); enableVisibleSound(true); - loadXmlFile(paths.getStringValue("questsFile"), SkipError_false); - loadXmlFile(paths.getStringValue("questsPatchFile"), SkipError_true); - loadXmlDir("questsPatchDir", loadXmlFile); + QuestDb::load(); + mVars = QuestDb::getVars(); + mQuests = QuestDb::getQuests(); + mAllEffects = QuestDb::getAllEffects(); } QuestsWindow::~QuestsWindow() { delete2(mQuestsModel); - for (std::map<int, std::vector<QuestItem*> >::iterator it - = mQuests.begin(), it_end = mQuests.end(); it != it_end; ++ it) - { - std::vector<QuestItem*> &quests = (*it).second; - for (std::vector<QuestItem*>::iterator it2 = quests.begin(), - it2_end = quests.end(); it2 != it2_end; ++ it2) - { - delete *it2; - } - } - delete_all(mAllEffects); - mAllEffects.clear(); + QuestDb::unload(); delete2(mItemLinkHandler); - mQuests.clear(); mQuestLinks.clear(); if (mCompleteIcon) { @@ -166,162 +154,6 @@ QuestsWindow::~QuestsWindow() } } -void QuestsWindow::loadXmlFile(const std::string &fileName, - const SkipError skipError) -{ - XML::Document doc(fileName, - UseResman_true, - skipError); - const XmlNodePtrConst root = doc.rootNode(); - if (!root) - return; - - for_each_xml_child_node(varNode, root) - { - if (xmlNameEqual(varNode, "include")) - { - const std::string name = XML::getProperty(varNode, "name", ""); - if (!name.empty()) - loadXmlFile(name, skipError); - continue; - } - else if (xmlNameEqual(varNode, "var")) - { - const int id = XML::getProperty(varNode, "id", 0); - if (id < 0) - continue; - mVars[id] = QuestVar(); - for_each_xml_child_node(questNode, varNode) - { - if (xmlNameEqual(questNode, "quest")) - loadQuest(id, questNode); - else if (xmlNameEqual(questNode, "effect")) - loadEffect(id, questNode); - } - } - } -} - -void QuestsWindow::loadQuest(const int var, const XmlNodePtr node) -{ - if (!node) - return; - QuestItem *const quest = new QuestItem(); - // TRANSLATORS: quests window quest name - quest->name = XML::langProperty(node, "name", _("unknown")); - quest->group = XML::getProperty(node, "group", ""); - std::string incompleteStr = XML::getProperty(node, "incomplete", ""); - std::string completeStr = XML::getProperty(node, "complete", ""); - if (incompleteStr.empty() && completeStr.empty()) - { - logger->log("complete flags incorrect"); - delete quest; - return; - } - splitToIntSet(quest->incomplete, incompleteStr, ','); - splitToIntSet(quest->complete, completeStr, ','); - if (quest->incomplete.empty() && quest->complete.empty()) - { - logger->log("complete flags incorrect"); - delete quest; - return; - } - if (quest->incomplete.empty() || quest->complete.empty()) - quest->broken = true; - - for_each_xml_child_node(dataNode, node) - { - if (!xmlTypeEqual(dataNode, XML_ELEMENT_NODE)) - continue; - const char *const data = reinterpret_cast<const char*>( - XmlNodeGetContent(dataNode)); - if (!data) - continue; - std::string str = translator->getStr(data); - - for (int f = 1; f < 100; f ++) - { - const std::string key = strprintf("text%d", f); - const std::string val = XML::getProperty(dataNode, - key.c_str(), - ""); - if (val.empty()) - break; - const std::string param = strprintf("{@@%d}", f); - replaceAll(str, param, val); - } - replaceItemLinks(str); - if (xmlNameEqual(dataNode, "text")) - { - quest->texts.push_back(QuestItemText(str, - QuestType::TEXT, - std::string(), - std::string())); - } - else if (xmlNameEqual(dataNode, "name")) - { - quest->texts.push_back(QuestItemText(str, - QuestType::NAME, - std::string(), - std::string())); - } - else if (xmlNameEqual(dataNode, "reward")) - { - quest->texts.push_back(QuestItemText(str, - QuestType::REWARD, - std::string(), - std::string())); - } - else if (xmlNameEqual(dataNode, "questgiver") || - xmlNameEqual(dataNode, "giver")) - { - quest->texts.push_back(QuestItemText(str, - QuestType::GIVER, - std::string(), - std::string())); - } - else if (xmlNameEqual(dataNode, "coordinates")) - { - const std::string str1 = toString(XML::getIntProperty( - dataNode, "x", 0, 1, 1000)); - const std::string str2 = toString(XML::getIntProperty( - dataNode, "y", 0, 1, 1000)); - quest->texts.push_back(QuestItemText(str, - QuestType::COORDINATES, - str1, - str2)); - } - else if (xmlNameEqual(dataNode, "npc")) - { - quest->texts.push_back(QuestItemText(str, - QuestType::NPC, - std::string(), - std::string())); - } - } - quest->var = var; - mQuests[var].push_back(quest); -} - -void QuestsWindow::loadEffect(const int var, const XmlNodePtr node) -{ - QuestEffect *const effect = new QuestEffect; - effect->map = XML::getProperty(node, "map", ""); - effect->id = fromInt(XML::getProperty(node, "npc", -1), BeingTypeId); - effect->effectId = XML::getProperty(node, "effect", -1); - const std::string values = XML::getProperty(node, "value", ""); - splitToIntSet(effect->values, values, ','); - - if (effect->map.empty() || effect->id == BeingTypeId_negOne - || effect->effectId == -1 || values.empty()) - { - delete effect; - return; - } - effect->var = var; - mAllEffects.push_back(effect); -} - void QuestsWindow::action(const ActionEvent &event) { const std::string &eventId = event.getId(); @@ -344,7 +176,7 @@ void QuestsWindow::updateQuest(const int var, const int val3, const int time1) { - mVars[var] = QuestVar(val1, val2, val3, time1); + (*mVars)[var] = QuestVar(val1, val2, val3, time1); } void QuestsWindow::rebuild(const bool playSound) @@ -359,11 +191,11 @@ void QuestsWindow::rebuild(const bool playSound) int updatedQuest = -1; int newCompleteStatus = -1; - FOR_EACH (NpcQuestVarMapCIter, it, mVars) + FOR_EACHP (NpcQuestVarMapCIter, it, mVars) { const int var = (*it).first; const QuestVar &val = (*it).second; - const std::vector<QuestItem*> &quests = mQuests[var]; + const std::vector<QuestItem*> &quests = (*mQuests)[var]; FOR_EACH (std::vector<QuestItem*>::const_iterator, it2, quests) { if (!*it2) @@ -470,11 +302,11 @@ void QuestsWindow::rebuild(const bool playSound) void QuestsWindow::showQuest(const QuestItem *const quest) { - if (!quest || !translator) + if (!quest) return; const std::vector<QuestItemText> &texts = quest->texts; - const QuestVar &var = mVars[quest->var]; + 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); @@ -541,7 +373,7 @@ void QuestsWindow::setMap(const Map *const map) return; const std::string name = mMap->getProperty("shortName"); - FOR_EACH (std::vector<QuestEffect*>::const_iterator, it, mAllEffects) + FOR_EACHP (std::vector<QuestEffect*>::const_iterator, it, mAllEffects) { const QuestEffect *const effect = *it; if (effect && name == effect->map) @@ -562,11 +394,11 @@ void QuestsWindow::updateEffects() const QuestEffect *const effect = *it; if (effect) { - const NpcQuestVarMapCIter varIt = mVars.find(effect->var); - if (varIt != mVars.end()) + const NpcQuestVarMapCIter varIt = mVars->find(effect->var); + if (varIt != mVars->end()) { const std::set<int> &vals = effect->values; - if (vals.find(mVars[effect->var].var1) != 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 082ab011e..dd3464fae 100644 --- a/src/gui/windows/questswindow.h +++ b/src/gui/windows/questswindow.h @@ -47,8 +47,6 @@ 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 @@ -79,13 +77,6 @@ class QuestsWindow final : public Window, void addEffect(Being *const being); private: - void loadXmlFile(const std::string &fileName, - const SkipError skipError); - - void loadQuest(const int var, const XmlNodePtr node); - - void loadEffect(const int var, const XmlNodePtr node); - QuestsModel *mQuestsModel A_NONNULLPOINTER; ExtendedListBox *mQuestsListBox A_NONNULLPOINTER; ScrollArea *mQuestScrollArea A_NONNULLPOINTER; @@ -95,12 +86,11 @@ class QuestsWindow final : public Window, Button *mCloseButton A_NONNULLPOINTER; Image *mCompleteIcon; Image *mIncompleteIcon; - // quest variables: var, (val1, val2, val3, time) - NpcQuestVarMap mVars; - // quests: var, quests - std::map<int, std::vector<QuestItem*> > mQuests; - std::vector<QuestEffect*> mAllEffects; std::vector<const QuestEffect*> mMapEffects; + NpcQuestVarMap *mVars; + std::map<int, std::vector<QuestItem*> > *mQuests; + std::vector<QuestEffect*> *mAllEffects; + // npc effects for current map and values: npc, effect NpcQuestEffectMap mNpcEffects; std::vector<QuestItem*> mQuestLinks; diff --git a/src/resources/db/questdb.cpp b/src/resources/db/questdb.cpp new file mode 100644 index 000000000..9df240f92 --- /dev/null +++ b/src/resources/db/questdb.cpp @@ -0,0 +1,243 @@ +/* + * The ManaPlus Client + * Copyright (C) 2013-2017 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/>. + */ + +#include "resources/db/questdb.h" + +#include "configuration.h" +#include "logger.h" + +#include "utils/dtor.h" +#include "utils/gettext.h" + +#include "utils/translation/podict.h" + +#include "resources/beingcommon.h" +#include "resources/questeffect.h" +#include "resources/questitem.h" + +#include "debug.h" + +namespace +{ + // quest variables: var, (val1, val2, val3, time) + NpcQuestVarMap mVars; + // quests: var, quests + std::map<int, std::vector<QuestItem*> > mQuests; + std::vector<QuestEffect*> mAllEffects; +} + +void QuestDb::load() +{ + unload(); + loadXmlFile(paths.getStringValue("questsFile"), SkipError_false); + loadXmlFile(paths.getStringValue("questsPatchFile"), SkipError_true); + loadXmlDir("questsPatchDir", loadXmlFile); +} + +static void loadQuest(const int var, + const XmlNodePtr node) +{ + if (!node) + return; + QuestItem *const quest = new QuestItem(); + // TRANSLATORS: quests window quest name + quest->name = XML::langProperty(node, "name", _("unknown")); + quest->group = XML::getProperty(node, "group", ""); + std::string incompleteStr = XML::getProperty(node, "incomplete", ""); + std::string completeStr = XML::getProperty(node, "complete", ""); + if (incompleteStr.empty() && completeStr.empty()) + { + logger->log("complete flags incorrect"); + delete quest; + return; + } + splitToIntSet(quest->incomplete, incompleteStr, ','); + splitToIntSet(quest->complete, completeStr, ','); + if (quest->incomplete.empty() && quest->complete.empty()) + { + logger->log("complete flags incorrect"); + delete quest; + return; + } + if (quest->incomplete.empty() || quest->complete.empty()) + quest->broken = true; + + for_each_xml_child_node(dataNode, node) + { + if (!xmlTypeEqual(dataNode, XML_ELEMENT_NODE)) + continue; + const char *const data = reinterpret_cast<const char*>( + XmlNodeGetContent(dataNode)); + if (!data) + continue; + std::string str = translator->getStr(data); + + for (int f = 1; f < 100; f ++) + { + const std::string key = strprintf("text%d", f); + const std::string val = XML::getProperty(dataNode, + key.c_str(), + ""); + if (val.empty()) + break; + const std::string param = strprintf("{@@%d}", f); + replaceAll(str, param, val); + } + replaceItemLinks(str); + if (xmlNameEqual(dataNode, "text")) + { + quest->texts.push_back(QuestItemText(str, + QuestType::TEXT, + std::string(), + std::string())); + } + else if (xmlNameEqual(dataNode, "name")) + { + quest->texts.push_back(QuestItemText(str, + QuestType::NAME, + std::string(), + std::string())); + } + else if (xmlNameEqual(dataNode, "reward")) + { + quest->texts.push_back(QuestItemText(str, + QuestType::REWARD, + std::string(), + std::string())); + } + else if (xmlNameEqual(dataNode, "questgiver") || + xmlNameEqual(dataNode, "giver")) + { + quest->texts.push_back(QuestItemText(str, + QuestType::GIVER, + std::string(), + std::string())); + } + else if (xmlNameEqual(dataNode, "coordinates")) + { + const std::string str1 = toString(XML::getIntProperty( + dataNode, "x", 0, 1, 1000)); + const std::string str2 = toString(XML::getIntProperty( + dataNode, "y", 0, 1, 1000)); + quest->texts.push_back(QuestItemText(str, + QuestType::COORDINATES, + str1, + str2)); + } + else if (xmlNameEqual(dataNode, "npc")) + { + quest->texts.push_back(QuestItemText(str, + QuestType::NPC, + std::string(), + std::string())); + } + } + quest->var = var; + mQuests[var].push_back(quest); +} + +static void loadEffect(const int var, + const XmlNodePtr node) +{ + QuestEffect *const effect = new QuestEffect; + effect->map = XML::getProperty(node, "map", ""); + effect->id = fromInt(XML::getProperty(node, "npc", -1), BeingTypeId); + effect->effectId = XML::getProperty(node, "effect", -1); + const std::string values = XML::getProperty(node, "value", ""); + splitToIntSet(effect->values, values, ','); + + if (effect->map.empty() || effect->id == BeingTypeId_negOne + || effect->effectId == -1 || values.empty()) + { + delete effect; + return; + } + effect->var = var; + mAllEffects.push_back(effect); +} + +void QuestDb::loadXmlFile(const std::string &fileName, + const SkipError skipError) +{ + XML::Document doc(fileName, + UseResman_true, + skipError); + const XmlNodePtrConst root = doc.rootNode(); + if (!root) + return; + + for_each_xml_child_node(varNode, root) + { + if (xmlNameEqual(varNode, "include")) + { + const std::string name = XML::getProperty(varNode, "name", ""); + if (!name.empty()) + loadXmlFile(name, skipError); + continue; + } + else if (xmlNameEqual(varNode, "var")) + { + const int id = XML::getProperty(varNode, "id", 0); + if (id < 0) + continue; + mVars[id] = QuestVar(); + for_each_xml_child_node(questNode, varNode) + { + if (xmlNameEqual(questNode, "quest")) + loadQuest(id, questNode); + else if (xmlNameEqual(questNode, "effect")) + loadEffect(id, questNode); + } + } + } +} + + +void QuestDb::unload() +{ + for (std::map<int, std::vector<QuestItem*> >::iterator it + = mQuests.begin(), it_end = mQuests.end(); it != it_end; ++ it) + { + std::vector<QuestItem*> &quests = (*it).second; + for (std::vector<QuestItem*>::iterator it2 = quests.begin(), + it2_end = quests.end(); it2 != it2_end; ++ it2) + { + delete *it2; + } + } + delete_all(mAllEffects); + mAllEffects.clear(); + mQuests.clear(); +} + +NpcQuestVarMap *QuestDb::getVars() +{ + return &mVars; +} + +std::map<int, std::vector<QuestItem*> > *QuestDb::getQuests() +{ + return &mQuests; +} + +std::vector<QuestEffect*> *QuestDb::getAllEffects() +{ + return &mAllEffects; +} diff --git a/src/resources/db/questdb.h b/src/resources/db/questdb.h new file mode 100644 index 000000000..3b9fa2ef1 --- /dev/null +++ b/src/resources/db/questdb.h @@ -0,0 +1,53 @@ +/* + * The ManaPlus Client + * Copyright (C) 2013-2017 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_DB_QUESTDB_H +#define RESOURCES_DB_QUESTDB_H + +#include "enums/simpletypes/skiperror.h" + +#include "resources/questvar.h" + +#include <map> +#include <string> +#include <vector> + +#include "localconsts.h" + +struct QuestEffect; +struct QuestItem; + +namespace QuestDb +{ + void load(); + + void loadXmlFile(const std::string &fileName, + const SkipError skipError); + + void unload(); + + NpcQuestVarMap *getVars(); + + std::map<int, std::vector<QuestItem*> > *getQuests(); + + std::vector<QuestEffect*> *getAllEffects(); +} // namespace QuestDb + +#endif // RESOURCES_DB_QUESTDB_H diff --git a/src/resources/questvar.h b/src/resources/questvar.h index 3895d2783..1164d0f58 100644 --- a/src/resources/questvar.h +++ b/src/resources/questvar.h @@ -21,6 +21,8 @@ #ifndef RESOURCES_QUESTVAR_H #define RESOURCES_QUESTVAR_H +#include <map> + #include "localconsts.h" struct QuestVar final @@ -52,4 +54,7 @@ struct QuestVar final int time1; }; +typedef std::map<int, QuestVar> NpcQuestVarMap; +typedef NpcQuestVarMap::const_iterator NpcQuestVarMapCIter; + #endif // RESOURCES_QUESTVAR_H |