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

6
}