GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/resources/db/monsterdb.cpp Lines: 8 64 12.5 %
Date: 2021-03-17 Branches: 0 110 0.0 %

Line Branch Exec Source
1
/*
2
 *  The ManaPlus Client
3
 *  Copyright (C) 2004-2009  The Mana World Development Team
4
 *  Copyright (C) 2009-2010  The Mana Developers
5
 *  Copyright (C) 2011-2019  The ManaPlus Developers
6
 *  Copyright (C) 2019-2021  Andrei Karas
7
 *
8
 *  This file is part of The ManaPlus Client.
9
 *
10
 *  This program is free software; you can redistribute it and/or modify
11
 *  it under the terms of the GNU General Public License as published by
12
 *  the Free Software Foundation; either version 2 of the License, or
13
 *  any later version.
14
 *
15
 *  This program is distributed in the hope that it will be useful,
16
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 *  GNU General Public License for more details.
19
 *
20
 *  You should have received a copy of the GNU General Public License
21
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
22
 */
23
24
#include "resources/db/monsterdb.h"
25
26
#include "enums/resources/map/blockmask.h"
27
28
#include "resources/beingcommon.h"
29
#include "resources/beinginfo.h"
30
31
#include "utils/checkutils.h"
32
#include "utils/dtor.h"
33
#include "utils/gettext.h"
34
35
#include "configuration.h"
36
37
#include "debug.h"
38
39
static const unsigned int OLD_TMWATHENA_OFFSET = 1002;
40
41
namespace
42
{
43
1
    BeingInfos mMonsterInfos;
44
    bool mLoaded = false;
45
}  // namespace
46
47
void MonsterDB::load()
48
{
49
    if (mLoaded)
50
        unload();
51
52
    logger->log1("Initializing monster database...");
53
    loadXmlFile(paths.getStringValue("monstersFile"), SkipError_false);
54
    loadXmlFile(paths.getStringValue("monstersPatchFile"), SkipError_true);
55
    loadXmlDir("monstersPatchDir", loadXmlFile)
56
57
    mLoaded = true;
58
}
59
60
void MonsterDB::loadXmlFile(const std::string &fileName,
61
                            const SkipError skipError)
62
{
63
    XML::Document doc(fileName, UseVirtFs_true, skipError);
64
    XmlNodeConstPtr rootNode = doc.rootNode();
65
66
    if ((rootNode == nullptr) || !xmlNameEqual(rootNode, "monsters"))
67
    {
68
        logger->log("Monster Database: Error while loading %s!",
69
            paths.getStringValue("monstersFile").c_str());
70
        mLoaded = true;
71
        return;
72
    }
73
74
    const int offset = XML::getProperty(rootNode,
75
        "offset", OLD_TMWATHENA_OFFSET);
76
77
    // iterate <monster>s
78
    for_each_xml_child_node(monsterNode, rootNode)
79
    {
80
        if (xmlNameEqual(monsterNode, "include"))
81
        {
82
            const std::string name = XML::getProperty(monsterNode, "name", "");
83
            if (!name.empty())
84
                loadXmlFile(name, skipError);
85
            continue;
86
        }
87
        if (!xmlNameEqual(monsterNode, "monster"))
88
            continue;
89
90
        const int id = XML::getProperty(monsterNode, "id", 0);
91
        BeingInfo *currentInfo = nullptr;
92
        if (mMonsterInfos.find(fromInt(id + offset, BeingTypeId))
93
            != mMonsterInfos.end())
94
        {
95
            logger->log("MonsterDB: Redefinition of monster ID %d", id);
96
            currentInfo = mMonsterInfos[fromInt(id + offset, BeingTypeId)];
97
        }
98
        if (currentInfo == nullptr)
99
            currentInfo = new BeingInfo;
100
101
        currentInfo->setBlockType(BlockType::NONE);
102
        currentInfo->setName(XML::langProperty(
103
            // TRANSLATORS: unknown info name
104
            monsterNode, "name", _("unnamed")));
105
106
        BeingCommon::readBasicAttributes(currentInfo, monsterNode, "attack");
107
        BeingCommon::readWalkingAttributes(currentInfo, monsterNode,
108
            BlockMask::MONSTERWALL);
109
110
        currentInfo->setMaxHP(XML::getProperty(monsterNode, "maxHP", 0));
111
112
        currentInfo->setDeadSortOffsetY(XML::getProperty(
113
            monsterNode, "deadSortOffsetY", 31));
114
115
        currentInfo->setColorsList(XML::getProperty(monsterNode,
116
            "colors", ""));
117
118
        if (currentInfo->getMaxHP() != 0)
119
            currentInfo->setStaticMaxHP(true);
120
121
        SpriteDisplay display;
122
123
        // iterate <sprite>s and <sound>s
124
        for_each_xml_child_node(spriteNode, monsterNode)
125
        {
126
            BeingCommon::readObjectNodes(spriteNode, display,
127
                currentInfo, "MonsterDB");
128
        }
129
        currentInfo->setDisplay(display);
130
131
        mMonsterInfos[fromInt(id + offset, BeingTypeId)] = currentInfo;
132
    }
133
}
134
135
204
void MonsterDB::unload()
136
{
137
204
    logger->log1("Unloading monster database...");
138
204
    delete_all(mMonsterInfos);
139
204
    mMonsterInfos.clear();
140
141
204
    mLoaded = false;
142
204
}
143
144
145
BeingInfo *MonsterDB::get(const BeingTypeId id)
146
{
147
    BeingInfoIterator i = mMonsterInfos.find(id);
148
149
    if (i == mMonsterInfos.end())
150
    {
151
        i = mMonsterInfos.find(fromInt(toInt(
152
            id, int) + OLD_TMWATHENA_OFFSET, BeingTypeId));
153
        if (i == mMonsterInfos.end())
154
        {
155
            reportAlways("MonsterDB: Warning, unknown monster ID %d requested",
156
                toInt(id, int))
157
            return BeingInfo::unknown;
158
        }
159
    }
160
    return i->second;
161
2
}