GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/resources/db/emotedb.cpp Lines: 21 152 13.8 %
Date: 2017-11-29 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-2017  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
    unknownSprite->name = "unknown";
59
    unknownSprite->id = 0;
60
    mUnknown.sprites.push_back(unknownSprite);
61
62
    mLastEmote = 0;
63
    loadXmlFile(paths.getStringValue("emotesFile"), SkipError_false);
64
    loadXmlFile(paths.getStringValue("emotesPatchFile"), SkipError_true);
65
    loadXmlDir("emotesPatchDir", loadXmlFile);
66
    loadSpecialXmlFile("graphics/sprites/manaplus_emotes.xml",
67
        SkipError_false);
68
69
    mLoaded = true;
70
}
71
72
void EmoteDB::loadXmlFile(const std::string &fileName,
73
                          const SkipError skipError)
74
{
75
    XML::Document doc(fileName, UseVirtFs_true, skipError);
76
    XmlNodePtrConst rootNode = doc.rootNode();
77
78
    if ((rootNode == nullptr) || !xmlNameEqual(rootNode, "emotes"))
79
    {
80
        logger->log("Emote Database: Error while loading %s!",
81
            fileName.c_str());
82
        return;
83
    }
84
85
    // iterate <emote>s
86
    for_each_xml_child_node(emoteNode, rootNode)
87
    {
88
        if (xmlNameEqual(emoteNode, "include"))
89
        {
90
            const std::string name = XML::getProperty(emoteNode, "name", "");
91
            if (!name.empty())
92
                loadXmlFile(name, skipError);
93
            continue;
94
        }
95
        else if (!xmlNameEqual(emoteNode, "emote"))
96
        {
97
            continue;
98
        }
99
100
        const int id = XML::getProperty(emoteNode, "id", -1);
101
        // skip hight images
102
        if (id > 19 || (Client::isTmw() && id > 13))
103
            continue;
104
105
        if (id == -1)
106
        {
107
            reportAlways("Emote Database: Emote with missing ID in %s!",
108
                paths.getStringValue("emotesFile").c_str());
109
            continue;
110
        }
111
        EmoteInfo *currentInfo = nullptr;
112
        if (mEmoteInfos.find(id) != mEmoteInfos.end())
113
            currentInfo = mEmoteInfos[id];
114
        else
115
            currentInfo = new EmoteInfo;
116
        if (currentInfo == nullptr)
117
            continue;
118
        currentInfo->time = XML::getProperty(emoteNode, "time", 500);
119
        currentInfo->effectId = XML::getProperty(emoteNode, "effect", -1);
120
121
        for_each_xml_child_node(spriteNode, emoteNode)
122
        {
123
            if (!XmlHaveChildContent(spriteNode))
124
                continue;
125
126
            if (xmlNameEqual(spriteNode, "sprite"))
127
            {
128
                EmoteSprite *const currentSprite = new EmoteSprite;
129
                currentSprite->sprite = AnimatedSprite::load(pathJoin(
130
                    paths.getStringValue("sprites"),
131
                    XmlChildContent(spriteNode)),
132
                    XML::getProperty(spriteNode, "variant", 0));
133
                currentSprite->name = XML::langProperty(
134
                    spriteNode, "name", "");
135
                currentSprite->id = id;
136
                currentInfo->sprites.push_back(currentSprite);
137
            }
138
            else if (xmlNameEqual(spriteNode, "particlefx"))
139
            {
140
                currentInfo->particles.push_back(XmlChildContent(spriteNode));
141
            }
142
        }
143
        mEmoteInfos[id] = currentInfo;
144
        if (id > mLastEmote)
145
            mLastEmote = id;
146
    }
147
}
148
149
void EmoteDB::loadSpecialXmlFile(const std::string &fileName,
150
                                 const SkipError skipError)
151
{
152
    XML::Document doc(fileName, UseVirtFs_true, skipError);
153
    XmlNodePtrConst rootNode = doc.rootNode();
154
155
    if ((rootNode == nullptr) || !xmlNameEqual(rootNode, "emotes"))
156
    {
157
        logger->log1("Emote Database: Error while loading"
158
                     " manaplus_emotes.xml!");
159
        return;
160
    }
161
162
    // iterate <emote>s
163
    for_each_xml_child_node(emoteNode, rootNode)
164
    {
165
        if (xmlNameEqual(emoteNode, "include"))
166
        {
167
            const std::string name = XML::getProperty(emoteNode, "name", "");
168
            if (!name.empty())
169
                loadSpecialXmlFile(name, skipError);
170
            continue;
171
        }
172
        else if (!xmlNameEqual(emoteNode, "emote"))
173
        {
174
            continue;
175
        }
176
177
        const int id = XML::getProperty(emoteNode, "id", -1);
178
        if (id == -1)
179
        {
180
            reportAlways("Emote Database: Emote with missing ID in "
181
                "manaplus_emotes.xml!");
182
            continue;
183
        }
184
        const int altId = XML::getProperty(emoteNode, "altid", -1);
185
186
        EmoteInfo *currentInfo = nullptr;
187
        if (mEmoteInfos.find(id) != mEmoteInfos.end())
188
            currentInfo = mEmoteInfos[id];
189
        if (currentInfo == nullptr)
190
            currentInfo = new EmoteInfo;
191
        currentInfo->time = XML::getProperty(emoteNode, "time", 500);
192
        currentInfo->effectId = XML::getProperty(emoteNode, "effect", -1);
193
194
        for_each_xml_child_node(spriteNode, emoteNode)
195
        {
196
            if (!XmlHaveChildContent(spriteNode))
197
                continue;
198
199
            if (xmlNameEqual(spriteNode, "sprite"))
200
            {
201
                EmoteSprite *const currentSprite = new EmoteSprite;
202
                currentSprite->sprite = AnimatedSprite::load(pathJoin(
203
                    paths.getStringValue("sprites"),
204
                    XmlChildContent(spriteNode)),
205
                    XML::getProperty(spriteNode, "variant", 0));
206
                currentSprite->name = XML::langProperty(
207
                    spriteNode, "name", "");
208
                currentSprite->id = id;
209
                currentInfo->sprites.push_back(currentSprite);
210
            }
211
            else if (xmlNameEqual(spriteNode, "particlefx"))
212
            {
213
                currentInfo->particles.push_back(XmlChildContent(spriteNode));
214
            }
215
        }
216
        mEmoteInfos[id] = currentInfo;
217
        if (altId != -1)
218
            mEmotesAlt[altId] = id;
219
220
        if (id > mLastEmote)
221
            mLastEmote = id;
222
    }
223
}
224
225
384
void EmoteDB::unload()
226
{
227
384
    logger->log1("Unloading emote database...");
228
1536
    FOR_EACH (EmoteInfos::const_iterator, i, mEmoteInfos)
229
    {
230
        if (i->second != nullptr)
231
        {
232
            std::list<EmoteSprite*> &sprites = i->second->sprites;
233
            while (!sprites.empty())
234
            {
235
                delete sprites.front()->sprite;
236
                delete sprites.front();
237
                sprites.pop_front();
238
            }
239
            delete i->second;
240
        }
241
    }
242
243
384
    mEmoteInfos.clear();
244
245
384
    std::list<EmoteSprite*> &sprites = mUnknown.sprites;
246
384
    while (!sprites.empty())
247
    {
248
        delete sprites.front()->sprite;
249
        delete sprites.front();
250
        sprites.pop_front();
251
    }
252
253
384
    mLoaded = false;
254
384
}
255
256
2
const EmoteInfo *EmoteDB::get(const int id, const bool allowNull)
257
{
258
4
    const EmoteInfos::const_iterator i = mEmoteInfos.find(id);
259
260
2
    if (i == mEmoteInfos.end())
261
    {
262
2
        if (allowNull)
263
            return nullptr;
264
        reportAlways("EmoteDB: Warning, unknown emote ID %d requested",
265
            id);
266
        return &mUnknown;
267
    }
268
    return i->second;
269
}
270
271
const EmoteInfo *EmoteDB::get2(int id, const bool allowNull)
272
{
273
    const EmoteToEmote::const_iterator it = mEmotesAlt.find(id);
274
    if (it != mEmotesAlt.end())
275
        id = (*it).second;
276
277
    const EmoteInfos::const_iterator i = mEmoteInfos.find(id);
278
279
    if (i == mEmoteInfos.end())
280
    {
281
        if (allowNull)
282
            return nullptr;
283
        reportAlways("EmoteDB: Warning, unknown emote ID %d requested",
284
            id);
285
        return &mUnknown;
286
    }
287
    return i->second;
288
}
289
290
2
const EmoteSprite *EmoteDB::getSprite(const int id, const bool allowNull)
291
{
292
2
    const EmoteInfo *const info = get(id, allowNull);
293
2
    if (info == nullptr)
294
        return nullptr;
295
296
    return info->sprites.front();
297
}
298
299
4
const int &EmoteDB::getLast()
300
{
301
4
    return mLastEmote;
302
}
303
304
int EmoteDB::size()
305
{
306
    return static_cast<signed int>(mEmoteInfos.size());
307
}
308
309
int EmoteDB::getIdByIndex(const int index)
310
{
311
    if (index < 0 || index >= static_cast<signed int>(mEmoteInfos.size()))
312
        return 0;
313
    EmoteInfos::const_iterator it = mEmoteInfos.begin();
314
    for (int f = 0; f < index; f ++)
315
        ++ it;
316
    return (*it).first;
317

6
}