GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/resources/db/horsedb.cpp Lines: 3 116 2.6 %
Date: 2021-03-17 Branches: 2 236 0.8 %

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

3
}