GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/resources/db/npcdialogdb.cpp Lines: 8 103 7.8 %
Date: 2017-11-29 Branches: 1 164 0.6 %

Line Branch Exec Source
1
/*
2
 *  The ManaPlus Client
3
 *  Copyright (C) 2011-2017  The ManaPlus Developers
4
 *
5
 *  This file is part of The ManaPlus Client.
6
 *
7
 *  This program is free software; you can redistribute it and/or modify
8
 *  it under the terms of the GNU General Public License as published by
9
 *  the Free Software Foundation; either version 2 of the License, or
10
 *  any later version.
11
 *
12
 *  This program is distributed in the hope that it will be useful,
13
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 *  GNU General Public License for more details.
16
 *
17
 *  You should have received a copy of the GNU General Public License
18
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
 */
20
21
#include "resources/db/npcdialogdb.h"
22
23
#include "configuration.h"
24
25
#include "resources/beingcommon.h"
26
#include "resources/npcdialoginfo.h"
27
28
#include "utils/checkutils.h"
29
#include "utils/dtor.h"
30
31
#include "debug.h"
32
33
namespace
34
{
35
    bool mLoaded = false;
36
2
    NpcDialogDB::Dialogs mDialogs;
37
}  // namespace
38
39
void NpcDialogDB::load()
40
{
41
    if (mLoaded)
42
        unload();
43
44
    logger->log1("Loading npc dialog database...");
45
    loadXmlFile(paths.getStringValue("npcDialogsFile"), SkipError_false);
46
    loadXmlFile(paths.getStringValue("npcDialogsPatchFile"), SkipError_true);
47
    loadXmlDir("npcDialogsPatchDir", loadXmlFile);
48
49
    mLoaded = true;
50
}
51
52
static void loadNpcDialogMenu(NpcDialogInfo *const dialog,
53
                              XmlNodeConstPtrConst node)
54
{
55
    for_each_xml_child_node(childNode, node)
56
    {
57
        if (!xmlTypeEqual(childNode, XML_ELEMENT_NODE))
58
            continue;
59
60
        if (xmlNameEqual(childNode, "button"))
61
        {
62
            const std::string name = XML::getProperty(childNode, "name", "");
63
            const std::string value = XML::getProperty(childNode, "value", "");
64
            if (value.empty())
65
                continue;
66
67
            NpcButtonInfo *const button = new NpcButtonInfo;
68
            button->x = XML::getIntProperty(
69
                childNode, "x", 0, 0, 10000);
70
            button->y = XML::getIntProperty(
71
                childNode, "y", 0, 0, 10000);
72
            button->name = name;
73
            button->value = value;
74
            button->image = XML::getProperty(childNode, "image", "");
75
            if (button->name.empty() && button->image.empty())
76
            {
77
                reportAlways("Error: npc button without name or image");
78
                delete button;
79
                continue;
80
            }
81
            button->imageWidth = XML::getIntProperty(
82
                childNode, "imageWidth", 16, 1, 1000);
83
            button->imageHeight = XML::getIntProperty(
84
                childNode, "imageHeight", 16, 1, 1000);
85
            dialog->menu.buttons.push_back(button);
86
        }
87
        else if (xmlNameEqual(childNode, "image"))
88
        {
89
            const std::string image = XML::getProperty(childNode, "image", "");
90
            if (image.empty())
91
            {
92
                reportAlways("Error: no image attribute found in image tag.");
93
                continue;
94
            }
95
            NpcImageInfo *const imageInfo = new NpcImageInfo;
96
            imageInfo->name = image;
97
            imageInfo->x = XML::getIntProperty(
98
                childNode, "x", 0, 0, 10000);
99
            imageInfo->y = XML::getIntProperty(
100
                childNode, "y", 0, 0, 10000);
101
            dialog->menu.images.push_back(imageInfo);
102
        }
103
        else if (xmlNameEqual(childNode, "text"))
104
        {
105
            const std::string text = XML::getProperty(childNode, "text", "");
106
            if (text.empty())
107
            {
108
                reportAlways("Error: no text attribute found in text tag.");
109
                continue;
110
            }
111
            NpcTextInfo *const textInfo = new NpcTextInfo;
112
            textInfo->text = text;
113
            textInfo->x = XML::getIntProperty(
114
                childNode, "x", 0, 0, 10000);
115
            textInfo->y = XML::getIntProperty(
116
                childNode, "y", 0, 0, 10000);
117
            textInfo->width = XML::getIntProperty(
118
                childNode, "width", 20, 10, 10000);
119
            textInfo->height = XML::getIntProperty(
120
                childNode, "height", 20, 10, 10000);
121
            dialog->menu.texts.push_back(textInfo);
122
        }
123
    }
124
}
125
126
static void loadNpcDialogInventory(NpcDialogInfo *const dialog,
127
                                   XmlNodePtrConst node)
128
{
129
    dialog->inventory.cell = XML::getProperty(node, "cell", "");
130
    dialog->inventory.columns = XML::getIntProperty(
131
        node, "columns", 10000, 1, 10000);
132
}
133
134
static void loadNpcDialog(NpcDialogInfo *const dialog,
135
                          XmlNodeConstPtrConst node)
136
{
137
    for_each_xml_child_node(childNode, node)
138
    {
139
        if (xmlNameEqual(childNode, "menu"))
140
        {
141
            loadNpcDialogMenu(dialog, childNode);
142
        }
143
        else if (xmlNameEqual(childNode, "inventory"))
144
        {
145
            loadNpcDialogInventory(dialog, childNode);
146
        }
147
    }
148
}
149
150
void NpcDialogDB::loadXmlFile(const std::string &fileName,
151
                              const SkipError skipError)
152
{
153
    XML::Document *const doc = new XML::Document(fileName,
154
        UseVirtFs_true,
155
        skipError);
156
157
    XmlNodeConstPtrConst root = doc->rootNode();
158
    if (root == nullptr)
159
    {
160
        delete doc;
161
        return;
162
    }
163
164
    for_each_xml_child_node(node, root)
165
    {
166
        if (xmlNameEqual(node, "dialog"))
167
        {
168
            const std::string name = XML::getProperty(node, "name", "");
169
            if (name.empty())
170
                continue;
171
172
            deleteDialog(name);
173
            NpcDialogInfo *const dialog = new NpcDialogInfo;
174
            dialog->name = name;
175
            dialog->hideText = XML::getBoolProperty(
176
                node, "hideText", false);
177
            mDialogs[name] = dialog;
178
            loadNpcDialog(dialog, node);
179
        }
180
        else if (xmlNameEqual(node, "include"))
181
        {
182
            const std::string name = XML::getProperty(node, "name", "");
183
            if (!name.empty())
184
                loadXmlFile(name, skipError);
185
            continue;
186
        }
187
    }
188
189
    delete doc;
190
}
191
192
void NpcDialogDB::deleteDialog(const std::string &name)
193
{
194
    const DialogsIter it = mDialogs.find(name);
195
    if (it == mDialogs.end())
196
        return;
197
198
    NpcDialogInfo *dialog = (*it).second;
199
    delete_all(dialog->menu.buttons);
200
    delete_all(dialog->menu.images);
201
    delete_all(dialog->menu.texts);
202
    mDialogs.erase(it);
203
    delete dialog;
204
}
205
206
384
void NpcDialogDB::unload()
207
{
208
384
    logger->log1("Unloading npc dialog database...");
209
210
768
    FOR_EACH (DialogsIter, it, mDialogs)
211
    {
212
        NpcDialogInfo *dialog = (*it).second;
213
        delete_all(dialog->menu.buttons);
214
        delete_all(dialog->menu.images);
215
        delete_all(dialog->menu.texts);
216
        delete dialog;
217
    }
218
384
    mDialogs.clear();
219
220
384
    mLoaded = false;
221
384
}
222
223
NpcDialogInfo *NpcDialogDB::getDialog(const std::string &name)
224
{
225
    const DialogsIter it = mDialogs.find(name);
226
    if (it == mDialogs.end())
227
        return nullptr;
228
    return (*it).second;
229
4
}