GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/resources/db/emotedb.cpp Lines: 21 150 14.0 %
Date: 2021-03-17 Branches: 7 284 2.5 %

Line Branch Exec Source
1
/*
2
 *  The ManaPlus Client
3
 *  Copyright (C) 2009  Aethyra Development Team
4
 *  Copyright (C) 2011-2019  The ManaPlus Developers
5
 *  Copyright (C) 2019-2021  Andrei Karas
6
 *
7
 *  This file is part of The ManaPlus Client.
8
 *
9
 *  This program is free software; you can redistribute it and/or modify
10
 *  it under the terms of the GNU General Public License as published by
11
 *  the Free Software Foundation; either version 2 of the License, or
12
 *  any later version.
13
 *
14
 *  This program is distributed in the hope that it will be useful,
15
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 *  GNU General Public License for more details.
18
 *
19
 *  You should have received a copy of the GNU General Public License
20
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
 */
22
23
#include "resources/db/emotedb.h"
24
25
#include "client.h"
26
27
#include "configuration.h"
28
29
#include "utils/checkutils.h"
30
31
#include "resources/beingcommon.h"
32
#include "resources/emoteinfo.h"
33
#include "resources/emotesprite.h"
34
35
#include "resources/sprite/animatedsprite.h"
36
37
#include "debug.h"
38
39
namespace
40
{
41
1
    EmoteInfos mEmoteInfos;
42
1
    EmoteToEmote mEmotesAlt;
43
1
    EmoteInfo mUnknown;
44
    bool mLoaded = false;
45
    int mLastEmote = 0;
46
}  // namespace
47
48
void EmoteDB::load()
49
{
50
    if (mLoaded)
51
        unload();
52
53
    logger->log1("Initializing emote database...");
54
55
    EmoteSprite *const unknownSprite = new EmoteSprite;
56
    unknownSprite->sprite = AnimatedSprite::load(pathJoin(paths.getStringValue(
57
        "sprites"), paths.getStringValue(
58
        "spriteErrorFile")),
59
        0);
60
    unknownSprite->name = "unknown";
61
    unknownSprite->id = 0;
62
    mUnknown.sprites.push_back(unknownSprite);
63
64
    mLastEmote = 0;
65
    loadXmlFile(paths.getStringValue("emotesFile"), SkipError_false);
66
    loadXmlFile(paths.getStringValue("emotesPatchFile"), SkipError_true);
67
    loadXmlDir("emotesPatchDir", loadXmlFile)
68
    loadSpecialXmlFile("graphics/sprites/manaplus_emotes.xml",
69
        SkipError_false);
70
71
    mLoaded = true;
72
}
73
74
void EmoteDB::loadXmlFile(const std::string &fileName,
75
                          const SkipError skipError)
76
{
77
    XML::Document doc(fileName, UseVirtFs_true, skipError);
78
    XmlNodePtrConst rootNode = doc.rootNode();
79
80
    if ((rootNode == nullptr) || !xmlNameEqual(rootNode, "emotes"))
81
    {
82
        logger->log("Emote Database: Error while loading %s!",
83
            fileName.c_str());
84
        return;
85
    }
86
87
    // iterate <emote>s
88
    for_each_xml_child_node(emoteNode, rootNode)
89
    {
90
        if (xmlNameEqual(emoteNode, "include"))
91
        {
92
            const std::string name = XML::getProperty(emoteNode, "name", "");
93
            if (!name.empty())
94
                loadXmlFile(name, skipError);
95
            continue;
96
        }
97
        else if (!xmlNameEqual(emoteNode, "emote"))
98
        {
99
            continue;
100
        }
101
102
        const int id = XML::getProperty(emoteNode, "id", -1);
103
        // skip hight images
104
        if (id > 19 || (Client::isTmw() && id > 13))
105
            continue;
106
107
        if (id == -1)
108
        {
109
            reportAlways("Emote Database: Emote with missing ID in %s!",
110
                paths.getStringValue("emotesFile").c_str())
111
            continue;
112
        }
113
        EmoteInfo *currentInfo = nullptr;
114
        if (mEmoteInfos.find(id) != mEmoteInfos.end())
115
            currentInfo = mEmoteInfos[id];
116
        else
117
            currentInfo = new EmoteInfo;
118
        if (currentInfo == nullptr)
119
            continue;
120
        currentInfo->time = XML::getProperty(emoteNode, "time", 500);
121
        currentInfo->effectId = XML::getProperty(emoteNode, "effect", -1);
122
123
        for_each_xml_child_node(spriteNode, emoteNode)
124
        {
125
            if (!XmlHaveChildContent(spriteNode))
126
                continue;
127
128
            if (xmlNameEqual(spriteNode, "sprite"))
129
            {
130
                EmoteSprite *const currentSprite = new EmoteSprite;
131
                currentSprite->sprite = AnimatedSprite::load(pathJoin(
132
                    paths.getStringValue("sprites"),
133
                    XmlChildContent(spriteNode)),
134
                    XML::getProperty(spriteNode, "variant", 0));
135
                currentSprite->name = XML::langProperty(
136
                    spriteNode, "name", "");
137
                currentSprite->id = id;
138
                currentInfo->sprites.push_back(currentSprite);
139
            }
140
            else if (xmlNameEqual(spriteNode, "particlefx"))
141
            {
142
                currentInfo->particles.push_back(XmlChildContent(spriteNode));
143
            }
144
        }
145
        mEmoteInfos[id] = currentInfo;
146
        if (id > mLastEmote)
147
            mLastEmote = id;
148
    }
149
}
150
151
void EmoteDB::loadSpecialXmlFile(const std::string &fileName,
152
                                 const SkipError skipError)
153
{
154
    XML::Document doc(fileName, UseVirtFs_true, skipError);
155
    XmlNodePtrConst rootNode = doc.rootNode();
156
157
    if ((rootNode == nullptr) || !xmlNameEqual(rootNode, "emotes"))
158
    {
159
        logger->log1("Emote Database: Error while loading"
160
                     " manaplus_emotes.xml!");
161
        return;
162
    }
163
164
    // iterate <emote>s
165
    for_each_xml_child_node(emoteNode, rootNode)
166
    {
167
        if (xmlNameEqual(emoteNode, "include"))
168
        {
169
            const std::string name = XML::getProperty(emoteNode, "name", "");
170
            if (!name.empty())
171
                loadSpecialXmlFile(name, skipError);
172
            continue;
173
        }
174
        else if (!xmlNameEqual(emoteNode, "emote"))
175
        {
176
            continue;
177
        }
178
179
        const int id = XML::getProperty(emoteNode, "id", -1);
180
        if (id == -1)
181
        {
182
            reportAlways("Emote Database: Emote with missing ID in "
183
                "manaplus_emotes.xml!")
184
            continue;
185
        }
186
        const int altId = XML::getProperty(emoteNode, "altid", -1);
187
188
        EmoteInfo *currentInfo = nullptr;
189
        if (mEmoteInfos.find(id) != mEmoteInfos.end())
190
            currentInfo = mEmoteInfos[id];
191
        if (currentInfo == nullptr)
192
            currentInfo = new EmoteInfo;
193
        currentInfo->time = XML::getProperty(emoteNode, "time", 500);
194
        currentInfo->effectId = XML::getProperty(emoteNode, "effect", -1);
195
196
        for_each_xml_child_node(spriteNode, emoteNode)
197
        {
198
            if (!XmlHaveChildContent(spriteNode))
199
                continue;
200
201
            if (xmlNameEqual(spriteNode, "sprite"))
202
            {
203
                EmoteSprite *const currentSprite = new EmoteSprite;
204
                currentSprite->sprite = AnimatedSprite::load(pathJoin(
205
                    paths.getStringValue("sprites"),
206
                    XmlChildContent(spriteNode)),
207
                    XML::getProperty(spriteNode, "variant", 0));
208
                currentSprite->name = XML::langProperty(
209
                    spriteNode, "name", "");
210
                currentSprite->id = id;
211
                currentInfo->sprites.push_back(currentSprite);
212
            }
213
            else if (xmlNameEqual(spriteNode, "particlefx"))
214
            {
215
                currentInfo->particles.push_back(XmlChildContent(spriteNode));
216
            }
217
        }
218
        mEmoteInfos[id] = currentInfo;
219
        if (altId != -1)
220
            mEmotesAlt[altId] = id;
221
222
        if (id > mLastEmote)
223
            mLastEmote = id;
224
    }
225
}
226
227
204
void EmoteDB::unload()
228
{
229
204
    logger->log1("Unloading emote database...");
230
816
    FOR_EACH (EmoteInfos::const_iterator, i, mEmoteInfos)
231
    {
232
        if (i->second != nullptr)
233
        {
234
            std::list<EmoteSprite*> &sprites = i->second->sprites;
235
            while (!sprites.empty())
236
            {
237
                delete sprites.front()->sprite;
238
                delete sprites.front();
239
                sprites.pop_front();
240
            }
241
            delete i->second;
242
        }
243
    }
244
245
204
    mEmoteInfos.clear();
246
247
204
    std::list<EmoteSprite*> &sprites = mUnknown.sprites;
248
204
    while (!sprites.empty())
249
    {
250
        delete sprites.front()->sprite;
251
        delete sprites.front();
252
        sprites.pop_front();
253
    }
254
255
204
    mLoaded = false;
256
204
}
257
258
1
const EmoteInfo *EmoteDB::get(const int id, const bool allowNull)
259
{
260
2
    const EmoteInfos::const_iterator i = mEmoteInfos.find(id);
261
262
1
    if (i == mEmoteInfos.end())
263
    {
264
1
        if (allowNull)
265
            return nullptr;
266
        reportAlways("EmoteDB: Warning, unknown emote ID %d requested",
267
            id)
268
        return &mUnknown;
269
    }
270
    return i->second;
271
}
272
273
const EmoteInfo *EmoteDB::get2(int id, const bool allowNull)
274
{
275
    const EmoteToEmote::const_iterator it = mEmotesAlt.find(id);
276
    if (it != mEmotesAlt.end())
277
        id = (*it).second;
278
279
    const EmoteInfos::const_iterator i = mEmoteInfos.find(id);
280
281
    if (i == mEmoteInfos.end())
282
    {
283
        if (allowNull)
284
            return nullptr;
285
        reportAlways("EmoteDB: Warning, unknown emote ID %d requested",
286
            id)
287
        return &mUnknown;
288
    }
289
    return i->second;
290
}
291
292
1
const EmoteSprite *EmoteDB::getSprite(const int id, const bool allowNull)
293
{
294
1
    const EmoteInfo *const info = get(id, allowNull);
295
1
    if (info == nullptr)
296
        return nullptr;
297
298
    return info->sprites.front();
299
}
300
301
2
const int &EmoteDB::getLast()
302
{
303
2
    return mLastEmote;
304
}
305
306
int EmoteDB::size()
307
{
308
    return static_cast<signed int>(mEmoteInfos.size());
309
}
310
311
int EmoteDB::getIdByIndex(const int index)
312
{
313
    if (index < 0 || index >= static_cast<signed int>(mEmoteInfos.size()))
314
        return 0;
315
    EmoteInfos::const_iterator it = mEmoteInfos.begin();
316
    for (int f = 0; f < index; f ++)
317
        ++ it;
318
    return (*it).first;
319

3
}