1 /*
2 * The ManaPlus Client
3 * Copyright (C) 2013-2019 The ManaPlus Developers
4 * Copyright (C) 2019-2021 Andrei Karas
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/beingcommon.h"
23
24 #include "configuration.h"
25 #include "logger.h"
26
27 #include "enums/resources/map/blockmask.h"
28
29 #include "utils/cast.h"
30
31 #include "resources/beinginfo.h"
32
33 #include "resources/sprite/spritereference.h"
34
35 #include "debug.h"
36
readBasicAttributes(BeingInfo * const info,XmlNodePtrConst node,const std::string & hoverCursor)37 void BeingCommon::readBasicAttributes(BeingInfo *const info,
38 XmlNodePtrConst node,
39 const std::string &hoverCursor)
40 {
41 info->setTargetCursorSize(XML::getProperty(node,
42 "targetCursor", "medium"));
43
44 info->setHoverCursor(XML::getProperty(node, "hoverCursor", hoverCursor));
45
46 info->setTargetOffsetX(XML::getProperty(node, "targetOffsetX", 0));
47 info->setTargetOffsetY(XML::getProperty(node, "targetOffsetY", 0));
48
49 info->setNameOffsetX(XML::getProperty(node, "nameOffsetX", 0));
50 info->setNameOffsetY(XML::getProperty(node, "nameOffsetY", 0));
51 info->setSortOffsetY(XML::getProperty(node, "sortOffsetY", 0));
52
53 info->setHpBarOffsetX(XML::getProperty(node, "hpBarOffsetX", 0));
54 info->setHpBarOffsetY(XML::getProperty(node, "hpBarOffsetY", 0));
55
56 info->setQuickActionEffectId(XML::getProperty(node,
57 "quickActionEffect", -1));
58 }
59
readWalkingAttributes(BeingInfo * const info,XmlNodePtrConst node,const int moreBlockFlags)60 void BeingCommon::readWalkingAttributes(BeingInfo *const info,
61 XmlNodePtrConst node,
62 const int moreBlockFlags)
63 {
64 uint8_t block = 0;
65 std::string walkStr = XML::getProperty(
66 node, "walkType", "walk");
67
68 const uint8_t allFlags = CAST_U8(
69 BlockMask::GROUND |
70 BlockMask::WALL |
71 BlockMask::WATER |
72 BlockMask::AIR |
73 moreBlockFlags);
74 StringVect tokens;
75 splitToStringVector(tokens, walkStr, ',');
76 FOR_EACH (StringVectCIter, it, tokens)
77 {
78 if (walkStr == "walk" || walkStr == "ground")
79 block |= BlockMask::GROUND;
80 else if (walkStr == "fly" || walkStr == "air")
81 block |= BlockMask::GROUND | BlockMask::WATER | BlockMask::AIR;
82 else if (walkStr == "all")
83 block |= allFlags;
84 else if (walkStr == "wall")
85 block |= BlockMask::WALL;
86 else if (walkStr == "monsterwall")
87 block |= BlockMask::MONSTERWALL;
88 else if (walkStr == "swim" || walkStr == "water")
89 block |= BlockMask::WATER;
90 else if (walkStr == "walkswim" || walkStr == "swimwalk") // legacy
91 block |= BlockMask::GROUND | BlockMask::WATER;
92 }
93 info->setBlockWalkMask(CAST_U8(block ^ allFlags));
94 }
95
readAiAttributes(BeingInfo * const info,XmlNodePtrConst node)96 void BeingCommon::readAiAttributes(BeingInfo *const info,
97 XmlNodePtrConst node)
98 {
99 info->setStartFollowDist(XML::getProperty(node,
100 "startFollowDistance", 3));
101 info->setFollowDist(XML::getProperty(node,
102 "followDistance", 0));
103 info->setWarpDist(XML::getProperty(node,
104 "warpDistance", 11));
105
106 info->setTargetOffsetX(XML::getProperty(node,
107 "offsetX", 0));
108 info->setTargetOffsetY(XML::getProperty(node,
109 "offsetY", 1));
110 info->setSitOffsetX(XML::getProperty(node,
111 "sitOffsetX", 0));
112 info->setSitOffsetY(XML::getProperty(node,
113 "sitOffsetY", 1));
114 info->setMoveOffsetX(XML::getProperty(node,
115 "moveOffsetX", 0));
116 info->setMoveOffsetY(XML::getProperty(node,
117 "moveOffsetY", 1));
118 info->setDeadOffsetX(XML::getProperty(node,
119 "deadOffsetX", 0));
120 info->setDeadOffsetY(XML::getProperty(node,
121 "deadOffsetY", 1));
122 info->setAttackOffsetX(XML::getProperty(node,
123 "attackOffsetX", info->getTargetOffsetX()));
124 info->setAttackOffsetY(XML::getProperty(node,
125 "attackOffsetY", info->getTargetOffsetY()));
126
127 info->setThinkTime(XML::getProperty(node,
128 "thinkTime", 500) / 10);
129
130 info->setDirectionType(XML::getProperty(node,
131 "directionType", 1));
132 info->setSitDirectionType(XML::getProperty(node,
133 "sitDirectionType", 1));
134 info->setDeadDirectionType(XML::getProperty(node,
135 "deadDirectionType", 1));
136 info->setAttackDirectionType(XML::getProperty(node,
137 "attackDirectionType", 4));
138 }
139
readObjectNodes(XmlNodePtrConst & spriteNode,SpriteDisplay & display,BeingInfo * const currentInfo,const std::string & dbName)140 bool BeingCommon::readObjectNodes(XmlNodePtrConst &spriteNode,
141 SpriteDisplay &display,
142 BeingInfo *const currentInfo,
143 const std::string &dbName)
144 {
145 if (xmlNameEqual(spriteNode, "sprite"))
146 {
147 if (!XmlHaveChildContent(spriteNode))
148 return true;
149
150 SpriteReference *const currentSprite = new SpriteReference;
151 currentSprite->sprite = XmlChildContent(spriteNode);
152
153 currentSprite->variant = XML::getProperty(
154 spriteNode, "variant", 0);
155 display.sprites.push_back(currentSprite);
156 return true;
157 }
158 else if (xmlNameEqual(spriteNode, "sound"))
159 {
160 if (!XmlHaveChildContent(spriteNode))
161 return true;
162
163 const std::string event = XML::getProperty(
164 spriteNode, "event", "");
165 const int delay = XML::getProperty(
166 spriteNode, "delay", 0);
167 const char *const filename = XmlChildContent(spriteNode);
168
169 if (event == "hit")
170 {
171 currentInfo->addSound(ItemSoundEvent::HIT, filename, delay);
172 }
173 else if (event == "miss")
174 {
175 currentInfo->addSound(ItemSoundEvent::MISS, filename, delay);
176 }
177 else if (event == "hurt")
178 {
179 currentInfo->addSound(ItemSoundEvent::HURT, filename, delay);
180 }
181 else if (event == "die")
182 {
183 currentInfo->addSound(ItemSoundEvent::DIE, filename, delay);
184 }
185 else if (event == "move")
186 {
187 currentInfo->addSound(ItemSoundEvent::MOVE, filename, delay);
188 }
189 else if (event == "sit")
190 {
191 currentInfo->addSound(ItemSoundEvent::SIT, filename, delay);
192 }
193 else if (event == "sittop")
194 {
195 currentInfo->addSound(ItemSoundEvent::SITTOP, filename, delay);
196 }
197 else if (event == "spawn")
198 {
199 currentInfo->addSound(ItemSoundEvent::SPAWN, filename, delay);
200 }
201 else
202 {
203 logger->log((dbName + ": Warning, sound effect %s for "
204 "unknown event %s of monster %s").c_str(),
205 filename, event.c_str(),
206 currentInfo->getName().c_str());
207 }
208 return true;
209 }
210 else if (xmlNameEqual(spriteNode, "attack"))
211 {
212 const int attackId = XML::getProperty(spriteNode, "id", 0);
213 const int effectId = XML::getProperty(spriteNode, "effect-id",
214 paths.getIntValue("effectId"));
215 const int hitEffectId = XML::getProperty(spriteNode, "hit-effect-id",
216 paths.getIntValue("hitEffectId"));
217 const int criticalHitEffectId = XML::getProperty(spriteNode,
218 "critical-hit-effect-id",
219 paths.getIntValue("criticalHitEffectId"));
220 const int missEffectId = XML::getProperty(spriteNode, "miss-effect-id",
221 paths.getIntValue("missEffectId"));
222
223 const std::string spriteAction = XML::getProperty(spriteNode, "action",
224 "attack");
225 const std::string skySpriteAction = XML::getProperty(spriteNode,
226 "skyaction", "skyattack");
227 const std::string waterSpriteAction = XML::getProperty(spriteNode,
228 "wateraction", "waterattack");
229 const std::string rideSpriteAction = XML::getProperty(spriteNode,
230 "rideaction", "rideattack");
231
232 const std::string missileParticle = XML::getProperty(spriteNode,
233 "missile-particle", "");
234
235 const float missileZ = XML::getFloatProperty(
236 spriteNode, "missile-z", 32.0F);
237 const int missileLifeTime = XML::getProperty(
238 spriteNode, "missile-lifetime", 500);
239 const float missileSpeed = XML::getFloatProperty(
240 spriteNode, "missile-speed", 7.0F);
241 const float missileDieDistance = XML::getFloatProperty(
242 spriteNode, "missile-diedistance", 8.0F);
243
244 currentInfo->addAttack(attackId,
245 spriteAction,
246 skySpriteAction,
247 waterSpriteAction,
248 rideSpriteAction,
249 effectId,
250 hitEffectId,
251 criticalHitEffectId,
252 missEffectId,
253 missileParticle,
254 missileZ,
255 missileSpeed,
256 missileDieDistance,
257 missileLifeTime);
258 return true;
259 }
260 else if (xmlNameEqual(spriteNode, "particlefx"))
261 {
262 if (!XmlHaveChildContent(spriteNode))
263 return true;
264
265 display.particles.push_back(XmlChildContent(spriteNode));
266 return true;
267 }
268 return false;
269 }
270