GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/resources/db/horsedb.cpp Lines: 3 117 2.6 %
Date: 2017-11-29 Branches: 2 234 0.9 %

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/horsedb.h"
23
24
#include "configuration.h"
25
26
#include "enums/resources/spritedirection.h"
27
28
#include "resources/beingcommon.h"
29
#include "resources/horseinfo.h"
30
31
#include "utils/checkutils.h"
32
#include "utils/dtor.h"
33
34
#include "debug.h"
35
36
namespace
37
{
38
2
    HorseInfos mHorseInfos;
39
2
    HorseInfo mUnknown;
40
    bool mLoaded = false;
41
}  // namespace
42
43
#define loadSprite(name) \
44
    { \
45
        SpriteReference *const currentSprite = new SpriteReference; \
46
        currentSprite->sprite = pathJoin(paths.getStringValue("sprites"), \
47
            XmlChildContent(spriteNode)); \
48
        currentSprite->variant = XML::getProperty( \
49
            spriteNode, "variant", 0); \
50
        currentInfo->name.push_back(currentSprite); \
51
    }
52
53
static void loadDownSprites(XmlNodePtrConst parentNode,
54
                            HorseInfo *const currentInfo);
55
56
static void loadUpSprites(XmlNodePtrConst parentNode,
57
                          HorseInfo *const currentInfo);
58
59
void HorseDB::load()
60
{
61
    if (mLoaded)
62
        unload();
63
64
    logger->log1("Initializing horse database...");
65
66
    SpriteReference *currentSprite = new SpriteReference;
67
    currentSprite->sprite = pathJoin(paths.getStringValue("sprites"),
68
        paths.getStringValue("spriteErrorFile"));
69
    currentSprite->variant = 0;
70
    mUnknown.downSprites.push_back(currentSprite);
71
72
    currentSprite = new SpriteReference;
73
    currentSprite->sprite = pathJoin(paths.getStringValue("sprites"),
74
        paths.getStringValue("spriteErrorFile"));
75
    currentSprite->variant = 0;
76
    mUnknown.upSprites.push_back(currentSprite);
77
78
    loadXmlFile(paths.getStringValue("horsesFile"), SkipError_false);
79
    loadXmlFile(paths.getStringValue("horsesPatchFile"), SkipError_true);
80
    loadXmlDir("horsesPatchDir", loadXmlFile);
81
82
    mLoaded = true;
83
}
84
85
static int parseDirectionName(const std::string &name)
86
{
87
    int id = -1;
88
    if (name == "down")
89
    {
90
        id = SpriteDirection::DOWN;
91
    }
92
    else if (name == "downleft" || name == "leftdown")
93
    {
94
        id = SpriteDirection::DOWNLEFT;
95
    }
96
    else if (name == "left")
97
    {
98
        id = SpriteDirection::LEFT;
99
    }
100
    else if (name == "upleft" || name == "leftup")
101
    {
102
        id = SpriteDirection::UPLEFT;
103
    }
104
    else if (name == "up")
105
    {
106
        id = SpriteDirection::UP;
107
    }
108
    else if (name == "upright" || name == "rightup")
109
    {
110
        id = SpriteDirection::UPRIGHT;
111
    }
112
    else if (name == "right")
113
    {
114
        id = SpriteDirection::RIGHT;
115
    }
116
    else if (name == "downright" || name == "rightdown")
117
    {
118
        id = SpriteDirection::DOWNRIGHT;
119
    }
120
    // hack for died action.
121
    else if (name == "died")
122
    {
123
        id = 9;
124
    }
125
126
    return id;
127
}
128
129
static void loadRiderOffset(XmlNodePtrConst node,
130
                            HorseInfo *const currentInfo)
131
{
132
    const std::string dirName = XML::getProperty(node,
133
        "direction", "");
134
    const int dir = parseDirectionName(dirName);
135
    if (dir == -1)
136
    {
137
        reportAlways("Wrong or missing horse rider direcion: %s",
138
            dirName.c_str());
139
        return;
140
    }
141
    HorseOffset &offset = currentInfo->offsets[dir];
142
    offset.riderOffsetX = XML::getProperty(node,
143
        "riderOffsetX", 0);
144
    offset.riderOffsetY = XML::getProperty(node,
145
        "riderOffsetY", 0);
146
}
147
148
void HorseDB::loadXmlFile(const std::string &fileName,
149
                          const SkipError skipError)
150
{
151
    XML::Document doc(fileName,
152
        UseVirtFs_true,
153
        skipError);
154
    XmlNodePtrConst rootNode = doc.rootNode();
155
156
    if ((rootNode == nullptr) || !xmlNameEqual(rootNode, "horses"))
157
    {
158
        logger->log("Horse Database: Error while loading %s!",
159
            fileName.c_str());
160
        return;
161
    }
162
163
    // iterate <emote>s
164
    for_each_xml_child_node(horseNode, rootNode)
165
    {
166
        if (xmlNameEqual(horseNode, "include"))
167
        {
168
            const std::string name = XML::getProperty(horseNode, "name", "");
169
            if (!name.empty())
170
                loadXmlFile(name, skipError);
171
            continue;
172
        }
173
        else if (!xmlNameEqual(horseNode, "horse"))
174
        {
175
            continue;
176
        }
177
178
        const int id = XML::getProperty(horseNode, "id", -1);
179
180
        if (id == -1)
181
        {
182
            reportAlways("Horse Database: Horse with missing ID in %s!",
183
                paths.getStringValue("horsesFile").c_str());
184
            continue;
185
        }
186
        HorseInfo *currentInfo = nullptr;
187
        if (mHorseInfos.find(id) != mHorseInfos.end())
188
            currentInfo = mHorseInfos[id];
189
        else
190
            currentInfo = new HorseInfo;
191
192
        if (currentInfo == nullptr)
193
            continue;
194
        for_each_xml_child_node(spriteNode, horseNode)
195
        {
196
            if (xmlNameEqual(spriteNode, "down"))
197
                loadDownSprites(spriteNode, currentInfo);
198
            else if (xmlNameEqual(spriteNode, "up"))
199
                loadUpSprites(spriteNode, currentInfo);
200
            else if (xmlNameEqual(spriteNode, "offset"))
201
                loadRiderOffset(spriteNode, currentInfo);
202
        }
203
        mHorseInfos[id] = currentInfo;
204
    }
205
}
206
207
static void loadOffset(XmlNodePtrConst node,
208
                       HorseInfo *const currentInfo,
209
                       const bool isUp)
210
{
211
    const std::string dirName = XML::getProperty(node,
212
        "direction", "");
213
    const int dir = parseDirectionName(dirName);
214
    if (dir == -1)
215
    {
216
        reportAlways("Wrong or missing horse direcion: %s",
217
            dirName.c_str());
218
        return;
219
    }
220
    HorseOffset &offset = currentInfo->offsets[dir];
221
    if (isUp)
222
    {
223
        offset.upOffsetX = XML::getProperty(node,
224
            "horseOffsetX", 0);
225
        offset.upOffsetY = XML::getProperty(node,
226
            "horseOffsetY", 0);
227
    }
228
    else
229
    {
230
        offset.downOffsetX = XML::getProperty(node,
231
            "horseOffsetX", 0);
232
        offset.downOffsetY = XML::getProperty(node,
233
            "horseOffsetY", 0);
234
    }
235
}
236
237
static void loadDownSprites(XmlNodePtrConst parentNode,
238
                            HorseInfo *const currentInfo)
239
{
240
    for_each_xml_child_node(spriteNode, parentNode)
241
    {
242
        if (xmlNameEqual(spriteNode, "offset"))
243
            loadOffset(spriteNode, currentInfo, false);
244
        if (!XmlHaveChildContent(spriteNode))
245
            continue;
246
        if (xmlNameEqual(spriteNode, "sprite"))
247
            loadSprite(downSprites)
248
    }
249
}
250
251
static void loadUpSprites(XmlNodePtrConst parentNode,
252
                          HorseInfo *const currentInfo)
253
{
254
    for_each_xml_child_node(spriteNode, parentNode)
255
    {
256
        if (xmlNameEqual(spriteNode, "offset"))
257
            loadOffset(spriteNode, currentInfo, true);
258
        if (!XmlHaveChildContent(spriteNode))
259
            continue;
260
        if (xmlNameEqual(spriteNode, "sprite"))
261
            loadSprite(upSprites)
262
    }
263
}
264
265
void HorseDB::unload()
266
{
267
    logger->log1("Unloading horse database...");
268
    FOR_EACH (HorseInfos::const_iterator, i, mHorseInfos)
269
    {
270
        delete_all(i->second->upSprites);
271
        delete_all(i->second->downSprites);
272
        delete i->second;
273
    }
274
    mHorseInfos.clear();
275
276
    delete_all(mUnknown.upSprites);
277
    delete_all(mUnknown.downSprites);
278
    mUnknown.upSprites.clear();
279
    mUnknown.downSprites.clear();
280
281
    mLoaded = false;
282
}
283
284
HorseInfo *HorseDB::get(const int id, const bool allowNull)
285
{
286
    const HorseInfos::const_iterator i = mHorseInfos.find(id);
287
288
    if (i == mHorseInfos.end())
289
    {
290
        if (allowNull)
291
            return nullptr;
292
        reportAlways("HorseDB: Warning, unknown horse ID %d requested",
293
            id);
294
        return &mUnknown;
295
    }
296
    return i->second;
297
}
298
299
int HorseDB::size()
300
{
301
    return static_cast<signed int>(mHorseInfos.size());
302

6
}