/* * The ManaPlus Client * Copyright (C) 2011-2020 The ManaPlus Developers * Copyright (C) 2020-2023 The ManaVerse 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 . */ #include "resources/db/npcdialogdb.h" #include "configuration.h" #include "resources/beingcommon.h" #include "resources/npcdialoginfo.h" #include "utils/checkutils.h" #include "utils/dtor.h" #include "debug.h" namespace { bool mLoaded = false; NpcDialogDB::Dialogs mDialogs; } // namespace void NpcDialogDB::load() { if (mLoaded) unload(); logger->log1("Loading npc dialog database..."); loadXmlFile(paths.getStringValue("npcDialogsFile"), SkipError_false); loadXmlFile(paths.getStringValue("npcDialogsPatchFile"), SkipError_true); loadXmlDir("npcDialogsPatchDir", loadXmlFile) mLoaded = true; } static void loadNpcDialogMenu(NpcDialogInfo *const dialog, XmlNodeConstPtrConst node) { for_each_xml_child_node(childNode, node) { if (!xmlTypeEqual(childNode, XML_ELEMENT_NODE)) continue; if (xmlNameEqual(childNode, "button")) { const std::string name = XML::getProperty(childNode, "name", ""); const std::string value = XML::getProperty(childNode, "value", ""); if (value.empty()) continue; NpcButtonInfo *const button = new NpcButtonInfo; button->x = XML::getIntProperty( childNode, "x", 0, 0, 10000); button->y = XML::getIntProperty( childNode, "y", 0, 0, 10000); button->name = name; button->value = value; button->image = XML::getProperty(childNode, "image", ""); if (button->name.empty() && button->image.empty()) { reportAlways("Error: npc button without name or image") delete button; continue; } button->imageWidth = XML::getIntProperty( childNode, "imageWidth", 16, 1, 1000); button->imageHeight = XML::getIntProperty( childNode, "imageHeight", 16, 1, 1000); dialog->menu.buttons.push_back(button); } else if (xmlNameEqual(childNode, "image")) { const std::string image = XML::getProperty(childNode, "image", ""); if (image.empty()) { reportAlways("Error: no image attribute found in image tag.") continue; } NpcImageInfo *const imageInfo = new NpcImageInfo; imageInfo->name = image; imageInfo->x = XML::getIntProperty( childNode, "x", 0, 0, 10000); imageInfo->y = XML::getIntProperty( childNode, "y", 0, 0, 10000); dialog->menu.images.push_back(imageInfo); } else if (xmlNameEqual(childNode, "text")) { const std::string text = XML::getProperty(childNode, "text", ""); if (text.empty()) { reportAlways("Error: no text attribute found in text tag.") continue; } NpcTextInfo *const textInfo = new NpcTextInfo; textInfo->text = text; textInfo->x = XML::getIntProperty( childNode, "x", 0, 0, 10000); textInfo->y = XML::getIntProperty( childNode, "y", 0, 0, 10000); textInfo->width = XML::getIntProperty( childNode, "width", 20, 10, 10000); textInfo->height = XML::getIntProperty( childNode, "height", 20, 10, 10000); dialog->menu.texts.push_back(textInfo); } } } static void loadNpcDialogInventory(NpcDialogInfo *const dialog, XmlNodePtrConst node) { dialog->inventory.cell = XML::getProperty(node, "cell", ""); dialog->inventory.columns = XML::getIntProperty( node, "columns", 10000, 1, 10000); } static void loadNpcDialog(NpcDialogInfo *const dialog, XmlNodeConstPtrConst node) { for_each_xml_child_node(childNode, node) { if (xmlNameEqual(childNode, "menu")) { loadNpcDialogMenu(dialog, childNode); } else if (xmlNameEqual(childNode, "inventory")) { loadNpcDialogInventory(dialog, childNode); } } } void NpcDialogDB::loadXmlFile(const std::string &fileName, const SkipError skipError) { XML::Document *const doc = new XML::Document(fileName, UseVirtFs_true, skipError); XmlNodeConstPtrConst root = doc->rootNode(); if (root == nullptr) { delete doc; return; } for_each_xml_child_node(node, root) { if (xmlNameEqual(node, "dialog")) { const std::string name = XML::getProperty(node, "name", ""); if (name.empty()) continue; deleteDialog(name); NpcDialogInfo *const dialog = new NpcDialogInfo; dialog->name = name; dialog->hideText = XML::getBoolProperty( node, "hideText", false); mDialogs[name] = dialog; loadNpcDialog(dialog, node); } else if (xmlNameEqual(node, "include")) { const std::string name = XML::getProperty(node, "name", ""); if (!name.empty()) loadXmlFile(name, skipError); continue; } } delete doc; } void NpcDialogDB::deleteDialog(const std::string &name) { const DialogsIter it = mDialogs.find(name); if (it == mDialogs.end()) return; NpcDialogInfo *dialog = (*it).second; delete_all(dialog->menu.buttons); delete_all(dialog->menu.images); delete_all(dialog->menu.texts); mDialogs.erase(it); delete dialog; } void NpcDialogDB::unload() { logger->log1("Unloading npc dialog database..."); FOR_EACH (DialogsIter, it, mDialogs) { NpcDialogInfo *dialog = (*it).second; delete_all(dialog->menu.buttons); delete_all(dialog->menu.images); delete_all(dialog->menu.texts); delete dialog; } mDialogs.clear(); mLoaded = false; } NpcDialogInfo *NpcDialogDB::getDialog(const std::string &name) { const DialogsIter it = mDialogs.find(name); if (it == mDialogs.end()) return nullptr; return (*it).second; }