GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
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 "being/being.h" |
||
25 |
|||
26 |
#include "actormanager.h" |
||
27 |
#include "beingequipbackend.h" |
||
28 |
#include "configuration.h" |
||
29 |
#include "effectmanager.h" |
||
30 |
#include "guild.h" |
||
31 |
#include "itemcolormanager.h" |
||
32 |
#include "party.h" |
||
33 |
#include "settings.h" |
||
34 |
#include "soundmanager.h" |
||
35 |
#include "text.h" |
||
36 |
|||
37 |
#include "being/beingcacheentry.h" |
||
38 |
#include "being/beingflag.h" |
||
39 |
#include "being/beingspeech.h" |
||
40 |
#include "being/castingeffect.h" |
||
41 |
#include "being/localplayer.h" |
||
42 |
#include "being/playerinfo.h" |
||
43 |
#include "being/playerrelations.h" |
||
44 |
#include "being/homunculusinfo.h" |
||
45 |
#include "being/mercenaryinfo.h" |
||
46 |
|||
47 |
#include "const/utils/timer.h" |
||
48 |
|||
49 |
#include "const/resources/spriteaction.h" |
||
50 |
|||
51 |
#include "enums/being/beingdirection.h" |
||
52 |
|||
53 |
#include "enums/resources/map/blockmask.h" |
||
54 |
|||
55 |
#include "fs/files.h" |
||
56 |
|||
57 |
#include "gui/gui.h" |
||
58 |
#include "gui/userpalette.h" |
||
59 |
|||
60 |
#include "gui/fonts/font.h" |
||
61 |
|||
62 |
#include "gui/popups/speechbubble.h" |
||
63 |
|||
64 |
#include "gui/windows/chatwindow.h" |
||
65 |
#include "gui/windows/equipmentwindow.h" |
||
66 |
#include "gui/windows/skilldialog.h" |
||
67 |
#include "gui/windows/socialwindow.h" |
||
68 |
|||
69 |
#include "net/charserverhandler.h" |
||
70 |
#include "net/gamehandler.h" |
||
71 |
#include "net/homunculushandler.h" |
||
72 |
#include "net/mercenaryhandler.h" |
||
73 |
#include "net/net.h" |
||
74 |
#include "net/npchandler.h" |
||
75 |
#include "net/packetlimiter.h" |
||
76 |
#include "net/playerhandler.h" |
||
77 |
#include "net/serverfeatures.h" |
||
78 |
|||
79 |
#include "particle/particleinfo.h" |
||
80 |
|||
81 |
#include "resources/attack.h" |
||
82 |
#include "resources/chatobject.h" |
||
83 |
#include "resources/emoteinfo.h" |
||
84 |
#include "resources/emotesprite.h" |
||
85 |
#include "resources/horseinfo.h" |
||
86 |
#include "resources/iteminfo.h" |
||
87 |
|||
88 |
#include "resources/db/avatardb.h" |
||
89 |
#include "resources/db/badgesdb.h" |
||
90 |
#include "resources/db/groupdb.h" |
||
91 |
#include "resources/db/elementaldb.h" |
||
92 |
#include "resources/db/emotedb.h" |
||
93 |
#include "resources/db/homunculusdb.h" |
||
94 |
#include "resources/db/horsedb.h" |
||
95 |
#include "resources/db/languagedb.h" |
||
96 |
#include "resources/db/mercenarydb.h" |
||
97 |
#include "resources/db/monsterdb.h" |
||
98 |
#include "resources/db/npcdb.h" |
||
99 |
#include "resources/db/petdb.h" |
||
100 |
#include "resources/db/skillunitdb.h" |
||
101 |
|||
102 |
#include "resources/image/image.h" |
||
103 |
|||
104 |
#include "resources/item/item.h" |
||
105 |
|||
106 |
#include "resources/map/map.h" |
||
107 |
|||
108 |
#include "resources/skill/skilldata.h" |
||
109 |
#include "resources/skill/skillinfo.h" |
||
110 |
|||
111 |
#include "resources/sprite/animatedsprite.h" |
||
112 |
|||
113 |
#include "gui/widgets/createwidget.h" |
||
114 |
|||
115 |
#include "utils/checkutils.h" |
||
116 |
#include "utils/delete2.h" |
||
117 |
#include "utils/foreach.h" |
||
118 |
#include "utils/gettext.h" |
||
119 |
#include "utils/likely.h" |
||
120 |
#include "utils/stdmove.h" |
||
121 |
#include "utils/timer.h" |
||
122 |
|||
123 |
#include "debug.h" |
||
124 |
|||
125 |
const unsigned int CACHE_SIZE = 50; |
||
126 |
|||
127 |
time_t Being::mUpdateConfigTime = 0; |
||
128 |
unsigned int Being::mConfLineLim = 0; |
||
129 |
int Being::mSpeechType = 0; |
||
130 |
bool Being::mHighlightMapPortals = false; |
||
131 |
bool Being::mHighlightMonsterAttackRange = false; |
||
132 |
bool Being::mLowTraffic = true; |
||
133 |
bool Being::mDrawHotKeys = true; |
||
134 |
bool Being::mShowBattleEvents = false; |
||
135 |
bool Being::mShowMobHP = false; |
||
136 |
bool Being::mShowOwnHP = false; |
||
137 |
bool Being::mShowGender = false; |
||
138 |
bool Being::mShowLevel = false; |
||
139 |
bool Being::mShowPlayersStatus = false; |
||
140 |
bool Being::mEnableReorderSprites = true; |
||
141 |
bool Being::mHideErased = false; |
||
142 |
Move Being::mMoveNames = Move_false; |
||
143 |
bool Being::mUseDiagonal = true; |
||
144 |
BadgeDrawType::Type Being::mShowBadges = BadgeDrawType::Top; |
||
145 |
int Being::mAwayEffect = -1; |
||
146 |
VisibleNamePos::Type Being::mVisibleNamePos = VisibleNamePos::Bottom; |
||
147 |
|||
148 |
1 |
std::list<BeingCacheEntry*> beingInfoCache; |
|
149 |
typedef std::map<int, Guild*>::const_iterator GuildsMapCIter; |
||
150 |
typedef std::map<int, int>::const_iterator IntMapCIter; |
||
151 |
|||
152 |
static const unsigned int SPEECH_TIME = 500; |
||
153 |
static const unsigned int SPEECH_MIN_TIME = 200; |
||
154 |
static const unsigned int SPEECH_MAX_TIME = 800; |
||
155 |
|||
156 |
#define for_each_badges() \ |
||
157 |
for (int f = 0; f < BadgeIndex::BadgeIndexSize; f++) |
||
158 |
|||
159 |
#define for_each_horses(name) \ |
||
160 |
FOR_EACH (STD_VECTOR<AnimatedSprite*>::const_iterator, it, name) |
||
161 |
|||
162 |
103 |
Being::Being(const BeingId id, |
|
163 |
103 |
const ActorTypeT type) : |
|
164 |
ActorSprite(id), |
||
165 |
mNextSound(), |
||
166 |
mInfo(BeingInfo::unknown), |
||
167 |
mEmotionSprite(nullptr), |
||
168 |
mAnimationEffect(nullptr), |
||
169 |
mCastingEffect(nullptr), |
||
170 |
mBadges(), |
||
171 |
mSpriteAction(SpriteAction::STAND), |
||
172 |
mName(), |
||
173 |
mExtName(), |
||
174 |
mRaceName(), |
||
175 |
mPartyName(), |
||
176 |
mGuildName(), |
||
177 |
mClanName(), |
||
178 |
mSpeech(), |
||
179 |
mDispName(nullptr), |
||
180 |
mNameColor(nullptr), |
||
181 |
mEquippedWeapon(nullptr), |
||
182 |
mPath(), |
||
183 |
mText(nullptr), |
||
184 |
mTextColor(nullptr), |
||
185 |
mDest(), |
||
186 |
mSlots(), |
||
187 |
mSpriteParticles(), |
||
188 |
mGuilds(), |
||
189 |
mParty(nullptr), |
||
190 |
mActionTime(0), |
||
191 |
mEmotionTime(0), |
||
192 |
mSpeechTime(0), |
||
193 |
mAttackSpeed(350), |
||
194 |
mLevel(0), |
||
195 |
mGroupId(0), |
||
196 |
mAttackRange(1), |
||
197 |
mLastAttackX(0), |
||
198 |
mLastAttackY(0), |
||
199 |
mPreStandTime(0), |
||
200 |
mGender(Gender::UNSPECIFIED), |
||
201 |
mAction(BeingAction::STAND), |
||
202 |
mSubType(fromInt(0xFFFF, BeingTypeId)), |
||
203 |
mDirection(BeingDirection::DOWN), |
||
204 |
mDirectionDelayed(0), |
||
205 |
mSpriteDirection(SpriteDirection::DOWN), |
||
206 |
mShowName(false), |
||
207 |
mIsGM(false), |
||
208 |
mType(type), |
||
209 |
mSpeechBubble(nullptr), |
||
210 |
✓✓✓✗ |
105 |
mWalkSpeed(playerHandler != nullptr ? |
211 |
2 |
playerHandler->getDefaultWalkSpeed() : 1), |
|
212 |
✓✓✓✗ |
105 |
mSpeed(playerHandler != nullptr ? |
213 |
2 |
playerHandler->getDefaultWalkSpeed() : 1), |
|
214 |
mIp(), |
||
215 |
✓✗ | 103 |
mSpriteRemap(new int[20]), |
216 |
✓✗ | 103 |
mSpriteHide(new int[20]), |
217 |
✓✗ | 103 |
mSpriteDraw(new int[20]), |
218 |
mComment(), |
||
219 |
mBuyBoard(), |
||
220 |
mSellBoard(), |
||
221 |
mOwner(nullptr), |
||
222 |
mSpecialParticle(nullptr), |
||
223 |
mChat(nullptr), |
||
224 |
mHorseInfo(nullptr), |
||
225 |
mDownHorseSprites(), |
||
226 |
mUpHorseSprites(), |
||
227 |
mSpiritParticles(), |
||
228 |
mX(0), |
||
229 |
mY(0), |
||
230 |
mCachedX(0), |
||
231 |
mCachedY(0), |
||
232 |
mSortOffsetY(0), |
||
233 |
mPixelOffsetY(0), |
||
234 |
mFixedOffsetY(0), |
||
235 |
mOldHeight(0), |
||
236 |
mDamageTaken(0), |
||
237 |
mHP(0), |
||
238 |
mMaxHP(0), |
||
239 |
mDistance(0), |
||
240 |
mReachable(Reachable::REACH_UNKNOWN), |
||
241 |
mGoodStatus(-1), |
||
242 |
mMoveTime(0), |
||
243 |
mAttackTime(0), |
||
244 |
mTalkTime(0), |
||
245 |
mOtherTime(0), |
||
246 |
mTestTime(cur_time), |
||
247 |
mAttackDelay(0), |
||
248 |
mMinHit(0), |
||
249 |
mMaxHit(0), |
||
250 |
mCriticalHit(0), |
||
251 |
mPvpRank(0), |
||
252 |
mNumber(100), |
||
253 |
mSpiritBalls(0U), |
||
254 |
mUsageCounter(1), |
||
255 |
mKarma(0), |
||
256 |
mManner(0), |
||
257 |
mAreaSize(11), |
||
258 |
mCastEndTime(0), |
||
259 |
mLanguageId(-1), |
||
260 |
mBadgesX(0), |
||
261 |
mBadgesY(0), |
||
262 |
mCreatorId(BeingId_zero), |
||
263 |
mTeamId(0U), |
||
264 |
mLook(0U), |
||
265 |
mBadgesCount(0U), |
||
266 |
mHairColor(ItemColor_zero), |
||
267 |
mErased(false), |
||
268 |
mEnemy(false), |
||
269 |
mGotComment(false), |
||
270 |
mAdvanced(false), |
||
271 |
mShop(false), |
||
272 |
mAway(false), |
||
273 |
mInactive(false), |
||
274 |
mNeedPosUpdate(true), |
||
275 |
mBotAi(true), |
||
276 |
✓✓ | 2884 |
mAllowNpcEquipment(false) |
277 |
{ |
||
278 |
✓✓ | 2163 |
for (int f = 0; f < 20; f ++) |
279 |
{ |
||
280 |
2060 |
mSpriteRemap[f] = f; |
|
281 |
2060 |
mSpriteHide[f] = 0; |
|
282 |
2060 |
mSpriteDraw[f] = 0; |
|
283 |
} |
||
284 |
|||
285 |
✓✓ | 2163 |
for_each_badges() |
286 |
1030 |
mBadges[f] = nullptr; |
|
287 |
103 |
} |
|
288 |
|||
289 |
103 |
void Being::postInit(const BeingTypeId subtype, |
|
290 |
Map *const map) |
||
291 |
{ |
||
292 |
103 |
setMap(map); |
|
293 |
103 |
setSubtype(subtype, 0); |
|
294 |
|||
295 |
103 |
VisibleName::Type showName1 = VisibleName::Hide; |
|
296 |
|||
297 |
✓✗✓✓ |
103 |
switch (mType) |
298 |
{ |
||
299 |
case ActorType::Player: |
||
300 |
case ActorType::Mercenary: |
||
301 |
case ActorType::Pet: |
||
302 |
case ActorType::Homunculus: |
||
303 |
case ActorType::Elemental: |
||
304 |
101 |
showName1 = static_cast<VisibleName::Type>( |
|
305 |
✓✗ | 404 |
config.getIntValue("visiblenames")); |
306 |
101 |
break; |
|
307 |
case ActorType::Portal: |
||
308 |
case ActorType::SkillUnit: |
||
309 |
showName1 = VisibleName::Hide; |
||
310 |
break; |
||
311 |
default: |
||
312 |
case ActorType::Unknown: |
||
313 |
case ActorType::Npc: |
||
314 |
case ActorType::Monster: |
||
315 |
case ActorType::FloorItem: |
||
316 |
case ActorType::Avatar: |
||
317 |
break; |
||
318 |
} |
||
319 |
|||
320 |
✓✗ | 103 |
if (mType != ActorType::Npc) |
321 |
103 |
mGotComment = true; |
|
322 |
|||
323 |
✓✗ | 412 |
config.addListener("visiblenames", this); |
324 |
|||
325 |
103 |
reReadConfig(); |
|
326 |
|||
327 |
✓✗✓✓ |
103 |
if (mType == ActorType::Npc || |
328 |
showName1 == VisibleName::Show) |
||
329 |
{ |
||
330 |
101 |
setShowName(true); |
|
331 |
} |
||
332 |
|||
333 |
103 |
updateColors(); |
|
334 |
103 |
updatePercentHP(); |
|
335 |
103 |
} |
|
336 |
|||
337 |
2172 |
Being::~Being() |
|
338 |
{ |
||
339 |
412 |
config.removeListener("visiblenames", this); |
|
340 |
CHECKLISTENERS |
||
341 |
|||
342 |
✓✗ | 103 |
delete [] mSpriteRemap; |
343 |
103 |
mSpriteRemap = nullptr; |
|
344 |
✓✗ | 103 |
delete [] mSpriteHide; |
345 |
103 |
mSpriteHide = nullptr; |
|
346 |
✓✗ | 103 |
delete [] mSpriteDraw; |
347 |
103 |
mSpriteDraw = nullptr; |
|
348 |
|||
349 |
✓✓ | 1133 |
for_each_badges() |
350 |
✗✓ | 1030 |
delete2(mBadges[f]) |
351 |
|||
352 |
✗✓ | 206 |
delete2(mSpeechBubble) |
353 |
✓✓ | 206 |
delete2(mDispName) |
354 |
✗✓ | 103 |
delete2(mText) |
355 |
✗✓ | 103 |
delete2(mEmotionSprite) |
356 |
✗✓ | 103 |
delete2(mAnimationEffect) |
357 |
✗✓ | 103 |
delete2(mCastingEffect) |
358 |
103 |
mBadgesCount = 0; |
|
359 |
✗✓ | 103 |
delete2(mChat) |
360 |
103 |
removeHorse(); |
|
361 |
|||
362 |
103 |
removeAllItemsParticles(); |
|
363 |
206 |
mSpiritParticles.clear(); |
|
364 |
112 |
} |
|
365 |
|||
366 |
void Being::createSpeechBubble() restrict2 |
||
367 |
{ |
||
368 |
CREATEWIDGETV0(mSpeechBubble, SpeechBubble); |
||
369 |
} |
||
370 |
|||
371 |
103 |
void Being::setSubtype(const BeingTypeId subtype, |
|
372 |
const uint16_t look) restrict2 |
||
373 |
{ |
||
374 |
✗✓ | 103 |
if (mInfo == nullptr) |
375 |
return; |
||
376 |
|||
377 |
if (subtype == mSubType && mLook == look) |
||
378 |
return; |
||
379 |
|||
380 |
mSubType = subtype; |
||
381 |
mLook = look; |
||
382 |
|||
383 |
switch (mType) |
||
384 |
{ |
||
385 |
case ActorType::Monster: |
||
386 |
mInfo = MonsterDB::get(mSubType); |
||
387 |
if (mInfo != nullptr) |
||
388 |
{ |
||
389 |
setName(mInfo->getName()); |
||
390 |
setupSpriteDisplay(mInfo->getDisplay(), |
||
391 |
ForceDisplay_true, |
||
392 |
DisplayType::Item, |
||
393 |
mInfo->getColor(fromInt(mLook, ItemColor))); |
||
394 |
mYDiff = mInfo->getSortOffsetY(); |
||
395 |
} |
||
396 |
break; |
||
397 |
case ActorType::Pet: |
||
398 |
mInfo = PETDB::get(mSubType); |
||
399 |
if (mInfo != nullptr) |
||
400 |
{ |
||
401 |
setName(mInfo->getName()); |
||
402 |
setupSpriteDisplay(mInfo->getDisplay(), |
||
403 |
ForceDisplay_true, |
||
404 |
DisplayType::Item, |
||
405 |
mInfo->getColor(fromInt(mLook, ItemColor))); |
||
406 |
mYDiff = mInfo->getSortOffsetY(); |
||
407 |
} |
||
408 |
break; |
||
409 |
case ActorType::Mercenary: |
||
410 |
mInfo = MercenaryDB::get(mSubType); |
||
411 |
if (mInfo != nullptr) |
||
412 |
{ |
||
413 |
setName(mInfo->getName()); |
||
414 |
setupSpriteDisplay(mInfo->getDisplay(), |
||
415 |
ForceDisplay_true, |
||
416 |
DisplayType::Item, |
||
417 |
mInfo->getColor(fromInt(mLook, ItemColor))); |
||
418 |
mYDiff = mInfo->getSortOffsetY(); |
||
419 |
} |
||
420 |
break; |
||
421 |
case ActorType::Homunculus: |
||
422 |
mInfo = HomunculusDB::get(mSubType); |
||
423 |
if (mInfo != nullptr) |
||
424 |
{ |
||
425 |
setName(mInfo->getName()); |
||
426 |
setupSpriteDisplay(mInfo->getDisplay(), |
||
427 |
ForceDisplay_true, |
||
428 |
DisplayType::Item, |
||
429 |
mInfo->getColor(fromInt(mLook, ItemColor))); |
||
430 |
mYDiff = mInfo->getSortOffsetY(); |
||
431 |
} |
||
432 |
break; |
||
433 |
case ActorType::SkillUnit: |
||
434 |
mInfo = SkillUnitDb::get(mSubType); |
||
435 |
if (mInfo != nullptr) |
||
436 |
{ |
||
437 |
setName(mInfo->getName()); |
||
438 |
setupSpriteDisplay(mInfo->getDisplay(), |
||
439 |
ForceDisplay_false, |
||
440 |
DisplayType::Item, |
||
441 |
mInfo->getColor(fromInt(mLook, ItemColor))); |
||
442 |
mYDiff = mInfo->getSortOffsetY(); |
||
443 |
} |
||
444 |
break; |
||
445 |
case ActorType::Elemental: |
||
446 |
mInfo = ElementalDb::get(mSubType); |
||
447 |
if (mInfo != nullptr) |
||
448 |
{ |
||
449 |
setName(mInfo->getName()); |
||
450 |
setupSpriteDisplay(mInfo->getDisplay(), |
||
451 |
ForceDisplay_false, |
||
452 |
DisplayType::Item, |
||
453 |
mInfo->getColor(fromInt(mLook, ItemColor))); |
||
454 |
mYDiff = mInfo->getSortOffsetY(); |
||
455 |
} |
||
456 |
break; |
||
457 |
case ActorType::Npc: |
||
458 |
mInfo = NPCDB::get(mSubType); |
||
459 |
if (mInfo != nullptr) |
||
460 |
{ |
||
461 |
setupSpriteDisplay(mInfo->getDisplay(), |
||
462 |
ForceDisplay_false, |
||
463 |
DisplayType::Item, |
||
464 |
std::string()); |
||
465 |
mYDiff = mInfo->getSortOffsetY(); |
||
466 |
mAllowNpcEquipment = mInfo->getAllowEquipment(); |
||
467 |
} |
||
468 |
break; |
||
469 |
case ActorType::Avatar: |
||
470 |
mInfo = AvatarDB::get(mSubType); |
||
471 |
if (mInfo != nullptr) |
||
472 |
{ |
||
473 |
setupSpriteDisplay(mInfo->getDisplay(), |
||
474 |
ForceDisplay_false, |
||
475 |
DisplayType::Item, |
||
476 |
std::string()); |
||
477 |
} |
||
478 |
break; |
||
479 |
case ActorType::Player: |
||
480 |
{ |
||
481 |
int id = -100 - toInt(subtype, int); |
||
482 |
// Prevent showing errors when sprite doesn't exist |
||
483 |
if (!ItemDB::exists(id)) |
||
484 |
{ |
||
485 |
id = -100; |
||
486 |
// TRANSLATORS: default race name |
||
487 |
setRaceName(_("Human")); |
||
488 |
if (charServerHandler != nullptr) |
||
489 |
{ |
||
490 |
setSpriteId(charServerHandler->baseSprite(), |
||
491 |
id); |
||
492 |
} |
||
493 |
} |
||
494 |
else |
||
495 |
{ |
||
496 |
const ItemInfo &restrict info = ItemDB::get(id); |
||
497 |
setRaceName(info.getName()); |
||
498 |
if (charServerHandler != nullptr) |
||
499 |
{ |
||
500 |
setSpriteColor(charServerHandler->baseSprite(), |
||
501 |
id, |
||
502 |
info.getColor(fromInt(mLook, ItemColor))); |
||
503 |
} |
||
504 |
} |
||
505 |
break; |
||
506 |
} |
||
507 |
case ActorType::Portal: |
||
508 |
break; |
||
509 |
case ActorType::Unknown: |
||
510 |
case ActorType::FloorItem: |
||
511 |
default: |
||
512 |
reportAlways("Wrong being type %d in setSubType", |
||
513 |
CAST_S32(mType)) |
||
514 |
break; |
||
515 |
} |
||
516 |
} |
||
517 |
|||
518 |
TargetCursorSizeT Being::getTargetCursorSize() const restrict2 |
||
519 |
{ |
||
520 |
if (mInfo == nullptr) |
||
521 |
return TargetCursorSize::SMALL; |
||
522 |
|||
523 |
return mInfo->getTargetCursorSize(); |
||
524 |
} |
||
525 |
|||
526 |
void Being::setPixelPositionF(const Vector &restrict pos) restrict2 |
||
527 |
{ |
||
528 |
Actor::setPixelPositionF(pos); |
||
529 |
|||
530 |
updateCoords(); |
||
531 |
|||
532 |
if (mText != nullptr) |
||
533 |
{ |
||
534 |
mText->adviseXY(CAST_S32(pos.x), |
||
535 |
CAST_S32(pos.y) - getHeight() - mText->getHeight() - 9, |
||
536 |
mMoveNames); |
||
537 |
} |
||
538 |
} |
||
539 |
|||
540 |
void Being::setDestination(const int dstX, |
||
541 |
const int dstY) restrict2 |
||
542 |
{ |
||
543 |
if (mMap == nullptr) |
||
544 |
return; |
||
545 |
|||
546 |
setPath(mMap->findPath(mX, |
||
547 |
mY, |
||
548 |
dstX, |
||
549 |
dstY, |
||
550 |
getBlockWalkMask(), |
||
551 |
20)); |
||
552 |
} |
||
553 |
|||
554 |
void Being::clearPath() restrict2 |
||
555 |
{ |
||
556 |
mPath.clear(); |
||
557 |
} |
||
558 |
|||
559 |
void Being::setPath(const Path &restrict path) restrict2 |
||
560 |
{ |
||
561 |
mPath = path; |
||
562 |
if (mPath.empty()) |
||
563 |
return; |
||
564 |
|||
565 |
if (mAction != BeingAction::MOVE && mAction != BeingAction::DEAD) |
||
566 |
{ |
||
567 |
nextTile(); |
||
568 |
mActionTime = tick_time; |
||
569 |
} |
||
570 |
} |
||
571 |
|||
572 |
void Being::setSpeech(const std::string &restrict text) restrict2 |
||
573 |
{ |
||
574 |
if (userPalette == nullptr) |
||
575 |
return; |
||
576 |
|||
577 |
// Remove colors |
||
578 |
mSpeech = removeColors(text); |
||
579 |
|||
580 |
// Trim whitespace |
||
581 |
trim(mSpeech); |
||
582 |
|||
583 |
const unsigned int lineLim = mConfLineLim; |
||
584 |
if (lineLim > 0 && mSpeech.length() > lineLim) |
||
585 |
mSpeech = mSpeech.substr(0, lineLim); |
||
586 |
|||
587 |
trim(mSpeech); |
||
588 |
if (mSpeech.empty()) |
||
589 |
return; |
||
590 |
|||
591 |
const size_t sz = mSpeech.size(); |
||
592 |
int time = 0; |
||
593 |
if (sz < 200) |
||
594 |
time = CAST_S32(SPEECH_TIME - 300 + (3 * sz)); |
||
595 |
|||
596 |
if (time < CAST_S32(SPEECH_MIN_TIME)) |
||
597 |
time = CAST_S32(SPEECH_MIN_TIME); |
||
598 |
|||
599 |
// Check for links |
||
600 |
size_t start = mSpeech.find('['); |
||
601 |
size_t e = mSpeech.find(']', start); |
||
602 |
|||
603 |
while (start != std::string::npos && e != std::string::npos) |
||
604 |
{ |
||
605 |
// Catch multiple embeds and ignore them so it doesn't crash the client. |
||
606 |
while ((mSpeech.find('[', start + 1) != std::string::npos) && |
||
607 |
(mSpeech.find('[', start + 1) < e)) |
||
608 |
{ |
||
609 |
start = mSpeech.find('[', start + 1); |
||
610 |
} |
||
611 |
|||
612 |
size_t position = mSpeech.find('|'); |
||
613 |
if (mSpeech[start + 1] == '@' && mSpeech[start + 2] == '@') |
||
614 |
{ |
||
615 |
mSpeech.erase(e, 1); |
||
616 |
mSpeech.erase(start, (position - start) + 1); |
||
617 |
} |
||
618 |
position = mSpeech.find("@@"); |
||
619 |
|||
620 |
while (position != std::string::npos) |
||
621 |
{ |
||
622 |
mSpeech.erase(position, 2); |
||
623 |
position = mSpeech.find('@'); |
||
624 |
} |
||
625 |
|||
626 |
start = mSpeech.find('[', start + 1); |
||
627 |
e = mSpeech.find(']', start); |
||
628 |
} |
||
629 |
|||
630 |
if (!mSpeech.empty()) |
||
631 |
{ |
||
632 |
mSpeechTime = time <= CAST_S32(SPEECH_MAX_TIME) |
||
633 |
? time : CAST_S32(SPEECH_MAX_TIME); |
||
634 |
} |
||
635 |
|||
636 |
const int speech = mSpeechType; |
||
637 |
if (speech == BeingSpeech::TEXT_OVERHEAD) |
||
638 |
{ |
||
639 |
delete mText; |
||
640 |
mText = nullptr; |
||
641 |
mText = new Text(mSpeech, |
||
642 |
mPixelX, |
||
643 |
mPixelY - getHeight(), |
||
644 |
Graphics::CENTER, |
||
645 |
&userPalette->getColor(UserColorId::PARTICLE, 255U), |
||
646 |
Speech_true, |
||
647 |
nullptr); |
||
648 |
mText->adviseXY(mPixelX, |
||
649 |
(mY + 1) * mapTileSize - getHeight() - mText->getHeight() - 9, |
||
650 |
mMoveNames); |
||
651 |
} |
||
652 |
else |
||
653 |
{ |
||
654 |
if (mSpeechBubble == nullptr) |
||
655 |
createSpeechBubble(); |
||
656 |
if (mSpeechBubble != nullptr) |
||
657 |
{ |
||
658 |
const bool isShowName = (speech == BeingSpeech::NAME_IN_BUBBLE); |
||
659 |
mSpeechBubble->setCaption(isShowName ? mName : "", |
||
660 |
&theme->getColor(ThemeColorId::BUBBLE_NAME, 255), |
||
661 |
&theme->getColor(ThemeColorId::BUBBLE_NAME_OUTLINE, 255)); |
||
662 |
mSpeechBubble->setText(mSpeech, isShowName); |
||
663 |
} |
||
664 |
} |
||
665 |
} |
||
666 |
|||
667 |
void Being::takeDamage(Being *restrict const attacker, |
||
668 |
const int amount, |
||
669 |
const AttackTypeT type, |
||
670 |
const int attackId, |
||
671 |
const int level) restrict2 |
||
672 |
{ |
||
673 |
if (userPalette == nullptr || attacker == nullptr) |
||
674 |
return; |
||
675 |
|||
676 |
BLOCK_START("Being::takeDamage1") |
||
677 |
|||
678 |
Font *font = nullptr; |
||
679 |
const Color *color; |
||
680 |
|||
681 |
if (gui != nullptr) |
||
682 |
font = gui->getInfoParticleFont(); |
||
683 |
|||
684 |
// Selecting the right color |
||
685 |
if (type == AttackType::CRITICAL || type == AttackType::FLEE) |
||
686 |
{ |
||
687 |
if (type == AttackType::CRITICAL) |
||
688 |
attacker->setCriticalHit(amount); |
||
689 |
|||
690 |
if (attacker == localPlayer) |
||
691 |
{ |
||
692 |
color = &userPalette->getColor( |
||
693 |
UserColorId::HIT_LOCAL_PLAYER_CRITICAL, |
||
694 |
255U); |
||
695 |
} |
||
696 |
else |
||
697 |
{ |
||
698 |
color = &userPalette->getColor(UserColorId::HIT_CRITICAL, |
||
699 |
255U); |
||
700 |
} |
||
701 |
} |
||
702 |
else if (amount == 0) |
||
703 |
{ |
||
704 |
if (attacker == localPlayer) |
||
705 |
{ |
||
706 |
// This is intended to be the wrong direction to visually |
||
707 |
// differentiate between hits and misses |
||
708 |
color = &userPalette->getColor(UserColorId::HIT_LOCAL_PLAYER_MISS, |
||
709 |
255U); |
||
710 |
} |
||
711 |
else |
||
712 |
{ |
||
713 |
color = &userPalette->getColor(UserColorId::MISS, |
||
714 |
255U); |
||
715 |
} |
||
716 |
} |
||
717 |
else if (mType == ActorType::Monster || |
||
718 |
mType == ActorType::Mercenary || |
||
719 |
mType == ActorType::Pet || |
||
720 |
mType == ActorType::Homunculus || |
||
721 |
mType == ActorType::SkillUnit) |
||
722 |
{ |
||
723 |
if (attacker == localPlayer) |
||
724 |
{ |
||
725 |
color = &userPalette->getColor( |
||
726 |
UserColorId::HIT_LOCAL_PLAYER_MONSTER, |
||
727 |
255U); |
||
728 |
} |
||
729 |
else |
||
730 |
{ |
||
731 |
color = &userPalette->getColor( |
||
732 |
UserColorId::HIT_PLAYER_MONSTER, |
||
733 |
255U); |
||
734 |
} |
||
735 |
} |
||
736 |
else if (mType == ActorType::Player && |
||
737 |
attacker != localPlayer && |
||
738 |
this == localPlayer) |
||
739 |
{ |
||
740 |
// here player was attacked by other player. mark him as enemy. |
||
741 |
color = &userPalette->getColor(UserColorId::HIT_PLAYER_PLAYER, |
||
742 |
255U); |
||
743 |
attacker->setEnemy(true); |
||
744 |
attacker->updateColors(); |
||
745 |
} |
||
746 |
else |
||
747 |
{ |
||
748 |
color = &userPalette->getColor(UserColorId::HIT_MONSTER_PLAYER, |
||
749 |
255U); |
||
750 |
} |
||
751 |
|||
752 |
if (chatWindow != nullptr && mShowBattleEvents) |
||
753 |
{ |
||
754 |
if (this == localPlayer) |
||
755 |
{ |
||
756 |
if (attacker->mType == ActorType::Player || (amount != 0)) |
||
757 |
{ |
||
758 |
ChatWindow::battleChatLog(strprintf("%s : Hit you -%d", |
||
759 |
attacker->getName().c_str(), amount), |
||
760 |
ChatMsgType::BY_OTHER, |
||
761 |
IgnoreRecord_false, |
||
762 |
TryRemoveColors_true); |
||
763 |
} |
||
764 |
} |
||
765 |
else if (attacker == localPlayer && (amount != 0)) |
||
766 |
{ |
||
767 |
ChatWindow::battleChatLog(strprintf("%s : You hit %s -%d", |
||
768 |
attacker->mName.c_str(), |
||
769 |
mName.c_str(), |
||
770 |
amount), |
||
771 |
ChatMsgType::BY_PLAYER, |
||
772 |
IgnoreRecord_false, |
||
773 |
TryRemoveColors_true); |
||
774 |
} |
||
775 |
} |
||
776 |
if (font != nullptr && particleEngine != nullptr) |
||
777 |
{ |
||
778 |
const std::string damage = amount != 0 ? toString(amount) : |
||
779 |
// TRANSLATORS: dodge or miss message in attacks |
||
780 |
type == AttackType::FLEE ? _("dodge") : _("miss"); |
||
781 |
// Show damage number |
||
782 |
particleEngine->addTextSplashEffect(damage, |
||
783 |
mPixelX, |
||
784 |
mPixelY - 16, |
||
785 |
color, |
||
786 |
font, |
||
787 |
true); |
||
788 |
} |
||
789 |
BLOCK_END("Being::takeDamage1") |
||
790 |
BLOCK_START("Being::takeDamage2") |
||
791 |
|||
792 |
if (type != AttackType::SKILL) |
||
793 |
attacker->updateHit(amount); |
||
794 |
|||
795 |
if (amount > 0) |
||
796 |
{ |
||
797 |
if ((localPlayer != nullptr) && localPlayer == this) |
||
798 |
localPlayer->setLastHitFrom(attacker->mName); |
||
799 |
|||
800 |
mDamageTaken += amount; |
||
801 |
if (mInfo != nullptr) |
||
802 |
{ |
||
803 |
playSfx(mInfo->getSound(ItemSoundEvent::HURT), |
||
804 |
this, |
||
805 |
false, |
||
806 |
mX, |
||
807 |
mY); |
||
808 |
|||
809 |
if (!mInfo->isStaticMaxHP()) |
||
810 |
{ |
||
811 |
if ((mHP == 0) && mInfo->getMaxHP() < mDamageTaken) |
||
812 |
mInfo->setMaxHP(mDamageTaken); |
||
813 |
} |
||
814 |
} |
||
815 |
if ((mHP != 0) && isAlive()) |
||
816 |
{ |
||
817 |
mHP -= amount; |
||
818 |
if (mHP < 0) |
||
819 |
mHP = 0; |
||
820 |
} |
||
821 |
|||
822 |
if (mType == ActorType::Monster) |
||
823 |
{ |
||
824 |
updatePercentHP(); |
||
825 |
updateName(); |
||
826 |
} |
||
827 |
else if (mType == ActorType::Player && |
||
828 |
(socialWindow != nullptr) && |
||
829 |
!mName.empty()) |
||
830 |
{ |
||
831 |
socialWindow->updateAvatar(mName); |
||
832 |
} |
||
833 |
|||
834 |
if (effectManager != nullptr) |
||
835 |
{ |
||
836 |
const int hitEffectId = getHitEffect(attacker, |
||
837 |
type, |
||
838 |
attackId, |
||
839 |
level); |
||
840 |
if (hitEffectId >= 0) |
||
841 |
effectManager->trigger(hitEffectId, this, 0); |
||
842 |
} |
||
843 |
} |
||
844 |
else |
||
845 |
{ |
||
846 |
if (effectManager != nullptr) |
||
847 |
{ |
||
848 |
int hitEffectId = -1; |
||
849 |
if (type == AttackType::SKILL) |
||
850 |
{ |
||
851 |
hitEffectId = getHitEffect(attacker, |
||
852 |
AttackType::SKILLMISS, |
||
853 |
attackId, |
||
854 |
level); |
||
855 |
} |
||
856 |
else |
||
857 |
{ |
||
858 |
hitEffectId = getHitEffect(attacker, |
||
859 |
AttackType::MISS, |
||
860 |
attackId, |
||
861 |
level); |
||
862 |
} |
||
863 |
if (hitEffectId >= 0) |
||
864 |
effectManager->trigger(hitEffectId, this, 0); |
||
865 |
} |
||
866 |
} |
||
867 |
BLOCK_END("Being::takeDamage2") |
||
868 |
} |
||
869 |
|||
870 |
int Being::getHitEffect(const Being *restrict const attacker, |
||
871 |
const AttackTypeT type, |
||
872 |
const int attackId, |
||
873 |
const int level) |
||
874 |
{ |
||
875 |
if (effectManager == nullptr) |
||
876 |
return 0; |
||
877 |
|||
878 |
BLOCK_START("Being::getHitEffect") |
||
879 |
// Init the particle effect path based on current |
||
880 |
// weapon or default. |
||
881 |
int hitEffectId = 0; |
||
882 |
if (type == AttackType::SKILL || type == AttackType::SKILLMISS) |
||
883 |
{ |
||
884 |
const SkillData *restrict const data = |
||
885 |
skillDialog->getSkillDataByLevel(attackId, level); |
||
886 |
if (data == nullptr) |
||
887 |
return -1; |
||
888 |
if (type == AttackType::SKILL) |
||
889 |
{ |
||
890 |
hitEffectId = data->hitEffectId; |
||
891 |
if (hitEffectId == -1) |
||
892 |
hitEffectId = paths.getIntValue("skillHitEffectId"); |
||
893 |
} |
||
894 |
else |
||
895 |
{ |
||
896 |
hitEffectId = data->missEffectId; |
||
897 |
if (hitEffectId == -1) |
||
898 |
hitEffectId = paths.getIntValue("skillMissEffectId"); |
||
899 |
} |
||
900 |
} |
||
901 |
else |
||
902 |
{ |
||
903 |
if (attacker != nullptr) |
||
904 |
{ |
||
905 |
const ItemInfo *restrict const attackerWeapon |
||
906 |
= attacker->getEquippedWeapon(); |
||
907 |
if (attackerWeapon != nullptr && |
||
908 |
attacker->getType() == ActorType::Player) |
||
909 |
{ |
||
910 |
if (type == AttackType::MISS) |
||
911 |
hitEffectId = attackerWeapon->getMissEffectId(); |
||
912 |
else if (type != AttackType::CRITICAL) |
||
913 |
hitEffectId = attackerWeapon->getHitEffectId(); |
||
914 |
else |
||
915 |
hitEffectId = attackerWeapon->getCriticalHitEffectId(); |
||
916 |
} |
||
917 |
else if (attacker->getType() == ActorType::Monster) |
||
918 |
{ |
||
919 |
const BeingInfo *restrict const info = attacker->getInfo(); |
||
920 |
if (info != nullptr) |
||
921 |
{ |
||
922 |
const Attack *restrict const atk = |
||
923 |
info->getAttack(attackId); |
||
924 |
if (atk != nullptr) |
||
925 |
{ |
||
926 |
if (type == AttackType::MISS) |
||
927 |
hitEffectId = atk->mMissEffectId; |
||
928 |
else if (type != AttackType::CRITICAL) |
||
929 |
hitEffectId = atk->mHitEffectId; |
||
930 |
else |
||
931 |
hitEffectId = atk->mCriticalHitEffectId; |
||
932 |
} |
||
933 |
else |
||
934 |
{ |
||
935 |
hitEffectId = getDefaultEffectId(type); |
||
936 |
} |
||
937 |
} |
||
938 |
} |
||
939 |
else |
||
940 |
{ |
||
941 |
hitEffectId = getDefaultEffectId(type); |
||
942 |
} |
||
943 |
} |
||
944 |
else |
||
945 |
{ |
||
946 |
hitEffectId = getDefaultEffectId(type); |
||
947 |
} |
||
948 |
} |
||
949 |
BLOCK_END("Being::getHitEffect") |
||
950 |
return hitEffectId; |
||
951 |
} |
||
952 |
|||
953 |
int Being::getDefaultEffectId(const AttackTypeT &restrict type) |
||
954 |
{ |
||
955 |
if (type == AttackType::MISS) |
||
956 |
return paths.getIntValue("missEffectId"); |
||
957 |
else if (type != AttackType::CRITICAL) |
||
958 |
return paths.getIntValue("hitEffectId"); |
||
959 |
else |
||
960 |
return paths.getIntValue("criticalHitEffectId"); |
||
961 |
} |
||
962 |
|||
963 |
void Being::handleAttack(Being *restrict const victim, |
||
964 |
const int damage, |
||
965 |
const int attackId) restrict2 |
||
966 |
{ |
||
967 |
if ((victim == nullptr) || (mInfo == nullptr)) |
||
968 |
return; |
||
969 |
|||
970 |
BLOCK_START("Being::handleAttack") |
||
971 |
|||
972 |
if (this != localPlayer) |
||
973 |
setAction(BeingAction::ATTACK, attackId); |
||
974 |
|||
975 |
mLastAttackX = victim->mX; |
||
976 |
mLastAttackY = victim->mY; |
||
977 |
|||
978 |
if (mType == ActorType::Player && (mEquippedWeapon != nullptr)) |
||
979 |
fireMissile(victim, mEquippedWeapon->getMissileConst()); |
||
980 |
else if (mInfo->getAttack(attackId) != nullptr) |
||
981 |
fireMissile(victim, mInfo->getAttack(attackId)->mMissile); |
||
982 |
|||
983 |
reset(); |
||
984 |
mActionTime = tick_time; |
||
985 |
|||
986 |
if (Net::getNetworkType() == ServerType::TMWATHENA && |
||
987 |
this != localPlayer) |
||
988 |
{ |
||
989 |
const uint8_t dir = calcDirection(victim->mX, |
||
990 |
victim->mY); |
||
991 |
if (dir != 0U) |
||
992 |
setDirection(dir); |
||
993 |
} |
||
994 |
|||
995 |
if ((damage != 0) && victim->mType == ActorType::Player |
||
996 |
&& victim->mAction == BeingAction::SIT) |
||
997 |
{ |
||
998 |
victim->setAction(BeingAction::STAND, 0); |
||
999 |
} |
||
1000 |
|||
1001 |
if (mType == ActorType::Player) |
||
1002 |
{ |
||
1003 |
if (mSlots.size() >= 10) |
||
1004 |
{ |
||
1005 |
// here 10 is weapon slot |
||
1006 |
int weaponId = mSlots[10].spriteId; |
||
1007 |
if (weaponId == 0) |
||
1008 |
weaponId = -100 - toInt(mSubType, int); |
||
1009 |
const ItemInfo &info = ItemDB::get(weaponId); |
||
1010 |
playSfx(info.getSound( |
||
1011 |
(damage > 0) ? ItemSoundEvent::HIT : ItemSoundEvent::MISS), |
||
1012 |
victim, |
||
1013 |
true, |
||
1014 |
mX, mY); |
||
1015 |
} |
||
1016 |
} |
||
1017 |
else |
||
1018 |
{ |
||
1019 |
playSfx(mInfo->getSound((damage > 0) ? |
||
1020 |
ItemSoundEvent::HIT : ItemSoundEvent::MISS), victim, true, mX, mY); |
||
1021 |
} |
||
1022 |
BLOCK_END("Being::handleAttack") |
||
1023 |
} |
||
1024 |
|||
1025 |
void Being::handleSkillCasting(Being *restrict const victim, |
||
1026 |
const int skillId, |
||
1027 |
const int skillLevel) restrict2 |
||
1028 |
{ |
||
1029 |
if ((victim == nullptr) || (mInfo == nullptr) || (skillDialog == nullptr)) |
||
1030 |
return; |
||
1031 |
|||
1032 |
setAction(BeingAction::CAST, skillId); |
||
1033 |
|||
1034 |
const SkillData *restrict const data = skillDialog->getSkillDataByLevel( |
||
1035 |
skillId, |
||
1036 |
skillLevel); |
||
1037 |
|||
1038 |
if (data != nullptr) |
||
1039 |
{ |
||
1040 |
effectManager->triggerDefault(data->castingSrcEffectId, |
||
1041 |
this, |
||
1042 |
paths.getIntValue("skillCastingSrcEffectId")); |
||
1043 |
effectManager->triggerDefault(data->castingDstEffectId, |
||
1044 |
victim, |
||
1045 |
paths.getIntValue("skillCastingDstEffectId")); |
||
1046 |
fireMissile(victim, data->castingMissile); |
||
1047 |
} |
||
1048 |
} |
||
1049 |
|||
1050 |
void Being::handleSkill(Being *restrict const victim, |
||
1051 |
const int damage, |
||
1052 |
const int skillId, |
||
1053 |
const int skillLevel) restrict2 |
||
1054 |
{ |
||
1055 |
if ((victim == nullptr) || (mInfo == nullptr) || (skillDialog == nullptr)) |
||
1056 |
return; |
||
1057 |
|||
1058 |
const SkillInfo *restrict const skill = skillDialog->getSkill(skillId); |
||
1059 |
const SkillData *restrict const data = skill != nullptr |
||
1060 |
? skill->getData1(skillLevel) : nullptr; |
||
1061 |
if (data != nullptr) |
||
1062 |
{ |
||
1063 |
effectManager->triggerDefault(data->srcEffectId, |
||
1064 |
this, |
||
1065 |
paths.getIntValue("skillSrcEffectId")); |
||
1066 |
effectManager->triggerDefault(data->dstEffectId, |
||
1067 |
victim, |
||
1068 |
paths.getIntValue("skillDstEffectId")); |
||
1069 |
fireMissile(victim, data->missile); |
||
1070 |
} |
||
1071 |
|||
1072 |
if (this != localPlayer && (skill != nullptr)) |
||
1073 |
{ |
||
1074 |
const SkillType::SkillType type = skill->type; |
||
1075 |
if ((type & SkillType::Attack) != 0 || |
||
1076 |
(type & SkillType::Ground) != 0) |
||
1077 |
{ |
||
1078 |
setAction(BeingAction::ATTACK, 1); |
||
1079 |
} |
||
1080 |
else |
||
1081 |
{ |
||
1082 |
setAction(BeingAction::STAND, 1); |
||
1083 |
} |
||
1084 |
} |
||
1085 |
|||
1086 |
reset(); |
||
1087 |
mActionTime = tick_time; |
||
1088 |
|||
1089 |
if (Net::getNetworkType() == ServerType::TMWATHENA && |
||
1090 |
this != localPlayer) |
||
1091 |
{ |
||
1092 |
const uint8_t dir = calcDirection(victim->mX, |
||
1093 |
victim->mY); |
||
1094 |
if (dir != 0U) |
||
1095 |
setDirection(dir); |
||
1096 |
} |
||
1097 |
if ((damage != 0) && victim->mType == ActorType::Player |
||
1098 |
&& victim->mAction == BeingAction::SIT) |
||
1099 |
{ |
||
1100 |
victim->setAction(BeingAction::STAND, 0); |
||
1101 |
} |
||
1102 |
if (data != nullptr) |
||
1103 |
{ |
||
1104 |
if (damage > 0) |
||
1105 |
playSfx(data->soundHit, victim, true, mX, mY); |
||
1106 |
else |
||
1107 |
playSfx(data->soundMiss, victim, true, mX, mY); |
||
1108 |
} |
||
1109 |
else |
||
1110 |
{ |
||
1111 |
playSfx(mInfo->getSound((damage > 0) ? |
||
1112 |
ItemSoundEvent::HIT : ItemSoundEvent::MISS), |
||
1113 |
victim, |
||
1114 |
true, |
||
1115 |
mX, mY); |
||
1116 |
} |
||
1117 |
} |
||
1118 |
|||
1119 |
6 |
void Being::showNameBadge(const bool show) restrict2 |
|
1120 |
{ |
||
1121 |
✗✓ | 6 |
delete2(mBadges[BadgeIndex::Name]) |
1122 |
✓✗✓✗ |
12 |
if (show && |
1123 |
✓✗✗✓ |
18 |
!mName.empty() && |
1124 |
6 |
mShowBadges != BadgeDrawType::Hide) |
|
1125 |
{ |
||
1126 |
12 |
const std::string badge = BadgesDB::getNameBadge(mName); |
|
1127 |
✗✓ | 6 |
if (!badge.empty()) |
1128 |
{ |
||
1129 |
mBadges[BadgeIndex::Name] = AnimatedSprite::load( |
||
1130 |
paths.getStringValue("badges") + badge, |
||
1131 |
0); |
||
1132 |
} |
||
1133 |
} |
||
1134 |
6 |
} |
|
1135 |
|||
1136 |
7 |
void Being::setName(const std::string &restrict name) restrict2 |
|
1137 |
{ |
||
1138 |
14 |
mExtName = name; |
|
1139 |
✗✓ | 7 |
if (mType == ActorType::Npc) |
1140 |
{ |
||
1141 |
mName = name.substr(0, name.find('#', 0)); |
||
1142 |
showName(); |
||
1143 |
} |
||
1144 |
✓✓ | 7 |
else if (mType == ActorType::Player) |
1145 |
{ |
||
1146 |
✓✗ | 12 |
if (mName != name) |
1147 |
{ |
||
1148 |
12 |
mName = name; |
|
1149 |
12 |
showNameBadge(!mName.empty()); |
|
1150 |
} |
||
1151 |
✓✗ | 6 |
if (getShowName()) |
1152 |
6 |
showName(); |
|
1153 |
} |
||
1154 |
else |
||
1155 |
{ |
||
1156 |
✗✓ | 1 |
if (mType == ActorType::Portal) |
1157 |
mName = name.substr(0, name.find('#', 0)); |
||
1158 |
else |
||
1159 |
1 |
mName = name; |
|
1160 |
|||
1161 |
✗✓ | 1 |
if (getShowName()) |
1162 |
showName(); |
||
1163 |
} |
||
1164 |
7 |
} |
|
1165 |
|||
1166 |
197 |
void Being::setShowName(const bool doShowName) restrict2 |
|
1167 |
{ |
||
1168 |
✓✓ | 197 |
if (mShowName == doShowName) |
1169 |
return; |
||
1170 |
|||
1171 |
103 |
mShowName = doShowName; |
|
1172 |
|||
1173 |
✓✓ | 103 |
if (doShowName) |
1174 |
102 |
showName(); |
|
1175 |
else |
||
1176 |
✓✗ | 2 |
delete2(mDispName) |
1177 |
} |
||
1178 |
|||
1179 |
void Being::showGuildBadge(const bool show) restrict2 |
||
1180 |
{ |
||
1181 |
delete2(mBadges[BadgeIndex::Guild]) |
||
1182 |
if (show && |
||
1183 |
!mGuildName.empty() && |
||
1184 |
mShowBadges != BadgeDrawType::Hide) |
||
1185 |
{ |
||
1186 |
const std::string badge = BadgesDB::getGuildBadge(mGuildName); |
||
1187 |
if (!badge.empty()) |
||
1188 |
{ |
||
1189 |
mBadges[BadgeIndex::Guild] = AnimatedSprite::load( |
||
1190 |
paths.getStringValue("badges") + badge, |
||
1191 |
0); |
||
1192 |
} |
||
1193 |
} |
||
1194 |
} |
||
1195 |
|||
1196 |
void Being::setGuildName(const std::string &restrict name) restrict2 |
||
1197 |
{ |
||
1198 |
if (mGuildName != name) |
||
1199 |
{ |
||
1200 |
mGuildName = name; |
||
1201 |
showGuildBadge(!mGuildName.empty()); |
||
1202 |
updateBadgesCount(); |
||
1203 |
} |
||
1204 |
} |
||
1205 |
|||
1206 |
void Being::showClanBadge(const bool show) restrict2 |
||
1207 |
{ |
||
1208 |
delete2(mBadges[BadgeIndex::Clan]) |
||
1209 |
if (show && |
||
1210 |
!mClanName.empty() && |
||
1211 |
mShowBadges != BadgeDrawType::Hide) |
||
1212 |
{ |
||
1213 |
const std::string badge = BadgesDB::getClanBadge(mClanName); |
||
1214 |
if (!badge.empty()) |
||
1215 |
{ |
||
1216 |
mBadges[BadgeIndex::Clan] = AnimatedSprite::load( |
||
1217 |
paths.getStringValue("badges") + badge, |
||
1218 |
0); |
||
1219 |
} |
||
1220 |
} |
||
1221 |
} |
||
1222 |
|||
1223 |
void Being::setClanName(const std::string &restrict name) restrict2 |
||
1224 |
{ |
||
1225 |
if (mClanName != name) |
||
1226 |
{ |
||
1227 |
mClanName = name; |
||
1228 |
showClanBadge(!mClanName.empty()); |
||
1229 |
updateBadgesCount(); |
||
1230 |
} |
||
1231 |
} |
||
1232 |
|||
1233 |
void Being::setGuildPos(const std::string &restrict pos A_UNUSED) restrict2 |
||
1234 |
{ |
||
1235 |
} |
||
1236 |
|||
1237 |
void Being::addGuild(Guild *restrict const guild) restrict2 |
||
1238 |
{ |
||
1239 |
if (guild == nullptr) |
||
1240 |
return; |
||
1241 |
|||
1242 |
mGuilds[guild->getId()] = guild; |
||
1243 |
|||
1244 |
if (this == localPlayer && (socialWindow != nullptr)) |
||
1245 |
socialWindow->addTab(guild); |
||
1246 |
} |
||
1247 |
|||
1248 |
void Being::removeGuild(const int id) restrict2 |
||
1249 |
{ |
||
1250 |
if (this == localPlayer && (socialWindow != nullptr)) |
||
1251 |
socialWindow->removeTab(mGuilds[id]); |
||
1252 |
|||
1253 |
if (mGuilds[id] != nullptr) |
||
1254 |
mGuilds[id]->removeMember(mName); |
||
1255 |
mGuilds.erase(id); |
||
1256 |
} |
||
1257 |
|||
1258 |
const Guild *Being::getGuild(const std::string &restrict guildName) const |
||
1259 |
restrict2 |
||
1260 |
{ |
||
1261 |
FOR_EACH (GuildsMapCIter, itr, mGuilds) |
||
1262 |
{ |
||
1263 |
const Guild *restrict const guild = itr->second; |
||
1264 |
if ((guild != nullptr) && guild->getName() == guildName) |
||
1265 |
return guild; |
||
1266 |
} |
||
1267 |
|||
1268 |
return nullptr; |
||
1269 |
} |
||
1270 |
|||
1271 |
const Guild *Being::getGuild(const int id) const restrict2 |
||
1272 |
{ |
||
1273 |
const std::map<int, Guild*>::const_iterator itr = mGuilds.find(id); |
||
1274 |
if (itr != mGuilds.end()) |
||
1275 |
return itr->second; |
||
1276 |
|||
1277 |
return nullptr; |
||
1278 |
} |
||
1279 |
|||
1280 |
1 |
Guild *Being::getGuild() const restrict2 |
|
1281 |
{ |
||
1282 |
6 |
const std::map<int, Guild*>::const_iterator itr = mGuilds.begin(); |
|
1283 |
✗✓✗✗ ✗✗✗✗ ✗✓ |
6 |
if (itr != mGuilds.end()) |
1284 |
return itr->second; |
||
1285 |
|||
1286 |
return nullptr; |
||
1287 |
} |
||
1288 |
|||
1289 |
void Being::clearGuilds() restrict2 |
||
1290 |
{ |
||
1291 |
FOR_EACH (GuildsMapCIter, itr, mGuilds) |
||
1292 |
{ |
||
1293 |
Guild *const guild = itr->second; |
||
1294 |
|||
1295 |
if (guild != nullptr) |
||
1296 |
{ |
||
1297 |
if (this == localPlayer && (socialWindow != nullptr)) |
||
1298 |
socialWindow->removeTab(guild); |
||
1299 |
|||
1300 |
guild->removeMember(mId); |
||
1301 |
} |
||
1302 |
} |
||
1303 |
|||
1304 |
mGuilds.clear(); |
||
1305 |
} |
||
1306 |
|||
1307 |
6 |
void Being::setParty(Party *restrict const party) restrict2 |
|
1308 |
{ |
||
1309 |
✓✗ | 6 |
if (party == mParty) |
1310 |
return; |
||
1311 |
|||
1312 |
6 |
Party *const old = mParty; |
|
1313 |
6 |
mParty = party; |
|
1314 |
|||
1315 |
✓✓ | 6 |
if (old != nullptr) |
1316 |
2 |
old->removeMember(mId); |
|
1317 |
|||
1318 |
✓✗ | 6 |
if (party != nullptr) |
1319 |
6 |
party->addMember(mId, mName); |
|
1320 |
|||
1321 |
6 |
updateColors(); |
|
1322 |
|||
1323 |
✓✓✗✓ |
6 |
if (this == localPlayer && (socialWindow != nullptr)) |
1324 |
{ |
||
1325 |
if (old != nullptr) |
||
1326 |
socialWindow->removeTab(old); |
||
1327 |
|||
1328 |
if (party != nullptr) |
||
1329 |
socialWindow->addTab(party); |
||
1330 |
} |
||
1331 |
} |
||
1332 |
|||
1333 |
void Being::updateGuild() restrict2 |
||
1334 |
{ |
||
1335 |
if (localPlayer == nullptr) |
||
1336 |
return; |
||
1337 |
|||
1338 |
Guild *restrict const guild = localPlayer->getGuild(); |
||
1339 |
if (guild == nullptr) |
||
1340 |
{ |
||
1341 |
clearGuilds(); |
||
1342 |
updateColors(); |
||
1343 |
return; |
||
1344 |
} |
||
1345 |
if (guild->getMember(mName) != nullptr) |
||
1346 |
{ |
||
1347 |
setGuild(guild); |
||
1348 |
if (!guild->getName().empty()) |
||
1349 |
setGuildName(guild->getName()); |
||
1350 |
} |
||
1351 |
updateColors(); |
||
1352 |
} |
||
1353 |
|||
1354 |
void Being::setGuild(Guild *restrict const guild) restrict2 |
||
1355 |
{ |
||
1356 |
Guild *restrict const old = getGuild(); |
||
1357 |
if (guild == old) |
||
1358 |
return; |
||
1359 |
|||
1360 |
clearGuilds(); |
||
1361 |
addGuild(guild); |
||
1362 |
|||
1363 |
if (old != nullptr) |
||
1364 |
old->removeMember(mName); |
||
1365 |
|||
1366 |
updateColors(); |
||
1367 |
|||
1368 |
if (this == localPlayer && (socialWindow != nullptr)) |
||
1369 |
{ |
||
1370 |
if (old != nullptr) |
||
1371 |
socialWindow->removeTab(old); |
||
1372 |
|||
1373 |
if (guild != nullptr) |
||
1374 |
socialWindow->addTab(guild); |
||
1375 |
} |
||
1376 |
} |
||
1377 |
|||
1378 |
void Being::fireMissile(Being *restrict const victim, |
||
1379 |
const MissileInfo &restrict missile) const restrict2 |
||
1380 |
{ |
||
1381 |
BLOCK_START("Being::fireMissile") |
||
1382 |
|||
1383 |
if (victim == nullptr || |
||
1384 |
missile.particle.empty() || |
||
1385 |
particleEngine == nullptr) |
||
1386 |
{ |
||
1387 |
BLOCK_END("Being::fireMissile") |
||
1388 |
return; |
||
1389 |
} |
||
1390 |
|||
1391 |
Particle *restrict const target = particleEngine->createChild(); |
||
1392 |
|||
1393 |
if (target == nullptr) |
||
1394 |
{ |
||
1395 |
BLOCK_END("Being::fireMissile") |
||
1396 |
return; |
||
1397 |
} |
||
1398 |
|||
1399 |
// +++ add z particle position? |
||
1400 |
Particle *restrict const missileParticle = target->addEffect( |
||
1401 |
missile.particle, |
||
1402 |
mPixelX, |
||
1403 |
mPixelY, |
||
1404 |
0); |
||
1405 |
|||
1406 |
target->moveBy(Vector(0.0F, 0.0F, missile.z)); |
||
1407 |
target->setLifetime(missile.lifeTime); |
||
1408 |
victim->controlAutoParticle(target); |
||
1409 |
|||
1410 |
if (missileParticle != nullptr) |
||
1411 |
{ |
||
1412 |
missileParticle->setDestination(target, missile.speed, 0.0F); |
||
1413 |
missileParticle->setDieDistance(missile.dieDistance); |
||
1414 |
missileParticle->setLifetime(missile.lifeTime); |
||
1415 |
} |
||
1416 |
BLOCK_END("Being::fireMissile") |
||
1417 |
} |
||
1418 |
|||
1419 |
std::string Being::getSitAction() const restrict2 |
||
1420 |
{ |
||
1421 |
if (mHorseId != 0) |
||
1422 |
return SpriteAction::SITRIDE; |
||
1423 |
if (mMap != nullptr) |
||
1424 |
{ |
||
1425 |
const unsigned char mask = mMap->getBlockMask(mX, mY); |
||
1426 |
if ((mask & BlockMask::GROUNDTOP) != 0) |
||
1427 |
return SpriteAction::SITTOP; |
||
1428 |
else if ((mask & BlockMask::AIR) != 0) |
||
1429 |
return SpriteAction::SITSKY; |
||
1430 |
else if ((mask & BlockMask::WATER) != 0) |
||
1431 |
return SpriteAction::SITWATER; |
||
1432 |
} |
||
1433 |
return SpriteAction::SIT; |
||
1434 |
} |
||
1435 |
|||
1436 |
|||
1437 |
std::string Being::getMoveAction() const restrict2 |
||
1438 |
{ |
||
1439 |
if (mHorseId != 0) |
||
1440 |
return SpriteAction::RIDE; |
||
1441 |
if (mMap != nullptr) |
||
1442 |
{ |
||
1443 |
const unsigned char mask = mMap->getBlockMask(mX, mY); |
||
1444 |
if ((mask & BlockMask::AIR) != 0) |
||
1445 |
return SpriteAction::FLY; |
||
1446 |
else if ((mask & BlockMask::WATER) != 0) |
||
1447 |
return SpriteAction::SWIM; |
||
1448 |
} |
||
1449 |
return SpriteAction::MOVE; |
||
1450 |
} |
||
1451 |
|||
1452 |
std::string Being::getWeaponAttackAction(const ItemInfo *restrict const weapon) |
||
1453 |
const restrict2 |
||
1454 |
{ |
||
1455 |
if (weapon == nullptr) |
||
1456 |
return getAttackAction(); |
||
1457 |
|||
1458 |
if (mHorseId != 0) |
||
1459 |
return weapon->getRideAttackAction(); |
||
1460 |
if (mMap != nullptr) |
||
1461 |
{ |
||
1462 |
const unsigned char mask = mMap->getBlockMask(mX, mY); |
||
1463 |
if ((mask & BlockMask::AIR) != 0) |
||
1464 |
return weapon->getSkyAttackAction(); |
||
1465 |
else if ((mask & BlockMask::WATER) != 0) |
||
1466 |
return weapon->getWaterAttackAction(); |
||
1467 |
} |
||
1468 |
return weapon->getAttackAction(); |
||
1469 |
} |
||
1470 |
|||
1471 |
std::string Being::getAttackAction(const Attack *restrict const attack1) const |
||
1472 |
restrict2 |
||
1473 |
{ |
||
1474 |
if (attack1 == nullptr) |
||
1475 |
return getAttackAction(); |
||
1476 |
|||
1477 |
if (mHorseId != 0) |
||
1478 |
return attack1->mRideAction; |
||
1479 |
if (mMap != nullptr) |
||
1480 |
{ |
||
1481 |
const unsigned char mask = mMap->getBlockMask(mX, mY); |
||
1482 |
if ((mask & BlockMask::AIR) != 0) |
||
1483 |
return attack1->mSkyAction; |
||
1484 |
else if ((mask & BlockMask::WATER) != 0) |
||
1485 |
return attack1->mWaterAction; |
||
1486 |
} |
||
1487 |
return attack1->mAction; |
||
1488 |
} |
||
1489 |
|||
1490 |
std::string Being::getCastAction(const SkillInfo *restrict const skill) const |
||
1491 |
restrict2 |
||
1492 |
{ |
||
1493 |
if (skill == nullptr) |
||
1494 |
return getCastAction(); |
||
1495 |
|||
1496 |
if (mHorseId != 0) |
||
1497 |
return skill->castingRideAction; |
||
1498 |
if (mMap != nullptr) |
||
1499 |
{ |
||
1500 |
const unsigned char mask = mMap->getBlockMask(mX, mY); |
||
1501 |
if ((mask & BlockMask::AIR) != 0) |
||
1502 |
return skill->castingSkyAction; |
||
1503 |
else if ((mask & BlockMask::WATER) != 0) |
||
1504 |
return skill->castingWaterAction; |
||
1505 |
} |
||
1506 |
return skill->castingAction; |
||
1507 |
} |
||
1508 |
|||
1509 |
#define getSpriteAction(func, action) \ |
||
1510 |
std::string Being::get##func##Action() const restrict2\ |
||
1511 |
{ \ |
||
1512 |
if (mHorseId != 0) \ |
||
1513 |
return SpriteAction::action##RIDE; \ |
||
1514 |
if (mMap) \ |
||
1515 |
{ \ |
||
1516 |
const unsigned char mask = mMap->getBlockMask(mX, mY); \ |
||
1517 |
if (mask & BlockMask::AIR) \ |
||
1518 |
return SpriteAction::action##SKY; \ |
||
1519 |
else if (mask & BlockMask::WATER) \ |
||
1520 |
return SpriteAction::action##WATER; \ |
||
1521 |
} \ |
||
1522 |
return SpriteAction::action; \ |
||
1523 |
} |
||
1524 |
|||
1525 |
getSpriteAction(Attack, ATTACK) |
||
1526 |
getSpriteAction(Cast, CAST) |
||
1527 |
getSpriteAction(Dead, DEAD) |
||
1528 |
getSpriteAction(Spawn, SPAWN) |
||
1529 |
|||
1530 |
std::string Being::getStandAction() const restrict2 |
||
1531 |
{ |
||
1532 |
if (mHorseId != 0) |
||
1533 |
return SpriteAction::STANDRIDE; |
||
1534 |
if (mMap != nullptr) |
||
1535 |
{ |
||
1536 |
const unsigned char mask = mMap->getBlockMask(mX, mY); |
||
1537 |
if (mTrickDead) |
||
1538 |
{ |
||
1539 |
if ((mask & BlockMask::AIR) != 0) |
||
1540 |
return SpriteAction::DEADSKY; |
||
1541 |
else if ((mask & BlockMask::WATER) != 0) |
||
1542 |
return SpriteAction::DEADWATER; |
||
1543 |
else |
||
1544 |
return SpriteAction::DEAD; |
||
1545 |
} |
||
1546 |
if ((mask & BlockMask::AIR) != 0) |
||
1547 |
return SpriteAction::STANDSKY; |
||
1548 |
else if ((mask & BlockMask::WATER) != 0) |
||
1549 |
return SpriteAction::STANDWATER; |
||
1550 |
} |
||
1551 |
return SpriteAction::STAND; |
||
1552 |
} |
||
1553 |
|||
1554 |
void Being::setAction(const BeingActionT &restrict action, |
||
1555 |
const int attackId) restrict2 |
||
1556 |
{ |
||
1557 |
std::string currentAction = SpriteAction::INVALID; |
||
1558 |
|||
1559 |
switch (action) |
||
1560 |
{ |
||
1561 |
case BeingAction::MOVE: |
||
1562 |
if (mInfo != nullptr) |
||
1563 |
{ |
||
1564 |
playSfx(mInfo->getSound( |
||
1565 |
ItemSoundEvent::MOVE), nullptr, true, mX, mY); |
||
1566 |
} |
||
1567 |
currentAction = getMoveAction(); |
||
1568 |
// Note: When adding a run action, |
||
1569 |
// Differentiate walk and run with action name, |
||
1570 |
// while using only the ACTION_MOVE. |
||
1571 |
break; |
||
1572 |
case BeingAction::SIT: |
||
1573 |
currentAction = getSitAction(); |
||
1574 |
if (mInfo != nullptr) |
||
1575 |
{ |
||
1576 |
ItemSoundEvent::Type event; |
||
1577 |
if (currentAction == SpriteAction::SITTOP) |
||
1578 |
event = ItemSoundEvent::SITTOP; |
||
1579 |
else |
||
1580 |
event = ItemSoundEvent::SIT; |
||
1581 |
playSfx(mInfo->getSound(event), nullptr, true, mX, mY); |
||
1582 |
} |
||
1583 |
break; |
||
1584 |
case BeingAction::ATTACK: |
||
1585 |
if (mEquippedWeapon != nullptr) |
||
1586 |
{ |
||
1587 |
currentAction = getWeaponAttackAction(mEquippedWeapon); |
||
1588 |
reset(); |
||
1589 |
} |
||
1590 |
else |
||
1591 |
{ |
||
1592 |
if (mInfo == nullptr || mInfo->getAttack(attackId) == nullptr) |
||
1593 |
break; |
||
1594 |
|||
1595 |
currentAction = getAttackAction(mInfo->getAttack(attackId)); |
||
1596 |
reset(); |
||
1597 |
|||
1598 |
// attack particle effect |
||
1599 |
if (ParticleEngine::enabled && (effectManager != nullptr)) |
||
1600 |
{ |
||
1601 |
const int effectId = mInfo->getAttack(attackId)->mEffectId; |
||
1602 |
if (effectId >= 0) |
||
1603 |
{ |
||
1604 |
effectManager->triggerDirection(effectId, |
||
1605 |
this, |
||
1606 |
mSpriteDirection); |
||
1607 |
} |
||
1608 |
} |
||
1609 |
} |
||
1610 |
break; |
||
1611 |
case BeingAction::CAST: |
||
1612 |
if (skillDialog != nullptr) |
||
1613 |
{ |
||
1614 |
const SkillInfo *restrict const info = |
||
1615 |
skillDialog->getSkill(attackId); |
||
1616 |
currentAction = getCastAction(info); |
||
1617 |
} |
||
1618 |
break; |
||
1619 |
case BeingAction::HURT: |
||
1620 |
if (mInfo != nullptr) |
||
1621 |
{ |
||
1622 |
playSfx(mInfo->getSound(ItemSoundEvent::HURT), |
||
1623 |
this, false, mX, mY); |
||
1624 |
} |
||
1625 |
break; |
||
1626 |
case BeingAction::DEAD: |
||
1627 |
currentAction = getDeadAction(); |
||
1628 |
if (mInfo != nullptr) |
||
1629 |
{ |
||
1630 |
playSfx(mInfo->getSound(ItemSoundEvent::DIE), |
||
1631 |
this, |
||
1632 |
false, |
||
1633 |
mX, mY); |
||
1634 |
if (mType == ActorType::Monster || |
||
1635 |
mType == ActorType::Npc || |
||
1636 |
mType == ActorType::SkillUnit) |
||
1637 |
{ |
||
1638 |
mYDiff = mInfo->getDeadSortOffsetY(); |
||
1639 |
} |
||
1640 |
} |
||
1641 |
break; |
||
1642 |
case BeingAction::STAND: |
||
1643 |
currentAction = getStandAction(); |
||
1644 |
break; |
||
1645 |
case BeingAction::SPAWN: |
||
1646 |
if (mInfo != nullptr) |
||
1647 |
{ |
||
1648 |
playSfx(mInfo->getSound(ItemSoundEvent::SPAWN), |
||
1649 |
nullptr, true, mX, mY); |
||
1650 |
} |
||
1651 |
currentAction = getSpawnAction(); |
||
1652 |
break; |
||
1653 |
case BeingAction::PRESTAND: |
||
1654 |
break; |
||
1655 |
default: |
||
1656 |
logger->log("Being::setAction unknown action: " |
||
1657 |
+ toString(CAST_U32(action))); |
||
1658 |
break; |
||
1659 |
} |
||
1660 |
|||
1661 |
if (currentAction != SpriteAction::INVALID) |
||
1662 |
{ |
||
1663 |
mSpriteAction = currentAction; |
||
1664 |
play(currentAction); |
||
1665 |
if (mEmotionSprite != nullptr) |
||
1666 |
mEmotionSprite->play(currentAction); |
||
1667 |
if (mAnimationEffect != nullptr) |
||
1668 |
mAnimationEffect->play(currentAction); |
||
1669 |
for_each_badges() |
||
1670 |
{ |
||
1671 |
AnimatedSprite *const sprite = mBadges[f]; |
||
1672 |
if (sprite != nullptr) |
||
1673 |
sprite->play(currentAction); |
||
1674 |
} |
||
1675 |
for_each_horses(mDownHorseSprites) |
||
1676 |
(*it)->play(currentAction); |
||
1677 |
for_each_horses(mUpHorseSprites) |
||
1678 |
(*it)->play(currentAction); |
||
1679 |
mAction = action; |
||
1680 |
} |
||
1681 |
|||
1682 |
if (currentAction != SpriteAction::MOVE |
||
1683 |
&& currentAction != SpriteAction::FLY |
||
1684 |
&& currentAction != SpriteAction::SWIM) |
||
1685 |
{ |
||
1686 |
mActionTime = tick_time; |
||
1687 |
} |
||
1688 |
} |
||
1689 |
|||
1690 |
void Being::setDirection(const uint8_t direction) restrict2 |
||
1691 |
{ |
||
1692 |
if (mDirection == direction) |
||
1693 |
return; |
||
1694 |
|||
1695 |
mDirection = direction; |
||
1696 |
|||
1697 |
mDirectionDelayed = 0; |
||
1698 |
|||
1699 |
// if the direction does not change much, keep the common component |
||
1700 |
int mFaceDirection = mDirection & direction; |
||
1701 |
if (mFaceDirection == 0) |
||
1702 |
mFaceDirection = direction; |
||
1703 |
|||
1704 |
SpriteDirection::Type dir; |
||
1705 |
if ((mFaceDirection & BeingDirection::UP) != 0) |
||
1706 |
{ |
||
1707 |
if ((mFaceDirection & BeingDirection::LEFT) != 0) |
||
1708 |
dir = SpriteDirection::UPLEFT; |
||
1709 |
else if ((mFaceDirection & BeingDirection::RIGHT) != 0) |
||
1710 |
dir = SpriteDirection::UPRIGHT; |
||
1711 |
else |
||
1712 |
dir = SpriteDirection::UP; |
||
1713 |
} |
||
1714 |
else if ((mFaceDirection & BeingDirection::DOWN) != 0) |
||
1715 |
{ |
||
1716 |
if ((mFaceDirection & BeingDirection::LEFT) != 0) |
||
1717 |
dir = SpriteDirection::DOWNLEFT; |
||
1718 |
else if ((mFaceDirection & BeingDirection::RIGHT) != 0) |
||
1719 |
dir = SpriteDirection::DOWNRIGHT; |
||
1720 |
else |
||
1721 |
dir = SpriteDirection::DOWN; |
||
1722 |
} |
||
1723 |
else if ((mFaceDirection & BeingDirection::RIGHT) != 0) |
||
1724 |
{ |
||
1725 |
dir = SpriteDirection::RIGHT; |
||
1726 |
} |
||
1727 |
else |
||
1728 |
{ |
||
1729 |
dir = SpriteDirection::LEFT; |
||
1730 |
} |
||
1731 |
mSpriteDirection = dir; |
||
1732 |
|||
1733 |
CompoundSprite::setSpriteDirection(dir); |
||
1734 |
if (mEmotionSprite != nullptr) |
||
1735 |
mEmotionSprite->setSpriteDirection(dir); |
||
1736 |
if (mAnimationEffect != nullptr) |
||
1737 |
mAnimationEffect->setSpriteDirection(dir); |
||
1738 |
|||
1739 |
for_each_badges() |
||
1740 |
{ |
||
1741 |
AnimatedSprite *const sprite = mBadges[f]; |
||
1742 |
if (sprite != nullptr) |
||
1743 |
sprite->setSpriteDirection(dir); |
||
1744 |
} |
||
1745 |
|||
1746 |
for_each_horses(mDownHorseSprites) |
||
1747 |
(*it)->setSpriteDirection(dir); |
||
1748 |
for_each_horses(mUpHorseSprites) |
||
1749 |
(*it)->setSpriteDirection(dir); |
||
1750 |
recalcSpritesOrder(); |
||
1751 |
} |
||
1752 |
|||
1753 |
uint8_t Being::calcDirection() const restrict2 |
||
1754 |
{ |
||
1755 |
uint8_t dir = 0; |
||
1756 |
if (mDest.x > mX) |
||
1757 |
dir |= BeingDirection::RIGHT; |
||
1758 |
else if (mDest.x < mX) |
||
1759 |
dir |= BeingDirection::LEFT; |
||
1760 |
if (mDest.y > mY) |
||
1761 |
dir |= BeingDirection::DOWN; |
||
1762 |
else if (mDest.y < mY) |
||
1763 |
dir |= BeingDirection::UP; |
||
1764 |
return dir; |
||
1765 |
} |
||
1766 |
|||
1767 |
uint8_t Being::calcDirection(const int dstX, |
||
1768 |
const int dstY) const restrict2 |
||
1769 |
{ |
||
1770 |
uint8_t dir = 0; |
||
1771 |
if (dstX > mX) |
||
1772 |
dir |= BeingDirection::RIGHT; |
||
1773 |
else if (dstX < mX) |
||
1774 |
dir |= BeingDirection::LEFT; |
||
1775 |
if (dstY > mY) |
||
1776 |
dir |= BeingDirection::DOWN; |
||
1777 |
else if (dstY < mY) |
||
1778 |
dir |= BeingDirection::UP; |
||
1779 |
return dir; |
||
1780 |
} |
||
1781 |
|||
1782 |
void Being::nextTile() restrict2 |
||
1783 |
{ |
||
1784 |
if (mPath.empty()) |
||
1785 |
{ |
||
1786 |
mAction = BeingAction::PRESTAND; |
||
1787 |
mPreStandTime = tick_time; |
||
1788 |
return; |
||
1789 |
} |
||
1790 |
|||
1791 |
const Position pos = mPath.front(); |
||
1792 |
mPath.pop_front(); |
||
1793 |
|||
1794 |
const uint8_t dir = calcDirection(pos.x, pos.y); |
||
1795 |
if (dir != 0U) |
||
1796 |
setDirection(dir); |
||
1797 |
|||
1798 |
if (mMap == nullptr || |
||
1799 |
!mMap->getWalk(pos.x, pos.y, getBlockWalkMask())) |
||
1800 |
{ |
||
1801 |
setAction(BeingAction::STAND, 0); |
||
1802 |
return; |
||
1803 |
} |
||
1804 |
|||
1805 |
mActionTime += mSpeed / 10; |
||
1806 |
if ((mType != ActorType::Player || mUseDiagonal) |
||
1807 |
&& mX != pos.x && mY != pos.y) |
||
1808 |
{ |
||
1809 |
mSpeed = mWalkSpeed * 14 / 10; |
||
1810 |
} |
||
1811 |
else |
||
1812 |
{ |
||
1813 |
mSpeed = mWalkSpeed; |
||
1814 |
} |
||
1815 |
|||
1816 |
if (mX != pos.x || mY != pos.y) |
||
1817 |
{ |
||
1818 |
mOldHeight = mMap->getHeightOffset(mX, mY); |
||
1819 |
if (mReachable == Reachable::REACH_NO && |
||
1820 |
mMap->getBlockMask(mX, mY) != mMap->getBlockMask(pos.x, pos.y)) |
||
1821 |
{ |
||
1822 |
mReachable = Reachable::REACH_UNKNOWN; |
||
1823 |
} |
||
1824 |
} |
||
1825 |
mX = pos.x; |
||
1826 |
mY = pos.y; |
||
1827 |
const uint8_t height = mMap->getHeightOffset(mX, mY); |
||
1828 |
mPixelOffsetY = height - mOldHeight; |
||
1829 |
mFixedOffsetY = height; |
||
1830 |
mNeedPosUpdate = true; |
||
1831 |
setAction(BeingAction::MOVE, 0); |
||
1832 |
} |
||
1833 |
|||
1834 |
void Being::logic() restrict2 |
||
1835 |
{ |
||
1836 |
BLOCK_START("Being::logic") |
||
1837 |
if (A_UNLIKELY(mSpeechTime != 0)) |
||
1838 |
{ |
||
1839 |
mSpeechTime--; |
||
1840 |
if (mSpeechTime == 0 && mText != nullptr) |
||
1841 |
delete2(mText) |
||
1842 |
} |
||
1843 |
|||
1844 |
if (A_UNLIKELY(mOwner != nullptr)) |
||
1845 |
{ |
||
1846 |
if (mType == ActorType::Homunculus || |
||
1847 |
mType == ActorType::Mercenary) |
||
1848 |
{ |
||
1849 |
botLogic(); |
||
1850 |
} |
||
1851 |
} |
||
1852 |
|||
1853 |
const int time = tick_time * MILLISECONDS_IN_A_TICK; |
||
1854 |
if (mEmotionSprite != nullptr) |
||
1855 |
mEmotionSprite->update(time); |
||
1856 |
for_each_horses(mDownHorseSprites) |
||
1857 |
(*it)->update(time); |
||
1858 |
for_each_horses(mUpHorseSprites) |
||
1859 |
(*it)->update(time); |
||
1860 |
|||
1861 |
if (A_UNLIKELY(mCastEndTime != 0 && mCastEndTime < tick_time)) |
||
1862 |
{ |
||
1863 |
mCastEndTime = 0; |
||
1864 |
delete2(mCastingEffect) |
||
1865 |
} |
||
1866 |
|||
1867 |
if (A_UNLIKELY(mAnimationEffect)) |
||
1868 |
{ |
||
1869 |
mAnimationEffect->update(time); |
||
1870 |
if (mAnimationEffect->isTerminated()) |
||
1871 |
delete2(mAnimationEffect) |
||
1872 |
} |
||
1873 |
if (A_UNLIKELY(mCastingEffect)) |
||
1874 |
{ |
||
1875 |
mCastingEffect->update(time); |
||
1876 |
if (mCastingEffect->isTerminated()) |
||
1877 |
delete2(mCastingEffect) |
||
1878 |
} |
||
1879 |
for_each_badges() |
||
1880 |
{ |
||
1881 |
AnimatedSprite *restrict const sprite = mBadges[f]; |
||
1882 |
if (sprite != nullptr) |
||
1883 |
sprite->update(time); |
||
1884 |
} |
||
1885 |
|||
1886 |
int frameCount = CAST_S32(getFrameCount()); |
||
1887 |
|||
1888 |
switch (mAction) |
||
1889 |
{ |
||
1890 |
case BeingAction::STAND: |
||
1891 |
case BeingAction::SIT: |
||
1892 |
case BeingAction::DEAD: |
||
1893 |
case BeingAction::HURT: |
||
1894 |
case BeingAction::SPAWN: |
||
1895 |
case BeingAction::CAST: |
||
1896 |
default: |
||
1897 |
break; |
||
1898 |
|||
1899 |
case BeingAction::MOVE: |
||
1900 |
{ |
||
1901 |
if (get_elapsed_time(mActionTime) >= mSpeed) |
||
1902 |
nextTile(); |
||
1903 |
break; |
||
1904 |
} |
||
1905 |
|||
1906 |
case BeingAction::ATTACK: |
||
1907 |
{ |
||
1908 |
if (mActionTime == 0) |
||
1909 |
break; |
||
1910 |
|||
1911 |
int curFrame = 0; |
||
1912 |
if (mAttackSpeed != 0) |
||
1913 |
{ |
||
1914 |
curFrame = (get_elapsed_time(mActionTime) * frameCount) |
||
1915 |
/ mAttackSpeed; |
||
1916 |
} |
||
1917 |
|||
1918 |
if (this == localPlayer && curFrame >= frameCount) |
||
1919 |
nextTile(); |
||
1920 |
|||
1921 |
break; |
||
1922 |
} |
||
1923 |
|||
1924 |
case BeingAction::PRESTAND: |
||
1925 |
{ |
||
1926 |
if (get_elapsed_time1(mPreStandTime) > 10) |
||
1927 |
setAction(BeingAction::STAND, 0); |
||
1928 |
break; |
||
1929 |
} |
||
1930 |
} |
||
1931 |
|||
1932 |
if (mAction == BeingAction::MOVE || mNeedPosUpdate) |
||
1933 |
{ |
||
1934 |
const int xOffset = getOffset<BeingDirection::LEFT, |
||
1935 |
BeingDirection::RIGHT>(); |
||
1936 |
const int yOffset = getOffset<BeingDirection::UP, |
||
1937 |
BeingDirection::DOWN>(); |
||
1938 |
int offset = xOffset; |
||
1939 |
if (offset == 0) |
||
1940 |
offset = yOffset; |
||
1941 |
|||
1942 |
if ((xOffset == 0) && (yOffset == 0)) |
||
1943 |
mNeedPosUpdate = false; |
||
1944 |
|||
1945 |
const int halfTile = mapTileSize / 2; |
||
1946 |
const float offset2 = static_cast<float>( |
||
1947 |
mPixelOffsetY * abs(offset)) / 2; |
||
1948 |
// mSortOffsetY = (mOldHeight - mFixedOffsetY + mPixelOffsetY) |
||
1949 |
// * halfTile - offset2; |
||
1950 |
mSortOffsetY = 0; |
||
1951 |
const float yOffset3 = (mY + 1) * mapTileSize + yOffset |
||
1952 |
- (mOldHeight + mPixelOffsetY) * halfTile + offset2; |
||
1953 |
|||
1954 |
// Update pixel coordinates |
||
1955 |
setPixelPositionF(static_cast<float>(mX * mapTileSize |
||
1956 |
+ mapTileSize / 2 + xOffset), |
||
1957 |
yOffset3, |
||
1958 |
0.0F); |
||
1959 |
} |
||
1960 |
|||
1961 |
if (A_UNLIKELY(mEmotionSprite)) |
||
1962 |
{ |
||
1963 |
mEmotionTime--; |
||
1964 |
if (mEmotionTime == 0) |
||
1965 |
delete2(mEmotionSprite) |
||
1966 |
} |
||
1967 |
|||
1968 |
ActorSprite::logic(); |
||
1969 |
|||
1970 |
if (frameCount < 10) |
||
1971 |
frameCount = 10; |
||
1972 |
|||
1973 |
if (A_UNLIKELY(!isAlive() && |
||
1974 |
mSpeed != 0 && |
||
1975 |
gameHandler->removeDeadBeings() && |
||
1976 |
get_elapsed_time(mActionTime) / mSpeed >= frameCount)) |
||
1977 |
{ |
||
1978 |
if (mType != ActorType::Player && (actorManager != nullptr)) |
||
1979 |
actorManager->destroy(this); |
||
1980 |
} |
||
1981 |
|||
1982 |
const SoundInfo *restrict const sound = mNextSound.sound; |
||
1983 |
if (A_UNLIKELY(sound)) |
||
1984 |
{ |
||
1985 |
const int time2 = tick_time; |
||
1986 |
if (time2 > mNextSound.time) |
||
1987 |
{ |
||
1988 |
soundManager.playSfx(sound->sound, |
||
1989 |
mNextSound.x, |
||
1990 |
mNextSound.y); |
||
1991 |
mNextSound.sound = nullptr; |
||
1992 |
mNextSound.time = time2 + sound->delay; |
||
1993 |
} |
||
1994 |
} |
||
1995 |
|||
1996 |
BLOCK_END("Being::logic") |
||
1997 |
} |
||
1998 |
|||
1999 |
void Being::botLogic() restrict2 |
||
2000 |
{ |
||
2001 |
if ((mOwner == nullptr) || (mMap == nullptr) || (mInfo == nullptr)) |
||
2002 |
return; |
||
2003 |
|||
2004 |
const int time = tick_time; |
||
2005 |
const int thinkTime = mInfo->getThinkTime(); |
||
2006 |
if (abs(CAST_S32(mMoveTime) - time) < thinkTime) |
||
2007 |
return; |
||
2008 |
|||
2009 |
mMoveTime = time; |
||
2010 |
|||
2011 |
int dstX = mOwner->mX; |
||
2012 |
int dstY = mOwner->mY; |
||
2013 |
const int warpDist = mInfo->getWarpDist(); |
||
2014 |
const int divX = abs(dstX - mX); |
||
2015 |
const int divY = abs(dstY - mY); |
||
2016 |
|||
2017 |
if (divX >= warpDist || divY >= warpDist) |
||
2018 |
{ |
||
2019 |
if (mType == ActorType::Homunculus) |
||
2020 |
homunculusHandler->moveToMaster(); |
||
2021 |
else |
||
2022 |
mercenaryHandler->moveToMaster(); |
||
2023 |
mBotAi = true; |
||
2024 |
return; |
||
2025 |
} |
||
2026 |
if (!mBotAi) |
||
2027 |
return; |
||
2028 |
if (mAction == BeingAction::MOVE) |
||
2029 |
{ |
||
2030 |
if (mOwner->mAction == BeingAction::MOVE) |
||
2031 |
{ |
||
2032 |
updateBotFollow(dstX, dstY, |
||
2033 |
divX, divY); |
||
2034 |
} |
||
2035 |
return; |
||
2036 |
} |
||
2037 |
|||
2038 |
switch (mOwner->mAction) |
||
2039 |
{ |
||
2040 |
case BeingAction::MOVE: |
||
2041 |
case BeingAction::PRESTAND: |
||
2042 |
updateBotFollow(dstX, dstY, |
||
2043 |
divX, divY); |
||
2044 |
break; |
||
2045 |
case BeingAction::STAND: |
||
2046 |
case BeingAction::SPAWN: |
||
2047 |
botFixOffset(dstX, dstY); |
||
2048 |
moveBotTo(dstX, dstY); |
||
2049 |
break; |
||
2050 |
case BeingAction::ATTACK: |
||
2051 |
{ |
||
2052 |
const Being *const target = localPlayer->getTarget(); |
||
2053 |
if (target == nullptr) |
||
2054 |
return; |
||
2055 |
const BeingId targetId = target->getId(); |
||
2056 |
if (mType == ActorType::Homunculus) |
||
2057 |
{ |
||
2058 |
homunculusHandler->attack(targetId, |
||
2059 |
Keep_true); |
||
2060 |
} |
||
2061 |
else |
||
2062 |
{ |
||
2063 |
mercenaryHandler->attack(targetId, |
||
2064 |
Keep_true); |
||
2065 |
} |
||
2066 |
break; |
||
2067 |
} |
||
2068 |
case BeingAction::SIT: |
||
2069 |
case BeingAction::DEAD: |
||
2070 |
botFixOffset(dstX, dstY); |
||
2071 |
moveBotTo(dstX, dstY); |
||
2072 |
break; |
||
2073 |
case BeingAction::CAST: |
||
2074 |
case BeingAction::HURT: |
||
2075 |
default: |
||
2076 |
break; |
||
2077 |
} |
||
2078 |
} |
||
2079 |
|||
2080 |
void Being::botFixOffset(int &restrict dstX, |
||
2081 |
int &restrict dstY) const |
||
2082 |
{ |
||
2083 |
if ((mInfo == nullptr) || (mOwner == nullptr)) |
||
2084 |
return; |
||
2085 |
|||
2086 |
int offsetX1; |
||
2087 |
int offsetY1; |
||
2088 |
switch (mOwner->getCurrentAction()) |
||
2089 |
{ |
||
2090 |
case BeingAction::SIT: |
||
2091 |
offsetX1 = mInfo->getSitOffsetX(); |
||
2092 |
offsetY1 = mInfo->getSitOffsetY(); |
||
2093 |
break; |
||
2094 |
|||
2095 |
case BeingAction::MOVE: |
||
2096 |
offsetX1 = mInfo->getMoveOffsetX(); |
||
2097 |
offsetY1 = mInfo->getMoveOffsetY(); |
||
2098 |
break; |
||
2099 |
|||
2100 |
case BeingAction::DEAD: |
||
2101 |
offsetX1 = mInfo->getDeadOffsetX(); |
||
2102 |
offsetY1 = mInfo->getDeadOffsetY(); |
||
2103 |
break; |
||
2104 |
|||
2105 |
case BeingAction::ATTACK: |
||
2106 |
offsetX1 = mInfo->getAttackOffsetX(); |
||
2107 |
offsetY1 = mInfo->getAttackOffsetY(); |
||
2108 |
break; |
||
2109 |
|||
2110 |
case BeingAction::SPAWN: |
||
2111 |
case BeingAction::HURT: |
||
2112 |
case BeingAction::STAND: |
||
2113 |
case BeingAction::PRESTAND: |
||
2114 |
case BeingAction::CAST: |
||
2115 |
default: |
||
2116 |
offsetX1 = mInfo->getTargetOffsetX(); |
||
2117 |
offsetY1 = mInfo->getTargetOffsetY(); |
||
2118 |
break; |
||
2119 |
} |
||
2120 |
|||
2121 |
int offsetX = offsetX1; |
||
2122 |
int offsetY = offsetY1; |
||
2123 |
switch (mOwner->mDirection) |
||
2124 |
{ |
||
2125 |
case BeingDirection::LEFT: |
||
2126 |
offsetX = -offsetY1; |
||
2127 |
offsetY = offsetX1; |
||
2128 |
break; |
||
2129 |
case BeingDirection::RIGHT: |
||
2130 |
offsetX = offsetY1; |
||
2131 |
offsetY = -offsetX1; |
||
2132 |
break; |
||
2133 |
case BeingDirection::UP: |
||
2134 |
offsetY = -offsetY; |
||
2135 |
offsetX = -offsetX; |
||
2136 |
break; |
||
2137 |
default: |
||
2138 |
case BeingDirection::DOWN: |
||
2139 |
break; |
||
2140 |
} |
||
2141 |
dstX += offsetX; |
||
2142 |
dstY += offsetY; |
||
2143 |
if (mMap != nullptr) |
||
2144 |
{ |
||
2145 |
if (!mMap->getWalk(dstX, dstY, getBlockWalkMask())) |
||
2146 |
{ |
||
2147 |
dstX = mOwner->mX; |
||
2148 |
dstY = mOwner->mY; |
||
2149 |
} |
||
2150 |
} |
||
2151 |
} |
||
2152 |
|||
2153 |
void Being::updateBotFollow(int dstX, |
||
2154 |
int dstY, |
||
2155 |
const int divX, |
||
2156 |
const int divY) |
||
2157 |
{ |
||
2158 |
const int followDist = mInfo->getStartFollowDist(); |
||
2159 |
const int dist = mInfo->getFollowDist(); |
||
2160 |
if (divX > followDist || divY > followDist) |
||
2161 |
{ |
||
2162 |
if (dist > 0) |
||
2163 |
{ |
||
2164 |
if (divX > followDist) |
||
2165 |
{ |
||
2166 |
if (dstX > mX + dist) |
||
2167 |
dstX -= dist; |
||
2168 |
else if (dstX + dist <= mX) |
||
2169 |
dstX += dist; |
||
2170 |
} |
||
2171 |
else |
||
2172 |
{ |
||
2173 |
dstX = mX; |
||
2174 |
} |
||
2175 |
if (divY > followDist) |
||
2176 |
{ |
||
2177 |
if (dstY > mY + dist) |
||
2178 |
dstY -= dist; |
||
2179 |
else if (dstX + dist <= mX) |
||
2180 |
dstY += dist; |
||
2181 |
} |
||
2182 |
else |
||
2183 |
{ |
||
2184 |
dstY = mY; |
||
2185 |
} |
||
2186 |
} |
||
2187 |
botFixOffset(dstX, dstY); |
||
2188 |
moveBotTo(dstX, dstY); |
||
2189 |
} |
||
2190 |
} |
||
2191 |
|||
2192 |
void Being::moveBotTo(int dstX, |
||
2193 |
int dstY) |
||
2194 |
{ |
||
2195 |
const int dstX0 = mOwner->mX; |
||
2196 |
const int dstY0 = mOwner->mY; |
||
2197 |
const unsigned char blockWalkMask = getBlockWalkMask(); |
||
2198 |
if (!mMap->getWalk(dstX, dstY, blockWalkMask)) |
||
2199 |
{ |
||
2200 |
if (dstX != dstX0) |
||
2201 |
{ |
||
2202 |
dstX = dstX0; |
||
2203 |
if (!mMap->getWalk(dstX, dstY, blockWalkMask)) |
||
2204 |
dstY = dstY0; |
||
2205 |
} |
||
2206 |
else if (dstY != dstY0) |
||
2207 |
{ |
||
2208 |
dstY = dstY0; |
||
2209 |
if (!mMap->getWalk(dstX, dstY, blockWalkMask)) |
||
2210 |
dstX = dstX0; |
||
2211 |
} |
||
2212 |
} |
||
2213 |
if (mX != dstX || mY != dstY) |
||
2214 |
{ |
||
2215 |
if (mType == ActorType::Homunculus) |
||
2216 |
homunculusHandler->move(dstX, dstY); |
||
2217 |
else |
||
2218 |
mercenaryHandler->move(dstX, dstY); |
||
2219 |
return; |
||
2220 |
} |
||
2221 |
updateBotDirection(dstX, dstY); |
||
2222 |
} |
||
2223 |
|||
2224 |
void Being::updateBotDirection(const int dstX, |
||
2225 |
const int dstY) |
||
2226 |
{ |
||
2227 |
int directionType = 0; |
||
2228 |
switch (mOwner->getCurrentAction()) |
||
2229 |
{ |
||
2230 |
case BeingAction::STAND: |
||
2231 |
case BeingAction::MOVE: |
||
2232 |
case BeingAction::HURT: |
||
2233 |
case BeingAction::SPAWN: |
||
2234 |
case BeingAction::CAST: |
||
2235 |
case BeingAction::PRESTAND: |
||
2236 |
default: |
||
2237 |
directionType = mInfo->getDirectionType(); |
||
2238 |
break; |
||
2239 |
case BeingAction::SIT: |
||
2240 |
directionType = mInfo->getSitDirectionType(); |
||
2241 |
break; |
||
2242 |
case BeingAction::DEAD: |
||
2243 |
directionType = mInfo->getDeadDirectionType(); |
||
2244 |
break; |
||
2245 |
case BeingAction::ATTACK: |
||
2246 |
directionType = mInfo->getAttackDirectionType(); |
||
2247 |
break; |
||
2248 |
} |
||
2249 |
|||
2250 |
uint8_t newDir = 0; |
||
2251 |
switch (directionType) |
||
2252 |
{ |
||
2253 |
case 0: |
||
2254 |
default: |
||
2255 |
return; |
||
2256 |
|||
2257 |
case 1: |
||
2258 |
newDir = mOwner->mDirection; |
||
2259 |
break; |
||
2260 |
|||
2261 |
case 2: |
||
2262 |
{ |
||
2263 |
const int dstX0 = mOwner->mX; |
||
2264 |
const int dstY0 = mOwner->mY; |
||
2265 |
if (dstX > dstX0) |
||
2266 |
newDir |= BeingDirection::LEFT; |
||
2267 |
else if (dstX < dstX0) |
||
2268 |
newDir |= BeingDirection::RIGHT; |
||
2269 |
if (dstY > dstY0) |
||
2270 |
newDir |= BeingDirection::UP; |
||
2271 |
else if (dstY < dstY0) |
||
2272 |
newDir |= BeingDirection::DOWN; |
||
2273 |
break; |
||
2274 |
} |
||
2275 |
case 3: |
||
2276 |
{ |
||
2277 |
const int dstX0 = mOwner->mX; |
||
2278 |
const int dstY0 = mOwner->mY; |
||
2279 |
if (dstX > dstX0) |
||
2280 |
newDir |= BeingDirection::RIGHT; |
||
2281 |
else if (dstX < dstX0) |
||
2282 |
newDir |= BeingDirection::LEFT; |
||
2283 |
if (dstY > dstY0) |
||
2284 |
newDir |= BeingDirection::DOWN; |
||
2285 |
else if (dstY < dstY0) |
||
2286 |
newDir |= BeingDirection::UP; |
||
2287 |
break; |
||
2288 |
} |
||
2289 |
case 4: |
||
2290 |
{ |
||
2291 |
const int dstX2 = mOwner->getLastAttackX(); |
||
2292 |
const int dstY2 = mOwner->getLastAttackY(); |
||
2293 |
if (dstX > dstX2) |
||
2294 |
newDir |= BeingDirection::LEFT; |
||
2295 |
else if (dstX < dstX2) |
||
2296 |
newDir |= BeingDirection::RIGHT; |
||
2297 |
if (dstY > dstY2) |
||
2298 |
newDir |= BeingDirection::UP; |
||
2299 |
else if (dstY < dstY2) |
||
2300 |
newDir |= BeingDirection::DOWN; |
||
2301 |
break; |
||
2302 |
} |
||
2303 |
} |
||
2304 |
if ((newDir != 0U) && newDir != mDirection) |
||
2305 |
{ |
||
2306 |
if (mType == ActorType::Homunculus) |
||
2307 |
homunculusHandler->setDirection(newDir); |
||
2308 |
else |
||
2309 |
mercenaryHandler->setDirection(newDir); |
||
2310 |
} |
||
2311 |
} |
||
2312 |
|||
2313 |
9 |
void Being::updateBadgesPosition() |
|
2314 |
{ |
||
2315 |
9 |
const int px = mPixelX - mapTileSize / 2; |
|
2316 |
9 |
const int py = mPixelY - mapTileSize * 2 - mapTileSize; |
|
2317 |
✓✗✗✓ |
18 |
if (mShowBadges != BadgeDrawType::Hide && |
2318 |
9 |
mBadgesCount != 0U) |
|
2319 |
{ |
||
2320 |
if (mDispName != nullptr && |
||
2321 |
gui != nullptr) |
||
2322 |
{ |
||
2323 |
if (mShowBadges == BadgeDrawType::Right) |
||
2324 |
{ |
||
2325 |
const Font *restrict const font = gui->getFont(); |
||
2326 |
mBadgesX = mDispName->getX() + mDispName->getWidth(); |
||
2327 |
mBadgesY = mDispName->getY() - font->getHeight(); |
||
2328 |
} |
||
2329 |
else if (mShowBadges == BadgeDrawType::Bottom) |
||
2330 |
{ |
||
2331 |
mBadgesX = px + 8 - mBadgesCount * 8; |
||
2332 |
if (mVisibleNamePos == VisibleNamePos::Bottom) |
||
2333 |
{ |
||
2334 |
mBadgesY = mDispName->getY(); |
||
2335 |
} |
||
2336 |
else |
||
2337 |
{ |
||
2338 |
mBadgesY = py + settings.playerNameOffset + 16; |
||
2339 |
} |
||
2340 |
} |
||
2341 |
else |
||
2342 |
{ |
||
2343 |
mBadgesX = px + 8 - mBadgesCount * 8; |
||
2344 |
if (mVisibleNamePos == VisibleNamePos::Top) |
||
2345 |
mBadgesY = py - mDispName->getHeight(); |
||
2346 |
else |
||
2347 |
mBadgesY = py; |
||
2348 |
} |
||
2349 |
} |
||
2350 |
else |
||
2351 |
{ |
||
2352 |
if (mShowBadges == BadgeDrawType::Right) |
||
2353 |
{ |
||
2354 |
mBadgesX = px + settings.playerBadgeAtRightOffset; |
||
2355 |
mBadgesY = py; |
||
2356 |
} |
||
2357 |
else if (mShowBadges == BadgeDrawType::Bottom) |
||
2358 |
{ |
||
2359 |
mBadgesX = px + 8 - mBadgesCount * 8; |
||
2360 |
const int height = settings.playerNameOffset; |
||
2361 |
if (mVisibleNamePos == VisibleNamePos::Bottom) |
||
2362 |
mBadgesY = py + height; |
||
2363 |
else |
||
2364 |
mBadgesY = py + height + 16; |
||
2365 |
} |
||
2366 |
else |
||
2367 |
{ |
||
2368 |
mBadgesX = px + 8 - mBadgesCount * 8; |
||
2369 |
mBadgesY = py; |
||
2370 |
} |
||
2371 |
} |
||
2372 |
} |
||
2373 |
9 |
} |
|
2374 |
|||
2375 |
void Being::drawEmotion(Graphics *restrict const graphics, |
||
2376 |
const int offsetX, |
||
2377 |
const int offsetY) const restrict2 |
||
2378 |
{ |
||
2379 |
if (mErased) |
||
2380 |
return; |
||
2381 |
|||
2382 |
const int px = mPixelX - offsetX - mapTileSize / 2; |
||
2383 |
const int py = mPixelY - offsetY - mapTileSize * 2 - mapTileSize; |
||
2384 |
if (mAnimationEffect != nullptr) |
||
2385 |
mAnimationEffect->draw(graphics, px, py); |
||
2386 |
if (mShowBadges != BadgeDrawType::Hide && |
||
2387 |
mBadgesCount != 0U) |
||
2388 |
{ |
||
2389 |
int x = mBadgesX - offsetX; |
||
2390 |
const int y = mBadgesY - offsetY; |
||
2391 |
for_each_badges() |
||
2392 |
{ |
||
2393 |
const AnimatedSprite *restrict const sprite = mBadges[f]; |
||
2394 |
if (sprite != nullptr) |
||
2395 |
{ |
||
2396 |
sprite->draw(graphics, x, y); |
||
2397 |
x += 16; |
||
2398 |
} |
||
2399 |
} |
||
2400 |
} |
||
2401 |
if (mEmotionSprite != nullptr) |
||
2402 |
mEmotionSprite->draw(graphics, px, py); |
||
2403 |
} |
||
2404 |
|||
2405 |
void Being::drawSpeech(const int offsetX, |
||
2406 |
const int offsetY) restrict2 |
||
2407 |
{ |
||
2408 |
if (mErased) |
||
2409 |
return; |
||
2410 |
if (mSpeech.empty()) |
||
2411 |
return; |
||
2412 |
|||
2413 |
const int px = mPixelX - offsetX; |
||
2414 |
const int py = mPixelY - offsetY; |
||
2415 |
const int speech = mSpeechType; |
||
2416 |
|||
2417 |
// Draw speech above this being |
||
2418 |
if (mSpeechTime == 0) |
||
2419 |
{ |
||
2420 |
if (mSpeechBubble != nullptr && |
||
2421 |
mSpeechBubble->mVisible == Visible_true) |
||
2422 |
{ |
||
2423 |
mSpeechBubble->setVisible(Visible_false); |
||
2424 |
} |
||
2425 |
mSpeech.clear(); |
||
2426 |
} |
||
2427 |
else if (mSpeechTime > 0 && (speech == BeingSpeech::NAME_IN_BUBBLE || |
||
2428 |
speech == BeingSpeech::NO_NAME_IN_BUBBLE)) |
||
2429 |
{ |
||
2430 |
delete2(mText) |
||
2431 |
|||
2432 |
if (mSpeechBubble != nullptr) |
||
2433 |
{ |
||
2434 |
mSpeechBubble->setPosition(px - (mSpeechBubble->getWidth() / 2), |
||
2435 |
py - getHeight() - (mSpeechBubble->getHeight())); |
||
2436 |
mSpeechBubble->setVisible(Visible_true); |
||
2437 |
} |
||
2438 |
} |
||
2439 |
else if (mSpeechTime > 0 && speech == BeingSpeech::TEXT_OVERHEAD) |
||
2440 |
{ |
||
2441 |
if (mSpeechBubble != nullptr) |
||
2442 |
mSpeechBubble->setVisible(Visible_false); |
||
2443 |
|||
2444 |
if ((mText == nullptr) && (userPalette != nullptr)) |
||
2445 |
{ |
||
2446 |
mText = new Text(mSpeech, |
||
2447 |
mPixelX, |
||
2448 |
mPixelY - getHeight(), |
||
2449 |
Graphics::CENTER, |
||
2450 |
&theme->getColor(ThemeColorId::BUBBLE_TEXT, 255), |
||
2451 |
Speech_true, |
||
2452 |
nullptr); |
||
2453 |
mText->adviseXY(mPixelX, |
||
2454 |
(mY + 1) * mapTileSize - getHeight() - mText->getHeight() - 9, |
||
2455 |
mMoveNames); |
||
2456 |
} |
||
2457 |
} |
||
2458 |
else if (speech == BeingSpeech::NO_SPEECH) |
||
2459 |
{ |
||
2460 |
if (mSpeechBubble != nullptr) |
||
2461 |
mSpeechBubble->setVisible(Visible_false); |
||
2462 |
delete2(mText) |
||
2463 |
} |
||
2464 |
} |
||
2465 |
|||
2466 |
template<signed char pos, signed char neg> |
||
2467 |
int Being::getOffset() const restrict2 |
||
2468 |
{ |
||
2469 |
// Check whether we're walking in the requested direction |
||
2470 |
if (mAction != BeingAction::MOVE || !(mDirection & (pos | neg))) |
||
2471 |
return 0; |
||
2472 |
|||
2473 |
int offset = 0; |
||
2474 |
|||
2475 |
if (mMap && mSpeed) |
||
2476 |
{ |
||
2477 |
const int time = get_elapsed_time(mActionTime); |
||
2478 |
offset = (pos == BeingDirection::LEFT && |
||
2479 |
neg == BeingDirection::RIGHT) ? |
||
2480 |
(time * mMap->getTileWidth() / mSpeed) |
||
2481 |
: (time * mMap->getTileHeight() / mSpeed); |
||
2482 |
} |
||
2483 |
|||
2484 |
// We calculate the offset _from_ the _target_ location |
||
2485 |
offset -= mapTileSize; |
||
2486 |
if (offset > 0) |
||
2487 |
offset = 0; |
||
2488 |
|||
2489 |
// Going into negative direction? Invert the offset. |
||
2490 |
if (mDirection & pos) |
||
2491 |
offset = -offset; |
||
2492 |
|||
2493 |
if (offset > mapTileSize) |
||
2494 |
offset = mapTileSize; |
||
2495 |
if (offset < -mapTileSize) |
||
2496 |
offset = -mapTileSize; |
||
2497 |
|||
2498 |
return offset; |
||
2499 |
} |
||
2500 |
|||
2501 |
9 |
void Being::updateCoords() restrict2 |
|
2502 |
{ |
||
2503 |
✓✗ | 9 |
if (mDispName != nullptr) |
2504 |
{ |
||
2505 |
9 |
int offsetX = mPixelX; |
|
2506 |
9 |
int offsetY = mPixelY; |
|
2507 |
✗✓ | 9 |
if (mInfo != nullptr) |
2508 |
{ |
||
2509 |
offsetX += mInfo->getNameOffsetX(); |
||
2510 |
offsetY += mInfo->getNameOffsetY(); |
||
2511 |
} |
||
2512 |
// Monster names show above the sprite instead of below it |
||
2513 |
✓✓✗✓ |
17 |
if (mType == ActorType::Monster || |
2514 |
8 |
mVisibleNamePos == VisibleNamePos::Top) |
|
2515 |
{ |
||
2516 |
2 |
offsetY += - settings.playerNameOffset - mDispName->getHeight(); |
|
2517 |
} |
||
2518 |
9 |
mDispName->adviseXY(offsetX, offsetY, mMoveNames); |
|
2519 |
} |
||
2520 |
9 |
updateBadgesPosition(); |
|
2521 |
9 |
} |
|
2522 |
|||
2523 |
void Being::optionChanged(const std::string &restrict value) restrict2 |
||
2524 |
{ |
||
2525 |
if (mType == ActorType::Player && value == "visiblenames") |
||
2526 |
{ |
||
2527 |
setShowName(config.getIntValue("visiblenames") == VisibleName::Show); |
||
2528 |
updateBadgesPosition(); |
||
2529 |
} |
||
2530 |
} |
||
2531 |
|||
2532 |
void Being::flashName(const int time) restrict2 |
||
2533 |
{ |
||
2534 |
if (mDispName != nullptr) |
||
2535 |
mDispName->flash(time); |
||
2536 |
} |
||
2537 |
|||
2538 |
std::string Being::getGenderSignWithSpace() const restrict2 |
||
2539 |
{ |
||
2540 |
const std::string &restrict str = getGenderSign(); |
||
2541 |
if (str.empty()) |
||
2542 |
return str; |
||
2543 |
else |
||
2544 |
return std::string(" ").append(str); |
||
2545 |
} |
||
2546 |
|||
2547 |
std::string Being::getGenderSign() const restrict2 |
||
2548 |
{ |
||
2549 |
std::string str; |
||
2550 |
if (mShowGender) |
||
2551 |
{ |
||
2552 |
if (getGender() == Gender::FEMALE) |
||
2553 |
str = "\u2640"; |
||
2554 |
else if (getGender() == Gender::MALE) |
||
2555 |
str = "\u2642"; |
||
2556 |
else if (mType == ActorType::Player) |
||
2557 |
str = "\u2640"; |
||
2558 |
} |
||
2559 |
if (mShowPlayersStatus && |
||
2560 |
mShowBadges == BadgeDrawType::Hide) |
||
2561 |
{ |
||
2562 |
if (mShop) |
||
2563 |
str.append("$"); |
||
2564 |
if (mAway) |
||
2565 |
{ |
||
2566 |
// TRANSLATORS: this away status writed in player nick |
||
2567 |
str.append(_("A")); |
||
2568 |
} |
||
2569 |
else if (mInactive) |
||
2570 |
{ |
||
2571 |
// TRANSLATORS: this inactive status writed in player nick |
||
2572 |
str.append(_("I")); |
||
2573 |
} |
||
2574 |
} |
||
2575 |
return str; |
||
2576 |
} |
||
2577 |
|||
2578 |
110 |
void Being::showName() restrict2 |
|
2579 |
{ |
||
2580 |
✓✓ | 220 |
if (mName.empty()) |
2581 |
101 |
return; |
|
2582 |
|||
2583 |
✓✓ | 18 |
delete2(mDispName) |
2584 |
|||
2585 |
✗✓✗✗ ✓✗ |
9 |
if (mHideErased && playerRelations.getRelation(mName) == Relation::ERASED) |
2586 |
return; |
||
2587 |
|||
2588 |
27 |
std::string displayName(mName); |
|
2589 |
|||
2590 |
✓✓✓✗ ✗✓ |
9 |
if (mType != ActorType::Monster && (mShowGender || mShowLevel)) |
2591 |
{ |
||
2592 |
displayName.append(" "); |
||
2593 |
if (mShowLevel && getLevel() != 0) |
||
2594 |
displayName.append(toString(getLevel())); |
||
2595 |
|||
2596 |
displayName.append(getGenderSign()); |
||
2597 |
} |
||
2598 |
|||
2599 |
✓✓ | 9 |
if (mType == ActorType::Monster) |
2600 |
{ |
||
2601 |
✓✗✓✗ ✓✗ |
4 |
if (config.getBoolValue("showMonstersTakedDamage")) |
2602 |
✓✗✓✗ |
3 |
displayName.append(", ").append(toString(getDamageTaken())); |
2603 |
} |
||
2604 |
|||
2605 |
9 |
Font *font = nullptr; |
|
2606 |
✓✗✓✓ ✓✓ |
27 |
if ((localPlayer != nullptr) && localPlayer->getTarget() == this |
2607 |
✓✗✓✓ |
11 |
&& mType != ActorType::Monster) |
2608 |
{ |
||
2609 |
1 |
font = boldFont; |
|
2610 |
} |
||
2611 |
✗✓ | 16 |
else if (mType == ActorType::Player |
2612 |
✓✓✓✗ ✗✓✗✗ |
8 |
&& !playerRelations.isGoodName(this) && (gui != nullptr)) |
2613 |
{ |
||
2614 |
font = gui->getSecureFont(); |
||
2615 |
} |
||
2616 |
|||
2617 |
✗✓ | 9 |
if (mInfo != nullptr) |
2618 |
{ |
||
2619 |
mDispName = new FlashText(displayName, |
||
2620 |
mPixelX + mInfo->getNameOffsetX(), |
||
2621 |
mPixelY + mInfo->getNameOffsetY(), |
||
2622 |
Graphics::CENTER, |
||
2623 |
mNameColor, |
||
2624 |
font); |
||
2625 |
} |
||
2626 |
else |
||
2627 |
{ |
||
2628 |
9 |
mDispName = new FlashText(displayName, |
|
2629 |
mPixelX, |
||
2630 |
mPixelY, |
||
2631 |
Graphics::CENTER, |
||
2632 |
mNameColor, |
||
2633 |
✓✗✓✗ |
9 |
font); |
2634 |
} |
||
2635 |
|||
2636 |
✓✗ | 9 |
updateCoords(); |
2637 |
} |
||
2638 |
|||
2639 |
71 |
void Being::setDefaultNameColor(const UserColorIdT defaultColor) restrict2 |
|
2640 |
{ |
||
2641 |
✓✗✗✗ |
71 |
switch (mTeamId) |
2642 |
{ |
||
2643 |
case 0: |
||
2644 |
default: |
||
2645 |
71 |
mNameColor = &userPalette->getColor(defaultColor, |
|
2646 |
71 |
255U); |
|
2647 |
71 |
break; |
|
2648 |
case 1: |
||
2649 |
mNameColor = &userPalette->getColor(UserColorId::TEAM1, |
||
2650 |
255U); |
||
2651 |
break; |
||
2652 |
case 2: |
||
2653 |
mNameColor = &userPalette->getColor(UserColorId::TEAM2, |
||
2654 |
255U); |
||
2655 |
break; |
||
2656 |
case 3: |
||
2657 |
mNameColor = &userPalette->getColor(UserColorId::TEAM3, |
||
2658 |
255U); |
||
2659 |
break; |
||
2660 |
} |
||
2661 |
71 |
} |
|
2662 |
|||
2663 |
109 |
void Being::updateColors() |
|
2664 |
{ |
||
2665 |
✓✓ | 109 |
if (userPalette != nullptr) |
2666 |
{ |
||
2667 |
✗✓ | 71 |
if (mType == ActorType::Monster) |
2668 |
{ |
||
2669 |
setDefaultNameColor(UserColorId::MONSTER); |
||
2670 |
mTextColor = &userPalette->getColor(UserColorId::MONSTER, |
||
2671 |
255U); |
||
2672 |
} |
||
2673 |
✗✓ | 71 |
else if (mType == ActorType::Npc) |
2674 |
{ |
||
2675 |
setDefaultNameColor(UserColorId::NPC); |
||
2676 |
mTextColor = &userPalette->getColor(UserColorId::NPC, |
||
2677 |
255U); |
||
2678 |
} |
||
2679 |
✗✓ | 71 |
else if (mType == ActorType::Pet) |
2680 |
{ |
||
2681 |
setDefaultNameColor(UserColorId::PET); |
||
2682 |
mTextColor = &userPalette->getColor(UserColorId::PET, |
||
2683 |
255U); |
||
2684 |
} |
||
2685 |
✗✓ | 71 |
else if (mType == ActorType::Homunculus) |
2686 |
{ |
||
2687 |
setDefaultNameColor(UserColorId::HOMUNCULUS); |
||
2688 |
mTextColor = &userPalette->getColor(UserColorId::HOMUNCULUS, |
||
2689 |
255U); |
||
2690 |
} |
||
2691 |
✗✓ | 71 |
else if (mType == ActorType::SkillUnit) |
2692 |
{ |
||
2693 |
setDefaultNameColor(UserColorId::SKILLUNIT); |
||
2694 |
mTextColor = &userPalette->getColor(UserColorId::SKILLUNIT, |
||
2695 |
255U); |
||
2696 |
} |
||
2697 |
✗✓ | 71 |
else if (this == localPlayer) |
2698 |
{ |
||
2699 |
mNameColor = &userPalette->getColor(UserColorId::SELF, 255U); |
||
2700 |
mTextColor = &theme->getColor(ThemeColorId::PLAYER, 255); |
||
2701 |
} |
||
2702 |
else |
||
2703 |
{ |
||
2704 |
71 |
mTextColor = &theme->getColor(ThemeColorId::PLAYER, 255); |
|
2705 |
|||
2706 |
✓✗ | 71 |
if (playerRelations.getRelation(mName) != Relation::ERASED) |
2707 |
71 |
mErased = false; |
|
2708 |
else |
||
2709 |
mErased = true; |
||
2710 |
|||
2711 |
✗✓ | 71 |
if (mIsGM) |
2712 |
{ |
||
2713 |
mTextColor = &userPalette->getColor(UserColorId::GM, |
||
2714 |
255U); |
||
2715 |
mNameColor = &userPalette->getColor(UserColorId::GM, |
||
2716 |
255U); |
||
2717 |
} |
||
2718 |
✗✓ | 71 |
else if (mEnemy) |
2719 |
{ |
||
2720 |
mNameColor = &userPalette->getColor(UserColorId::ENEMY, |
||
2721 |
255U); |
||
2722 |
} |
||
2723 |
✗✗✗✓ |
142 |
else if ((mParty != nullptr) && (localPlayer != nullptr) |
2724 |
✗✓✗✗ |
71 |
&& mParty == localPlayer->getParty()) |
2725 |
{ |
||
2726 |
mNameColor = &userPalette->getColor(UserColorId::PARTY, |
||
2727 |
255U); |
||
2728 |
} |
||
2729 |
✗✓✗✓ |
144 |
else if ((localPlayer != nullptr) && (getGuild() != nullptr) |
2730 |
✓✓✗✗ |
71 |
&& getGuild() == localPlayer->getGuild()) |
2731 |
{ |
||
2732 |
mNameColor = &userPalette->getColor(UserColorId::GUILD, |
||
2733 |
255U); |
||
2734 |
} |
||
2735 |
✗✓ | 71 |
else if (playerRelations.getRelation(mName) == Relation::FRIEND) |
2736 |
{ |
||
2737 |
mNameColor = &userPalette->getColor(UserColorId::FRIEND, |
||
2738 |
255U); |
||
2739 |
} |
||
2740 |
✗✓ | 142 |
else if (playerRelations.getRelation(mName) == |
2741 |
Relation::DISREGARDED |
||
2742 |
✓✗✗✓ |
71 |
|| playerRelations.getRelation(mName) == |
2743 |
Relation::BLACKLISTED) |
||
2744 |
{ |
||
2745 |
mNameColor = &userPalette->getColor(UserColorId::DISREGARDED, |
||
2746 |
255U); |
||
2747 |
} |
||
2748 |
✗✓ | 142 |
else if (playerRelations.getRelation(mName) |
2749 |
✓✗✗✓ |
142 |
== Relation::IGNORED || |
2750 |
71 |
playerRelations.getRelation(mName) == Relation::ENEMY2) |
|
2751 |
{ |
||
2752 |
mNameColor = &userPalette->getColor(UserColorId::IGNORED, |
||
2753 |
255U); |
||
2754 |
} |
||
2755 |
✗✓ | 71 |
else if (playerRelations.getRelation(mName) == Relation::ERASED) |
2756 |
{ |
||
2757 |
mNameColor = &userPalette->getColor(UserColorId::ERASED, |
||
2758 |
255U); |
||
2759 |
} |
||
2760 |
else |
||
2761 |
{ |
||
2762 |
71 |
setDefaultNameColor(UserColorId::PC); |
|
2763 |
} |
||
2764 |
} |
||
2765 |
|||
2766 |
✗✓ | 71 |
if (mDispName != nullptr) |
2767 |
mDispName->setColor(mNameColor); |
||
2768 |
} |
||
2769 |
109 |
} |
|
2770 |
|||
2771 |
void Being::updateSprite(const unsigned int slot, |
||
2772 |
const int id, |
||
2773 |
const std::string &restrict color) restrict2 |
||
2774 |
{ |
||
2775 |
if (charServerHandler == nullptr || slot >= charServerHandler->maxSprite()) |
||
2776 |
return; |
||
2777 |
|||
2778 |
if (slot >= CAST_U32(mSlots.size())) |
||
2779 |
mSlots.resize(slot + 1, BeingSlot()); |
||
2780 |
|||
2781 |
if ((slot != 0U) && mSlots[slot].spriteId == id) |
||
2782 |
return; |
||
2783 |
setSpriteColor(slot, |
||
2784 |
id, |
||
2785 |
color); |
||
2786 |
} |
||
2787 |
|||
2788 |
// set sprite id, reset colors, reset cards |
||
2789 |
void Being::setSpriteId(const unsigned int slot, |
||
2790 |
const int id) restrict2 |
||
2791 |
{ |
||
2792 |
if (charServerHandler == nullptr || slot >= charServerHandler->maxSprite()) |
||
2793 |
return; |
||
2794 |
|||
2795 |
if (slot >= CAST_U32(mSprites.size())) |
||
2796 |
ensureSize(slot + 1); |
||
2797 |
|||
2798 |
if (slot >= CAST_U32(mSlots.size())) |
||
2799 |
mSlots.resize(slot + 1, BeingSlot()); |
||
2800 |
|||
2801 |
// id = 0 means unequip |
||
2802 |
if (id == 0) |
||
2803 |
{ |
||
2804 |
removeSprite(slot); |
||
2805 |
mSpriteDraw[slot] = 0; |
||
2806 |
|||
2807 |
const int id1 = mSlots[slot].spriteId; |
||
2808 |
if (id1 != 0) |
||
2809 |
removeItemParticles(id1); |
||
2810 |
} |
||
2811 |
else |
||
2812 |
{ |
||
2813 |
const ItemInfo &info = ItemDB::get(id); |
||
2814 |
const std::string &restrict filename = info.getSprite( |
||
2815 |
mGender, mSubType); |
||
2816 |
int lastTime = 0; |
||
2817 |
int startTime = 0; |
||
2818 |
AnimatedSprite *restrict equipmentSprite = nullptr; |
||
2819 |
|||
2820 |
if (!filename.empty()) |
||
2821 |
{ |
||
2822 |
equipmentSprite = AnimatedSprite::delayedLoad( |
||
2823 |
pathJoin(paths.getStringValue("sprites"), filename), |
||
2824 |
0); |
||
2825 |
} |
||
2826 |
|||
2827 |
if (equipmentSprite != nullptr) |
||
2828 |
{ |
||
2829 |
equipmentSprite->setSpriteDirection(getSpriteDirection()); |
||
2830 |
startTime = getStartTime(); |
||
2831 |
lastTime = getLastTime(); |
||
2832 |
} |
||
2833 |
|||
2834 |
CompoundSprite::setSprite(slot, equipmentSprite); |
||
2835 |
mSpriteDraw[slot] = id; |
||
2836 |
|||
2837 |
addItemParticles(id, info.getDisplay()); |
||
2838 |
|||
2839 |
setAction(mAction, 0); |
||
2840 |
if (equipmentSprite != nullptr) |
||
2841 |
{ |
||
2842 |
if (lastTime > 0) |
||
2843 |
{ |
||
2844 |
equipmentSprite->setLastTime(startTime); |
||
2845 |
equipmentSprite->update(lastTime); |
||
2846 |
} |
||
2847 |
} |
||
2848 |
} |
||
2849 |
|||
2850 |
BeingSlot &beingSlot = mSlots[slot]; |
||
2851 |
beingSlot.spriteId = id; |
||
2852 |
beingSlot.color.clear(); |
||
2853 |
beingSlot.colorId = ItemColor_one; |
||
2854 |
beingSlot.cardsId = CardsList(nullptr); |
||
2855 |
recalcSpritesOrder(); |
||
2856 |
if (beingEquipmentWindow != nullptr) |
||
2857 |
beingEquipmentWindow->updateBeing(this); |
||
2858 |
} |
||
2859 |
|||
2860 |
// reset sprite id, reset colors, reset cards |
||
2861 |
void Being::unSetSprite(const unsigned int slot) restrict2 |
||
2862 |
{ |
||
2863 |
if (charServerHandler == nullptr || slot >= charServerHandler->maxSprite()) |
||
2864 |
return; |
||
2865 |
|||
2866 |
if (slot >= CAST_U32(mSprites.size())) |
||
2867 |
ensureSize(slot + 1); |
||
2868 |
|||
2869 |
if (slot >= CAST_U32(mSlots.size())) |
||
2870 |
mSlots.resize(slot + 1, BeingSlot()); |
||
2871 |
|||
2872 |
removeSprite(slot); |
||
2873 |
mSpriteDraw[slot] = 0; |
||
2874 |
|||
2875 |
BeingSlot &beingSlot = mSlots[slot]; |
||
2876 |
const int id1 = beingSlot.spriteId; |
||
2877 |
if (id1 != 0) |
||
2878 |
removeItemParticles(id1); |
||
2879 |
|||
2880 |
beingSlot.spriteId = 0; |
||
2881 |
beingSlot.color.clear(); |
||
2882 |
beingSlot.colorId = ItemColor_one; |
||
2883 |
beingSlot.cardsId = CardsList(nullptr); |
||
2884 |
recalcSpritesOrder(); |
||
2885 |
if (beingEquipmentWindow != nullptr) |
||
2886 |
beingEquipmentWindow->updateBeing(this); |
||
2887 |
} |
||
2888 |
|||
2889 |
// set sprite id, use color string, reset cards |
||
2890 |
void Being::setSpriteColor(const unsigned int slot, |
||
2891 |
const int id, |
||
2892 |
const std::string &color) restrict2 |
||
2893 |
{ |
||
2894 |
if (charServerHandler == nullptr || slot >= charServerHandler->maxSprite()) |
||
2895 |
return; |
||
2896 |
|||
2897 |
if (slot >= CAST_U32(mSprites.size())) |
||
2898 |
ensureSize(slot + 1); |
||
2899 |
|||
2900 |
if (slot >= CAST_U32(mSlots.size())) |
||
2901 |
mSlots.resize(slot + 1, BeingSlot()); |
||
2902 |
|||
2903 |
// disabled for now, because it may broke replace/reorder sprites logic |
||
2904 |
// if (slot && mSlots[slot].spriteId == id) |
||
2905 |
// return; |
||
2906 |
|||
2907 |
// id = 0 means unequip |
||
2908 |
if (id == 0) |
||
2909 |
{ |
||
2910 |
removeSprite(slot); |
||
2911 |
mSpriteDraw[slot] = 0; |
||
2912 |
|||
2913 |
const int id1 = mSlots[slot].spriteId; |
||
2914 |
if (id1 != 0) |
||
2915 |
removeItemParticles(id1); |
||
2916 |
} |
||
2917 |
else |
||
2918 |
{ |
||
2919 |
const ItemInfo &info = ItemDB::get(id); |
||
2920 |
const std::string &restrict filename = info.getSprite( |
||
2921 |
mGender, mSubType); |
||
2922 |
int lastTime = 0; |
||
2923 |
int startTime = 0; |
||
2924 |
AnimatedSprite *restrict equipmentSprite = nullptr; |
||
2925 |
|||
2926 |
if (!filename.empty()) |
||
2927 |
{ |
||
2928 |
equipmentSprite = AnimatedSprite::delayedLoad( |
||
2929 |
pathJoin(paths.getStringValue("sprites"), |
||
2930 |
combineDye(filename, color)), |
||
2931 |
0); |
||
2932 |
} |
||
2933 |
|||
2934 |
if (equipmentSprite != nullptr) |
||
2935 |
{ |
||
2936 |
equipmentSprite->setSpriteDirection(getSpriteDirection()); |
||
2937 |
startTime = getStartTime(); |
||
2938 |
lastTime = getLastTime(); |
||
2939 |
} |
||
2940 |
|||
2941 |
CompoundSprite::setSprite(slot, equipmentSprite); |
||
2942 |
mSpriteDraw[slot] = id; |
||
2943 |
addItemParticles(id, info.getDisplay()); |
||
2944 |
|||
2945 |
setAction(mAction, 0); |
||
2946 |
if (equipmentSprite != nullptr) |
||
2947 |
{ |
||
2948 |
if (lastTime > 0) |
||
2949 |
{ |
||
2950 |
equipmentSprite->setLastTime(startTime); |
||
2951 |
equipmentSprite->update(lastTime); |
||
2952 |
} |
||
2953 |
} |
||
2954 |
} |
||
2955 |
|||
2956 |
BeingSlot &beingSlot = mSlots[slot]; |
||
2957 |
beingSlot.spriteId = id; |
||
2958 |
beingSlot.color = color; |
||
2959 |
beingSlot.colorId = ItemColor_one; |
||
2960 |
beingSlot.cardsId = CardsList(nullptr); |
||
2961 |
recalcSpritesOrder(); |
||
2962 |
if (beingEquipmentWindow != nullptr) |
||
2963 |
beingEquipmentWindow->updateBeing(this); |
||
2964 |
} |
||
2965 |
|||
2966 |
// set sprite id, use color id, reset cards |
||
2967 |
void Being::setSpriteColorId(const unsigned int slot, |
||
2968 |
const int id, |
||
2969 |
ItemColor colorId) restrict2 |
||
2970 |
{ |
||
2971 |
if (charServerHandler == nullptr || slot >= charServerHandler->maxSprite()) |
||
2972 |
return; |
||
2973 |
|||
2974 |
if (slot >= CAST_U32(mSprites.size())) |
||
2975 |
ensureSize(slot + 1); |
||
2976 |
|||
2977 |
if (slot >= CAST_U32(mSlots.size())) |
||
2978 |
mSlots.resize(slot + 1, BeingSlot()); |
||
2979 |
|||
2980 |
// disabled for now, because it may broke replace/reorder sprites logic |
||
2981 |
// if (slot && mSlots[slot].spriteId == id) |
||
2982 |
// return; |
||
2983 |
|||
2984 |
std::string color; |
||
2985 |
|||
2986 |
// id = 0 means unequip |
||
2987 |
if (id == 0) |
||
2988 |
{ |
||
2989 |
removeSprite(slot); |
||
2990 |
mSpriteDraw[slot] = 0; |
||
2991 |
|||
2992 |
const int id1 = mSlots[slot].spriteId; |
||
2993 |
if (id1 != 0) |
||
2994 |
removeItemParticles(id1); |
||
2995 |
} |
||
2996 |
else |
||
2997 |
{ |
||
2998 |
const ItemInfo &info = ItemDB::get(id); |
||
2999 |
const std::string &restrict filename = info.getSprite( |
||
3000 |
mGender, mSubType); |
||
3001 |
int lastTime = 0; |
||
3002 |
int startTime = 0; |
||
3003 |
AnimatedSprite *restrict equipmentSprite = nullptr; |
||
3004 |
|||
3005 |
if (!filename.empty()) |
||
3006 |
{ |
||
3007 |
color = info.getDyeColorsString(colorId); |
||
3008 |
equipmentSprite = AnimatedSprite::delayedLoad( |
||
3009 |
pathJoin(paths.getStringValue("sprites"), |
||
3010 |
combineDye(filename, color)), |
||
3011 |
0); |
||
3012 |
} |
||
3013 |
|||
3014 |
if (equipmentSprite != nullptr) |
||
3015 |
{ |
||
3016 |
equipmentSprite->setSpriteDirection(getSpriteDirection()); |
||
3017 |
startTime = getStartTime(); |
||
3018 |
lastTime = getLastTime(); |
||
3019 |
} |
||
3020 |
|||
3021 |
CompoundSprite::setSprite(slot, equipmentSprite); |
||
3022 |
mSpriteDraw[slot] = id; |
||
3023 |
|||
3024 |
addItemParticles(id, info.getDisplay()); |
||
3025 |
|||
3026 |
setAction(mAction, 0); |
||
3027 |
if (equipmentSprite != nullptr) |
||
3028 |
{ |
||
3029 |
if (lastTime > 0) |
||
3030 |
{ |
||
3031 |
equipmentSprite->setLastTime(startTime); |
||
3032 |
equipmentSprite->update(lastTime); |
||
3033 |
} |
||
3034 |
} |
||
3035 |
} |
||
3036 |
|||
3037 |
BeingSlot &beingSlot = mSlots[slot]; |
||
3038 |
beingSlot.spriteId = id; |
||
3039 |
beingSlot.color = STD_MOVE(color); |
||
3040 |
beingSlot.colorId = colorId; |
||
3041 |
beingSlot.cardsId = CardsList(nullptr); |
||
3042 |
recalcSpritesOrder(); |
||
3043 |
if (beingEquipmentWindow != nullptr) |
||
3044 |
beingEquipmentWindow->updateBeing(this); |
||
3045 |
} |
||
3046 |
|||
3047 |
// set sprite id, colors from cards, cards |
||
3048 |
void Being::setSpriteCards(const unsigned int slot, |
||
3049 |
const int id, |
||
3050 |
const CardsList &cards) restrict2 |
||
3051 |
{ |
||
3052 |
if (charServerHandler == nullptr || slot >= charServerHandler->maxSprite()) |
||
3053 |
return; |
||
3054 |
|||
3055 |
if (slot >= CAST_U32(mSprites.size())) |
||
3056 |
ensureSize(slot + 1); |
||
3057 |
|||
3058 |
if (slot >= CAST_U32(mSlots.size())) |
||
3059 |
mSlots.resize(slot + 1, BeingSlot()); |
||
3060 |
|||
3061 |
// disabled for now, because it may broke replace/reorder sprites logic |
||
3062 |
// if (slot && mSlots[slot].spriteId == id) |
||
3063 |
// return; |
||
3064 |
|||
3065 |
ItemColor colorId = ItemColor_one; |
||
3066 |
std::string color; |
||
3067 |
|||
3068 |
// id = 0 means unequip |
||
3069 |
if (id == 0) |
||
3070 |
{ |
||
3071 |
removeSprite(slot); |
||
3072 |
mSpriteDraw[slot] = 0; |
||
3073 |
|||
3074 |
const int id1 = mSlots[slot].spriteId; |
||
3075 |
if (id1 != 0) |
||
3076 |
removeItemParticles(id1); |
||
3077 |
} |
||
3078 |
else |
||
3079 |
{ |
||
3080 |
const ItemInfo &info = ItemDB::get(id); |
||
3081 |
const std::string &restrict filename = info.getSprite( |
||
3082 |
mGender, mSubType); |
||
3083 |
int lastTime = 0; |
||
3084 |
int startTime = 0; |
||
3085 |
AnimatedSprite *restrict equipmentSprite = nullptr; |
||
3086 |
|||
3087 |
if (!cards.isEmpty()) |
||
3088 |
colorId = ItemColorManager::getColorFromCards(cards); |
||
3089 |
|||
3090 |
if (!filename.empty()) |
||
3091 |
{ |
||
3092 |
color = info.getDyeColorsString(colorId); |
||
3093 |
|||
3094 |
equipmentSprite = AnimatedSprite::delayedLoad( |
||
3095 |
pathJoin(paths.getStringValue("sprites"), |
||
3096 |
combineDye(filename, color)), |
||
3097 |
0); |
||
3098 |
} |
||
3099 |
|||
3100 |
if (equipmentSprite != nullptr) |
||
3101 |
{ |
||
3102 |
equipmentSprite->setSpriteDirection(getSpriteDirection()); |
||
3103 |
startTime = getStartTime(); |
||
3104 |
lastTime = getLastTime(); |
||
3105 |
} |
||
3106 |
|||
3107 |
CompoundSprite::setSprite(slot, equipmentSprite); |
||
3108 |
mSpriteDraw[slot] = id; |
||
3109 |
|||
3110 |
addItemParticlesCards(id, |
||
3111 |
info.getDisplay(), |
||
3112 |
cards); |
||
3113 |
|||
3114 |
setAction(mAction, 0); |
||
3115 |
if (equipmentSprite != nullptr) |
||
3116 |
{ |
||
3117 |
if (lastTime > 0) |
||
3118 |
{ |
||
3119 |
equipmentSprite->setLastTime(startTime); |
||
3120 |
equipmentSprite->update(lastTime); |
||
3121 |
} |
||
3122 |
} |
||
3123 |
} |
||
3124 |
|||
3125 |
BeingSlot &beingSlot = mSlots[slot]; |
||
3126 |
beingSlot.spriteId = id; |
||
3127 |
beingSlot.color = STD_MOVE(color); |
||
3128 |
beingSlot.colorId = colorId; |
||
3129 |
beingSlot.cardsId = CardsList(cards); |
||
3130 |
recalcSpritesOrder(); |
||
3131 |
if (beingEquipmentWindow != nullptr) |
||
3132 |
beingEquipmentWindow->updateBeing(this); |
||
3133 |
} |
||
3134 |
|||
3135 |
void Being::setWeaponId(const int id) restrict2 |
||
3136 |
{ |
||
3137 |
if (id == 0) |
||
3138 |
mEquippedWeapon = nullptr; |
||
3139 |
else |
||
3140 |
mEquippedWeapon = &ItemDB::get(id); |
||
3141 |
} |
||
3142 |
|||
3143 |
void Being::setTempSprite(const unsigned int slot, |
||
3144 |
const int id) restrict2 |
||
3145 |
{ |
||
3146 |
if (charServerHandler == nullptr || slot >= charServerHandler->maxSprite()) |
||
3147 |
return; |
||
3148 |
|||
3149 |
if (slot >= CAST_U32(mSprites.size())) |
||
3150 |
ensureSize(slot + 1); |
||
3151 |
|||
3152 |
if (slot >= CAST_U32(mSlots.size())) |
||
3153 |
mSlots.resize(slot + 1, BeingSlot()); |
||
3154 |
|||
3155 |
BeingSlot &beingSlot = mSlots[slot]; |
||
3156 |
|||
3157 |
// id = 0 means unequip |
||
3158 |
if (id == 0) |
||
3159 |
{ |
||
3160 |
removeSprite(slot); |
||
3161 |
mSpriteDraw[slot] = 0; |
||
3162 |
|||
3163 |
const int id1 = beingSlot.spriteId; |
||
3164 |
if (id1 != 0) |
||
3165 |
removeItemParticles(id1); |
||
3166 |
} |
||
3167 |
else |
||
3168 |
{ |
||
3169 |
const ItemInfo &info = ItemDB::get(id); |
||
3170 |
const std::string &restrict filename = info.getSprite( |
||
3171 |
mGender, mSubType); |
||
3172 |
int lastTime = 0; |
||
3173 |
int startTime = 0; |
||
3174 |
|||
3175 |
AnimatedSprite *restrict equipmentSprite = nullptr; |
||
3176 |
|||
3177 |
if (!filename.empty()) |
||
3178 |
{ |
||
3179 |
ItemColor colorId = ItemColor_one; |
||
3180 |
const CardsList &cards = beingSlot.cardsId; |
||
3181 |
if (!cards.isEmpty()) |
||
3182 |
colorId = ItemColorManager::getColorFromCards(cards); |
||
3183 |
std::string color = beingSlot.color; |
||
3184 |
if (color.empty()) |
||
3185 |
color = info.getDyeColorsString(colorId); |
||
3186 |
|||
3187 |
equipmentSprite = AnimatedSprite::delayedLoad( |
||
3188 |
pathJoin(paths.getStringValue("sprites"), |
||
3189 |
combineDye(filename, color)), |
||
3190 |
0); |
||
3191 |
} |
||
3192 |
|||
3193 |
if (equipmentSprite != nullptr) |
||
3194 |
{ |
||
3195 |
equipmentSprite->setSpriteDirection(getSpriteDirection()); |
||
3196 |
startTime = getStartTime(); |
||
3197 |
lastTime = getLastTime(); |
||
3198 |
} |
||
3199 |
|||
3200 |
CompoundSprite::setSprite(slot, equipmentSprite); |
||
3201 |
mSpriteDraw[slot] = id; |
||
3202 |
|||
3203 |
// +++ here probably need use existing cards |
||
3204 |
addItemParticles(id, info.getDisplay()); |
||
3205 |
|||
3206 |
setAction(mAction, 0); |
||
3207 |
if (equipmentSprite != nullptr) |
||
3208 |
{ |
||
3209 |
if (lastTime > 0) |
||
3210 |
{ |
||
3211 |
equipmentSprite->setLastTime(startTime); |
||
3212 |
equipmentSprite->update(lastTime); |
||
3213 |
} |
||
3214 |
} |
||
3215 |
} |
||
3216 |
} |
||
3217 |
|||
3218 |
void Being::setHairTempSprite(const unsigned int slot, |
||
3219 |
const int id) restrict2 |
||
3220 |
{ |
||
3221 |
if (charServerHandler == nullptr || slot >= charServerHandler->maxSprite()) |
||
3222 |
return; |
||
3223 |
|||
3224 |
if (slot >= CAST_U32(mSprites.size())) |
||
3225 |
ensureSize(slot + 1); |
||
3226 |
|||
3227 |
if (slot >= CAST_U32(mSlots.size())) |
||
3228 |
mSlots.resize(slot + 1, BeingSlot()); |
||
3229 |
|||
3230 |
const CardsList &cards = mSlots[slot].cardsId; |
||
3231 |
|||
3232 |
// id = 0 means unequip |
||
3233 |
if (id == 0) |
||
3234 |
{ |
||
3235 |
removeSprite(slot); |
||
3236 |
mSpriteDraw[slot] = 0; |
||
3237 |
|||
3238 |
const int id1 = mSlots[slot].spriteId; |
||
3239 |
if (id1 != 0) |
||
3240 |
removeItemParticles(id1); |
||
3241 |
} |
||
3242 |
else |
||
3243 |
{ |
||
3244 |
const ItemInfo &info = ItemDB::get(id); |
||
3245 |
const std::string &restrict filename = info.getSprite( |
||
3246 |
mGender, mSubType); |
||
3247 |
int lastTime = 0; |
||
3248 |
int startTime = 0; |
||
3249 |
AnimatedSprite *restrict equipmentSprite = nullptr; |
||
3250 |
|||
3251 |
if (!filename.empty()) |
||
3252 |
{ |
||
3253 |
ItemColor colorId = ItemColor_one; |
||
3254 |
if (!cards.isEmpty()) |
||
3255 |
colorId = ItemColorManager::getColorFromCards(cards); |
||
3256 |
|||
3257 |
std::string color = info.getDyeColorsString(mHairColor); |
||
3258 |
if (color.empty()) |
||
3259 |
color = info.getDyeColorsString(colorId); |
||
3260 |
|||
3261 |
equipmentSprite = AnimatedSprite::delayedLoad( |
||
3262 |
pathJoin(paths.getStringValue("sprites"), |
||
3263 |
combineDye(filename, color)), |
||
3264 |
0); |
||
3265 |
} |
||
3266 |
|||
3267 |
if (equipmentSprite != nullptr) |
||
3268 |
{ |
||
3269 |
equipmentSprite->setSpriteDirection(getSpriteDirection()); |
||
3270 |
startTime = getStartTime(); |
||
3271 |
lastTime = getLastTime(); |
||
3272 |
} |
||
3273 |
|||
3274 |
CompoundSprite::setSprite(slot, equipmentSprite); |
||
3275 |
mSpriteDraw[slot] = id; |
||
3276 |
|||
3277 |
addItemParticles(id, info.getDisplay()); |
||
3278 |
|||
3279 |
setAction(mAction, 0); |
||
3280 |
if (equipmentSprite != nullptr) |
||
3281 |
{ |
||
3282 |
if (lastTime > 0) |
||
3283 |
{ |
||
3284 |
equipmentSprite->setLastTime(startTime); |
||
3285 |
equipmentSprite->update(lastTime); |
||
3286 |
} |
||
3287 |
} |
||
3288 |
} |
||
3289 |
} |
||
3290 |
|||
3291 |
void Being::setHairColorSpriteID(const unsigned int slot, |
||
3292 |
const int id) restrict2 |
||
3293 |
{ |
||
3294 |
if (charServerHandler == nullptr || slot >= charServerHandler->maxSprite()) |
||
3295 |
return; |
||
3296 |
|||
3297 |
if (slot >= CAST_U32(mSprites.size())) |
||
3298 |
ensureSize(slot + 1); |
||
3299 |
|||
3300 |
if (slot >= CAST_U32(mSlots.size())) |
||
3301 |
mSlots.resize(slot + 1, BeingSlot()); |
||
3302 |
|||
3303 |
BeingSlot &beingSlot = mSlots[slot]; |
||
3304 |
setSpriteColor(slot, |
||
3305 |
id, |
||
3306 |
beingSlot.color); |
||
3307 |
} |
||
3308 |
|||
3309 |
void Being::setSpriteColor(const unsigned int slot, |
||
3310 |
const std::string &restrict color) restrict2 |
||
3311 |
{ |
||
3312 |
if (charServerHandler == nullptr || slot >= charServerHandler->maxSprite()) |
||
3313 |
return; |
||
3314 |
|||
3315 |
if (slot >= CAST_U32(mSprites.size())) |
||
3316 |
ensureSize(slot + 1); |
||
3317 |
|||
3318 |
if (slot >= CAST_U32(mSlots.size())) |
||
3319 |
mSlots.resize(slot + 1, BeingSlot()); |
||
3320 |
|||
3321 |
// disabled for now, because it may broke replace/reorder sprites logic |
||
3322 |
// if (slot && mSlots[slot].spriteId == id) |
||
3323 |
// return; |
||
3324 |
|||
3325 |
BeingSlot &beingSlot = mSlots[slot]; |
||
3326 |
const int id = beingSlot.spriteId; |
||
3327 |
|||
3328 |
// id = 0 means unequip |
||
3329 |
if (id != 0) |
||
3330 |
{ |
||
3331 |
const ItemInfo &info = ItemDB::get(id); |
||
3332 |
const std::string &restrict filename = info.getSprite( |
||
3333 |
mGender, mSubType); |
||
3334 |
int lastTime = 0; |
||
3335 |
int startTime = 0; |
||
3336 |
AnimatedSprite *restrict equipmentSprite = nullptr; |
||
3337 |
|||
3338 |
if (!filename.empty()) |
||
3339 |
{ |
||
3340 |
equipmentSprite = AnimatedSprite::delayedLoad( |
||
3341 |
pathJoin(paths.getStringValue("sprites"), |
||
3342 |
combineDye(filename, color)), |
||
3343 |
0); |
||
3344 |
} |
||
3345 |
|||
3346 |
if (equipmentSprite != nullptr) |
||
3347 |
{ |
||
3348 |
equipmentSprite->setSpriteDirection(getSpriteDirection()); |
||
3349 |
startTime = getStartTime(); |
||
3350 |
lastTime = getLastTime(); |
||
3351 |
} |
||
3352 |
|||
3353 |
CompoundSprite::setSprite(slot, equipmentSprite); |
||
3354 |
|||
3355 |
setAction(mAction, 0); |
||
3356 |
if (equipmentSprite != nullptr) |
||
3357 |
{ |
||
3358 |
if (lastTime > 0) |
||
3359 |
{ |
||
3360 |
equipmentSprite->setLastTime(startTime); |
||
3361 |
equipmentSprite->update(lastTime); |
||
3362 |
} |
||
3363 |
} |
||
3364 |
} |
||
3365 |
|||
3366 |
beingSlot.color = color; |
||
3367 |
beingSlot.colorId = ItemColor_one; |
||
3368 |
if (beingEquipmentWindow != nullptr) |
||
3369 |
beingEquipmentWindow->updateBeing(this); |
||
3370 |
} |
||
3371 |
|||
3372 |
void Being::setHairStyle(const unsigned int slot, |
||
3373 |
const int id) restrict2 |
||
3374 |
{ |
||
3375 |
if (id != 0) |
||
3376 |
{ |
||
3377 |
setSpriteColor(slot, |
||
3378 |
id, |
||
3379 |
ItemDB::get(id).getDyeColorsString(mHairColor)); |
||
3380 |
} |
||
3381 |
else |
||
3382 |
{ |
||
3383 |
setSpriteColor(slot, |
||
3384 |
0, |
||
3385 |
std::string()); |
||
3386 |
} |
||
3387 |
} |
||
3388 |
|||
3389 |
void Being::setHairColor(const unsigned int slot, |
||
3390 |
const ItemColor color) restrict2 |
||
3391 |
{ |
||
3392 |
mHairColor = color; |
||
3393 |
BeingSlot &beingSlot = mSlots[slot]; |
||
3394 |
const int id = beingSlot.spriteId; |
||
3395 |
if (id != 0) |
||
3396 |
{ |
||
3397 |
setSpriteColor(slot, |
||
3398 |
id, |
||
3399 |
ItemDB::get(id).getDyeColorsString(color)); |
||
3400 |
} |
||
3401 |
} |
||
3402 |
|||
3403 |
void Being::setSpriteSlot(const unsigned int slot, |
||
3404 |
const BeingSlot &beingSlot) |
||
3405 |
{ |
||
3406 |
mSlots[slot] = beingSlot; |
||
3407 |
} |
||
3408 |
|||
3409 |
void Being::dumpSprites() const restrict2 |
||
3410 |
{ |
||
3411 |
STD_VECTOR<BeingSlot>::const_iterator it1 = mSlots.begin(); |
||
3412 |
const STD_VECTOR<BeingSlot>::const_iterator it1_end = mSlots.end(); |
||
3413 |
|||
3414 |
logger->log("sprites"); |
||
3415 |
for (; it1 != it1_end; |
||
3416 |
++ it1) |
||
3417 |
{ |
||
3418 |
logger->log("%d,%s,%d", |
||
3419 |
(*it1).spriteId, |
||
3420 |
(*it1).color.c_str(), |
||
3421 |
toInt((*it1).colorId, int)); |
||
3422 |
} |
||
3423 |
} |
||
3424 |
|||
3425 |
4 |
void Being::updateName() restrict2 |
|
3426 |
{ |
||
3427 |
✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✓✓✗✗ |
4 |
if (mShowName) |
3428 |
2 |
showName(); |
|
3429 |
4 |
} |
|
3430 |
|||
3431 |
103 |
void Being::reReadConfig() |
|
3432 |
{ |
||
3433 |
BLOCK_START("Being::reReadConfig") |
||
3434 |
✗✓ | 103 |
if (mUpdateConfigTime + 1 < cur_time) |
3435 |
{ |
||
3436 |
mAwayEffect = paths.getIntValue("afkEffectId"); |
||
3437 |
mHighlightMapPortals = config.getBoolValue("highlightMapPortals"); |
||
3438 |
mConfLineLim = config.getIntValue("chatMaxCharLimit"); |
||
3439 |
mSpeechType = config.getIntValue("speech"); |
||
3440 |
mHighlightMonsterAttackRange = |
||
3441 |
config.getBoolValue("highlightMonsterAttackRange"); |
||
3442 |
mLowTraffic = config.getBoolValue("lowTraffic"); |
||
3443 |
mDrawHotKeys = config.getBoolValue("drawHotKeys"); |
||
3444 |
mShowBattleEvents = config.getBoolValue("showBattleEvents"); |
||
3445 |
mShowMobHP = config.getBoolValue("showMobHP"); |
||
3446 |
mShowOwnHP = config.getBoolValue("showOwnHP"); |
||
3447 |
mShowGender = config.getBoolValue("showgender"); |
||
3448 |
mShowLevel = config.getBoolValue("showlevel"); |
||
3449 |
mShowPlayersStatus = config.getBoolValue("showPlayersStatus"); |
||
3450 |
mEnableReorderSprites = config.getBoolValue("enableReorderSprites"); |
||
3451 |
mHideErased = config.getBoolValue("hideErased"); |
||
3452 |
mMoveNames = fromBool(config.getBoolValue("moveNames"), Move); |
||
3453 |
mUseDiagonal = config.getBoolValue("useDiagonalSpeed"); |
||
3454 |
mShowBadges = static_cast<BadgeDrawType::Type>( |
||
3455 |
config.getIntValue("showBadges")); |
||
3456 |
mVisibleNamePos = static_cast<VisibleNamePos::Type>( |
||
3457 |
config.getIntValue("visiblenamespos")); |
||
3458 |
|||
3459 |
mUpdateConfigTime = cur_time; |
||
3460 |
} |
||
3461 |
BLOCK_END("Being::reReadConfig") |
||
3462 |
103 |
} |
|
3463 |
|||
3464 |
bool Being::updateFromCache() restrict2 |
||
3465 |
{ |
||
3466 |
const BeingCacheEntry *restrict const entry = |
||
3467 |
Being::getCacheEntry(getId()); |
||
3468 |
|||
3469 |
if ((entry != nullptr) && entry->getTime() + 120 >= cur_time) |
||
3470 |
{ |
||
3471 |
if (!entry->getName().empty()) |
||
3472 |
setName(entry->getName()); |
||
3473 |
setPartyName(entry->getPartyName()); |
||
3474 |
setGuildName(entry->getGuildName()); |
||
3475 |
setLevel(entry->getLevel()); |
||
3476 |
setPvpRank(entry->getPvpRank()); |
||
3477 |
setIp(entry->getIp()); |
||
3478 |
setTeamId(entry->getTeamId()); |
||
3479 |
|||
3480 |
mAdvanced = entry->isAdvanced(); |
||
3481 |
if (mAdvanced) |
||
3482 |
{ |
||
3483 |
const int flags = entry->getFlags(); |
||
3484 |
if ((serverFeatures != nullptr) && |
||
3485 |
Net::getNetworkType() == ServerType::TMWATHENA) |
||
3486 |
{ |
||
3487 |
mShop = ((flags & BeingFlag::SHOP) != 0); |
||
3488 |
} |
||
3489 |
mAway = ((flags & BeingFlag::AWAY) != 0); |
||
3490 |
mInactive = ((flags & BeingFlag::INACTIVE) != 0); |
||
3491 |
if (mShop || mAway || mInactive) |
||
3492 |
updateName(); |
||
3493 |
} |
||
3494 |
else |
||
3495 |
{ |
||
3496 |
if (Net::getNetworkType() == ServerType::TMWATHENA) |
||
3497 |
mShop = false; |
||
3498 |
mAway = false; |
||
3499 |
mInactive = false; |
||
3500 |
} |
||
3501 |
|||
3502 |
showShopBadge(mShop); |
||
3503 |
showInactiveBadge(mInactive); |
||
3504 |
showAwayBadge(mAway); |
||
3505 |
updateAwayEffect(); |
||
3506 |
if (mType == ActorType::Player || (mTeamId != 0U)) |
||
3507 |
updateColors(); |
||
3508 |
return true; |
||
3509 |
} |
||
3510 |
return false; |
||
3511 |
} |
||
3512 |
|||
3513 |
void Being::addToCache() const restrict2 |
||
3514 |
{ |
||
3515 |
if (localPlayer == this) |
||
3516 |
return; |
||
3517 |
|||
3518 |
BeingCacheEntry *entry = Being::getCacheEntry(getId()); |
||
3519 |
if (entry == nullptr) |
||
3520 |
{ |
||
3521 |
entry = new BeingCacheEntry(getId()); |
||
3522 |
beingInfoCache.push_front(entry); |
||
3523 |
|||
3524 |
if (beingInfoCache.size() >= CACHE_SIZE) |
||
3525 |
{ |
||
3526 |
delete beingInfoCache.back(); |
||
3527 |
beingInfoCache.pop_back(); |
||
3528 |
} |
||
3529 |
} |
||
3530 |
if (!mLowTraffic) |
||
3531 |
return; |
||
3532 |
|||
3533 |
entry->setName(mName); |
||
3534 |
entry->setLevel(getLevel()); |
||
3535 |
entry->setPartyName(getPartyName()); |
||
3536 |
entry->setGuildName(getGuildName()); |
||
3537 |
entry->setTime(cur_time); |
||
3538 |
entry->setPvpRank(getPvpRank()); |
||
3539 |
entry->setIp(getIp()); |
||
3540 |
entry->setAdvanced(isAdvanced()); |
||
3541 |
entry->setTeamId(getTeamId()); |
||
3542 |
if (isAdvanced()) |
||
3543 |
{ |
||
3544 |
int flags = 0; |
||
3545 |
if (Net::getNetworkType() == ServerType::TMWATHENA && mShop) |
||
3546 |
flags += BeingFlag::SHOP; |
||
3547 |
if (mAway) |
||
3548 |
flags += BeingFlag::AWAY; |
||
3549 |
if (mInactive) |
||
3550 |
flags += BeingFlag::INACTIVE; |
||
3551 |
entry->setFlags(flags); |
||
3552 |
} |
||
3553 |
else |
||
3554 |
{ |
||
3555 |
entry->setFlags(0); |
||
3556 |
} |
||
3557 |
} |
||
3558 |
|||
3559 |
BeingCacheEntry* Being::getCacheEntry(const BeingId id) |
||
3560 |
{ |
||
3561 |
FOR_EACH (std::list<BeingCacheEntry*>::iterator, i, beingInfoCache) |
||
3562 |
{ |
||
3563 |
if (*i == nullptr) |
||
3564 |
continue; |
||
3565 |
|||
3566 |
if (id == (*i)->getId()) |
||
3567 |
{ |
||
3568 |
// Raise priority: move it to front |
||
3569 |
if ((*i)->getTime() + 120 < cur_time) |
||
3570 |
{ |
||
3571 |
beingInfoCache.splice(beingInfoCache.begin(), |
||
3572 |
beingInfoCache, i); |
||
3573 |
} |
||
3574 |
return *i; |
||
3575 |
} |
||
3576 |
} |
||
3577 |
return nullptr; |
||
3578 |
} |
||
3579 |
|||
3580 |
|||
3581 |
void Being::setGender(const GenderT gender) restrict2 |
||
3582 |
{ |
||
3583 |
if (charServerHandler == nullptr) |
||
3584 |
return; |
||
3585 |
|||
3586 |
if (gender != mGender) |
||
3587 |
{ |
||
3588 |
mGender = gender; |
||
3589 |
|||
3590 |
const unsigned int sz = CAST_U32(mSlots.size()); |
||
3591 |
|||
3592 |
if (sz > CAST_U32(mSprites.size())) |
||
3593 |
ensureSize(sz); |
||
3594 |
|||
3595 |
// Reload all subsprites |
||
3596 |
for (unsigned int i = 0; |
||
3597 |
i < sz; |
||
3598 |
i++) |
||
3599 |
{ |
||
3600 |
BeingSlot &beingSlot = mSlots[i]; |
||
3601 |
const int id = beingSlot.spriteId; |
||
3602 |
if (id != 0) |
||
3603 |
{ |
||
3604 |
const ItemInfo &info = ItemDB::get(id); |
||
3605 |
const std::string &restrict filename = info.getSprite( |
||
3606 |
mGender, mSubType); |
||
3607 |
int lastTime = 0; |
||
3608 |
int startTime = 0; |
||
3609 |
AnimatedSprite *restrict equipmentSprite = nullptr; |
||
3610 |
|||
3611 |
if (!filename.empty()) |
||
3612 |
{ |
||
3613 |
equipmentSprite = AnimatedSprite::delayedLoad( |
||
3614 |
pathJoin(paths.getStringValue("sprites"), |
||
3615 |
combineDye(filename, beingSlot.color)), |
||
3616 |
0); |
||
3617 |
} |
||
3618 |
|||
3619 |
if (equipmentSprite != nullptr) |
||
3620 |
{ |
||
3621 |
equipmentSprite->setSpriteDirection(getSpriteDirection()); |
||
3622 |
startTime = getStartTime(); |
||
3623 |
lastTime = getLastTime(); |
||
3624 |
} |
||
3625 |
|||
3626 |
CompoundSprite::setSprite(i, equipmentSprite); |
||
3627 |
setAction(mAction, 0); |
||
3628 |
if (equipmentSprite != nullptr) |
||
3629 |
{ |
||
3630 |
if (lastTime > 0) |
||
3631 |
{ |
||
3632 |
equipmentSprite->setLastTime(startTime); |
||
3633 |
equipmentSprite->update(lastTime); |
||
3634 |
} |
||
3635 |
} |
||
3636 |
|||
3637 |
if (beingEquipmentWindow != nullptr) |
||
3638 |
beingEquipmentWindow->updateBeing(this); |
||
3639 |
} |
||
3640 |
} |
||
3641 |
|||
3642 |
updateName(); |
||
3643 |
} |
||
3644 |
} |
||
3645 |
|||
3646 |
void Being::showGmBadge(const bool show) restrict2 |
||
3647 |
{ |
||
3648 |
delete2(mBadges[BadgeIndex::Gm]) |
||
3649 |
if (show && |
||
3650 |
mIsGM && |
||
3651 |
mShowBadges != BadgeDrawType::Hide && |
||
3652 |
GroupDb::getShowBadge(mGroupId)) |
||
3653 |
{ |
||
3654 |
const std::string &gmBadge = GroupDb::getBadge(mGroupId); |
||
3655 |
if (!gmBadge.empty()) |
||
3656 |
{ |
||
3657 |
mBadges[BadgeIndex::Gm] = AnimatedSprite::load( |
||
3658 |
paths.getStringValue("badges") + gmBadge, |
||
3659 |
0); |
||
3660 |
} |
||
3661 |
} |
||
3662 |
updateBadgesCount(); |
||
3663 |
updateBadgesPosition(); |
||
3664 |
} |
||
3665 |
|||
3666 |
void Being::setGM(const bool gm) restrict2 |
||
3667 |
{ |
||
3668 |
if (mIsGM != gm) |
||
3669 |
{ |
||
3670 |
mIsGM = gm; |
||
3671 |
updateColors(); |
||
3672 |
} |
||
3673 |
} |
||
3674 |
|||
3675 |
void Being::talkTo() const restrict2 |
||
3676 |
{ |
||
3677 |
if (npcHandler == nullptr) |
||
3678 |
return; |
||
3679 |
|||
3680 |
if (!PacketLimiter::limitPackets(PacketType::PACKET_NPC_TALK)) |
||
3681 |
{ |
||
3682 |
// using workaround... |
||
3683 |
if ((playerHandler != nullptr) && |
||
3684 |
PacketLimiter::limitPackets(PacketType::PACKET_ATTACK)) |
||
3685 |
{ |
||
3686 |
playerHandler->attack(mId, Keep_false); |
||
3687 |
} |
||
3688 |
return; |
||
3689 |
} |
||
3690 |
|||
3691 |
npcHandler->talk(this); |
||
3692 |
} |
||
3693 |
|||
3694 |
void Being::drawPlayer(Graphics *restrict const graphics, |
||
3695 |
const int offsetX, |
||
3696 |
const int offsetY) const restrict2 |
||
3697 |
{ |
||
3698 |
if (!mErased) |
||
3699 |
{ |
||
3700 |
// getActorX() + offsetX; |
||
3701 |
const int px = mPixelX - mapTileSize / 2 + offsetX; |
||
3702 |
// getActorY() + offsetY; |
||
3703 |
const int py = mPixelY - mapTileSize + offsetY; |
||
3704 |
if (mHorseInfo != nullptr) |
||
3705 |
{ |
||
3706 |
HorseOffset &offset = mHorseInfo->offsets[mSpriteDirection]; |
||
3707 |
for_each_horses(mDownHorseSprites) |
||
3708 |
{ |
||
3709 |
(*it)->draw(graphics, |
||
3710 |
px + offset.downOffsetX, |
||
3711 |
py + offset.downOffsetY); |
||
3712 |
} |
||
3713 |
|||
3714 |
drawBeingCursor(graphics, px, py); |
||
3715 |
drawPlayerSpriteAt(graphics, |
||
3716 |
px + offset.riderOffsetX, |
||
3717 |
py + offset.riderOffsetY); |
||
3718 |
|||
3719 |
for_each_horses(mUpHorseSprites) |
||
3720 |
{ |
||
3721 |
(*it)->draw(graphics, |
||
3722 |
px + offset.upOffsetX, |
||
3723 |
py + offset.upOffsetY); |
||
3724 |
} |
||
3725 |
} |
||
3726 |
else |
||
3727 |
{ |
||
3728 |
drawBeingCursor(graphics, px, py); |
||
3729 |
drawPlayerSpriteAt(graphics, px, py); |
||
3730 |
} |
||
3731 |
} |
||
3732 |
} |
||
3733 |
|||
3734 |
void Being::drawBeingCursor(Graphics *const graphics, |
||
3735 |
const int offsetX, |
||
3736 |
const int offsetY) const |
||
3737 |
{ |
||
3738 |
if (mUsedTargetCursor != nullptr) |
||
3739 |
{ |
||
3740 |
mUsedTargetCursor->update(tick_time * MILLISECONDS_IN_A_TICK); |
||
3741 |
if (mInfo == nullptr) |
||
3742 |
{ |
||
3743 |
mUsedTargetCursor->draw(graphics, |
||
3744 |
offsetX - mCursorPaddingX, |
||
3745 |
offsetY - mCursorPaddingY); |
||
3746 |
} |
||
3747 |
else |
||
3748 |
{ |
||
3749 |
mUsedTargetCursor->draw(graphics, |
||
3750 |
offsetX + mInfo->getTargetOffsetX() - mCursorPaddingX, |
||
3751 |
offsetY + mInfo->getTargetOffsetY() - mCursorPaddingY); |
||
3752 |
} |
||
3753 |
} |
||
3754 |
} |
||
3755 |
|||
3756 |
void Being::drawOther(Graphics *restrict const graphics, |
||
3757 |
const int offsetX, |
||
3758 |
const int offsetY) const restrict2 |
||
3759 |
{ |
||
3760 |
// getActorX() + offsetX; |
||
3761 |
const int px = mPixelX - mapTileSize / 2 + offsetX; |
||
3762 |
// getActorY() + offsetY; |
||
3763 |
const int py = mPixelY - mapTileSize + offsetY; |
||
3764 |
drawBeingCursor(graphics, px, py); |
||
3765 |
drawOtherSpriteAt(graphics, px, py); |
||
3766 |
} |
||
3767 |
|||
3768 |
void Being::drawNpc(Graphics *restrict const graphics, |
||
3769 |
const int offsetX, |
||
3770 |
const int offsetY) const restrict2 |
||
3771 |
{ |
||
3772 |
// getActorX() + offsetX; |
||
3773 |
const int px = mPixelX - mapTileSize / 2 + offsetX; |
||
3774 |
// getActorY() + offsetY; |
||
3775 |
const int py = mPixelY - mapTileSize + offsetY; |
||
3776 |
drawBeingCursor(graphics, px, py); |
||
3777 |
drawNpcSpriteAt(graphics, px, py); |
||
3778 |
} |
||
3779 |
|||
3780 |
void Being::drawMonster(Graphics *restrict const graphics, |
||
3781 |
const int offsetX, |
||
3782 |
const int offsetY) const restrict2 |
||
3783 |
{ |
||
3784 |
// getActorX() + offsetX; |
||
3785 |
const int px = mPixelX - mapTileSize / 2 + offsetX; |
||
3786 |
// getActorY() + offsetY; |
||
3787 |
const int py = mPixelY - mapTileSize + offsetY; |
||
3788 |
drawBeingCursor(graphics, px, py); |
||
3789 |
drawMonsterSpriteAt(graphics, px, py); |
||
3790 |
} |
||
3791 |
|||
3792 |
void Being::drawHomunculus(Graphics *restrict const graphics, |
||
3793 |
const int offsetX, |
||
3794 |
const int offsetY) const restrict2 |
||
3795 |
{ |
||
3796 |
// getActorX() + offsetX; |
||
3797 |
const int px = mPixelX - mapTileSize / 2 + offsetX; |
||
3798 |
// getActorY() + offsetY; |
||
3799 |
const int py = mPixelY - mapTileSize + offsetY; |
||
3800 |
drawBeingCursor(graphics, px, py); |
||
3801 |
drawHomunculusSpriteAt(graphics, px, py); |
||
3802 |
} |
||
3803 |
|||
3804 |
void Being::drawMercenary(Graphics *restrict const graphics, |
||
3805 |
const int offsetX, |
||
3806 |
const int offsetY) const restrict2 |
||
3807 |
{ |
||
3808 |
// getActorX() + offsetX; |
||
3809 |
const int px = mPixelX - mapTileSize / 2 + offsetX; |
||
3810 |
// getActorY() + offsetY; |
||
3811 |
const int py = mPixelY - mapTileSize + offsetY; |
||
3812 |
drawBeingCursor(graphics, px, py); |
||
3813 |
drawMercenarySpriteAt(graphics, px, py); |
||
3814 |
} |
||
3815 |
|||
3816 |
void Being::drawElemental(Graphics *restrict const graphics, |
||
3817 |
const int offsetX, |
||
3818 |
const int offsetY) const restrict2 |
||
3819 |
{ |
||
3820 |
// getActorX() + offsetX; |
||
3821 |
const int px = mPixelX - mapTileSize / 2 + offsetX; |
||
3822 |
// getActorY() + offsetY; |
||
3823 |
const int py = mPixelY - mapTileSize + offsetY; |
||
3824 |
drawBeingCursor(graphics, px, py); |
||
3825 |
drawElementalSpriteAt(graphics, px, py); |
||
3826 |
} |
||
3827 |
|||
3828 |
void Being::drawPortal(Graphics *restrict const graphics, |
||
3829 |
const int offsetX, |
||
3830 |
const int offsetY) const restrict2 |
||
3831 |
{ |
||
3832 |
// getActorX() + offsetX; |
||
3833 |
const int px = mPixelX - mapTileSize / 2 + offsetX; |
||
3834 |
// getActorY() + offsetY; |
||
3835 |
const int py = mPixelY - mapTileSize + offsetY; |
||
3836 |
drawPortalSpriteAt(graphics, px, py); |
||
3837 |
} |
||
3838 |
|||
3839 |
void Being::draw(Graphics *restrict const graphics, |
||
3840 |
const int offsetX, |
||
3841 |
const int offsetY) const restrict2 |
||
3842 |
{ |
||
3843 |
switch (mType) |
||
3844 |
{ |
||
3845 |
case ActorType::Player: |
||
3846 |
drawPlayer(graphics, |
||
3847 |
offsetX, |
||
3848 |
offsetY); |
||
3849 |
break; |
||
3850 |
case ActorType::Portal: |
||
3851 |
drawPortal(graphics, |
||
3852 |
offsetX, |
||
3853 |
offsetY); |
||
3854 |
break; |
||
3855 |
case ActorType::Homunculus: |
||
3856 |
drawHomunculus(graphics, |
||
3857 |
offsetX, |
||
3858 |
offsetY); |
||
3859 |
break; |
||
3860 |
case ActorType::Mercenary: |
||
3861 |
drawMercenary(graphics, |
||
3862 |
offsetX, |
||
3863 |
offsetY); |
||
3864 |
break; |
||
3865 |
case ActorType::Elemental: |
||
3866 |
drawElemental(graphics, |
||
3867 |
offsetX, |
||
3868 |
offsetY); |
||
3869 |
break; |
||
3870 |
case ActorType::Monster: |
||
3871 |
drawMonster(graphics, |
||
3872 |
offsetX, |
||
3873 |
offsetY); |
||
3874 |
break; |
||
3875 |
case ActorType::Npc: |
||
3876 |
drawNpc(graphics, |
||
3877 |
offsetX, |
||
3878 |
offsetY); |
||
3879 |
break; |
||
3880 |
case ActorType::Pet: |
||
3881 |
case ActorType::SkillUnit: |
||
3882 |
case ActorType::Unknown: |
||
3883 |
case ActorType::FloorItem: |
||
3884 |
case ActorType::Avatar: |
||
3885 |
default: |
||
3886 |
drawOther(graphics, |
||
3887 |
offsetX, |
||
3888 |
offsetY); |
||
3889 |
break; |
||
3890 |
} |
||
3891 |
} |
||
3892 |
|||
3893 |
void Being::drawPlayerSprites(Graphics *restrict const graphics, |
||
3894 |
const int posX, |
||
3895 |
const int posY) const restrict2 |
||
3896 |
{ |
||
3897 |
const int sz = CompoundSprite::getNumberOfLayers(); |
||
3898 |
for (int f = 0; f < sz; f ++) |
||
3899 |
{ |
||
3900 |
const int rSprite = mSpriteHide[mSpriteRemap[f]]; |
||
3901 |
if (rSprite == 1) |
||
3902 |
continue; |
||
3903 |
|||
3904 |
Sprite *restrict const sprite = mSprites[mSpriteRemap[f]]; |
||
3905 |
if (sprite != nullptr) |
||
3906 |
{ |
||
3907 |
sprite->setAlpha(mAlpha); |
||
3908 |
sprite->draw(graphics, posX, posY); |
||
3909 |
} |
||
3910 |
} |
||
3911 |
} |
||
3912 |
|||
3913 |
void Being::drawSpritesSDL(Graphics *restrict const graphics, |
||
3914 |
const int posX, |
||
3915 |
const int posY) const restrict2 |
||
3916 |
{ |
||
3917 |
const size_t sz = mSprites.size(); |
||
3918 |
for (size_t f = 0; f < sz; f ++) |
||
3919 |
{ |
||
3920 |
const int rSprite = mSpriteHide[mSpriteRemap[f]]; |
||
3921 |
if (rSprite == 1) |
||
3922 |
continue; |
||
3923 |
|||
3924 |
const Sprite *restrict const sprite = mSprites[mSpriteRemap[f]]; |
||
3925 |
if (sprite != nullptr) |
||
3926 |
sprite->draw(graphics, posX, posY); |
||
3927 |
} |
||
3928 |
} |
||
3929 |
|||
3930 |
void Being::drawBasic(Graphics *restrict const graphics, |
||
3931 |
const int x, |
||
3932 |
const int y) const restrict2 |
||
3933 |
{ |
||
3934 |
drawCompound(graphics, x, y); |
||
3935 |
} |
||
3936 |
|||
3937 |
void Being::drawCompound(Graphics *const graphics, |
||
3938 |
const int posX, |
||
3939 |
const int posY) const |
||
3940 |
{ |
||
3941 |
FUNC_BLOCK("CompoundSprite::draw", 1) |
||
3942 |
if (mNeedsRedraw) |
||
3943 |
updateImages(); |
||
3944 |
|||
3945 |
if (mSprites.empty()) // Nothing to draw |
||
3946 |
return; |
||
3947 |
|||
3948 |
if (mAlpha == 1.0F && (mImage != nullptr)) |
||
3949 |
{ |
||
3950 |
graphics->drawImage(mImage, |
||
3951 |
posX + mOffsetX, |
||
3952 |
posY + mOffsetY); |
||
3953 |
} |
||
3954 |
else if ((mAlpha != 0.0F) && (mAlphaImage != nullptr)) |
||
3955 |
{ |
||
3956 |
mAlphaImage->setAlpha(mAlpha); |
||
3957 |
graphics->drawImage(mAlphaImage, |
||
3958 |
posX + mOffsetX, |
||
3959 |
posY + mOffsetY); |
||
3960 |
} |
||
3961 |
else |
||
3962 |
{ |
||
3963 |
Being::drawPlayerSprites(graphics, posX, posY); |
||
3964 |
} |
||
3965 |
} |
||
3966 |
|||
3967 |
void Being::drawPlayerSpriteAt(Graphics *restrict const graphics, |
||
3968 |
const int x, |
||
3969 |
const int y) const restrict2 |
||
3970 |
{ |
||
3971 |
drawCompound(graphics, x, y); |
||
3972 |
|||
3973 |
if (mShowOwnHP && |
||
3974 |
(mInfo != nullptr) && |
||
3975 |
localPlayer == this && |
||
3976 |
mAction != BeingAction::DEAD) |
||
3977 |
{ |
||
3978 |
drawHpBar(graphics, |
||
3979 |
PlayerInfo::getAttribute(Attributes::PLAYER_MAX_HP), |
||
3980 |
PlayerInfo::getAttribute(Attributes::PLAYER_HP), |
||
3981 |
0, |
||
3982 |
UserColorId::PLAYER_HP, |
||
3983 |
UserColorId::PLAYER_HP2, |
||
3984 |
x - 50 + mapTileSize / 2 + mInfo->getHpBarOffsetX(), |
||
3985 |
y + mapTileSize - 6 + mInfo->getHpBarOffsetY(), |
||
3986 |
2 * 50, |
||
3987 |
4); |
||
3988 |
} |
||
3989 |
} |
||
3990 |
|||
3991 |
void Being::drawOtherSpriteAt(Graphics *restrict const graphics, |
||
3992 |
const int x, |
||
3993 |
const int y) const restrict2 |
||
3994 |
{ |
||
3995 |
CompoundSprite::drawSimple(graphics, x, y); |
||
3996 |
} |
||
3997 |
|||
3998 |
void Being::drawNpcSpriteAt(Graphics *restrict const graphics, |
||
3999 |
const int x, |
||
4000 |
const int y) const restrict2 |
||
4001 |
{ |
||
4002 |
drawCompound(graphics, x, y); |
||
4003 |
} |
||
4004 |
|||
4005 |
void Being::drawMonsterSpriteAt(Graphics *restrict const graphics, |
||
4006 |
const int x, |
||
4007 |
const int y) const restrict2 |
||
4008 |
{ |
||
4009 |
if (mHighlightMonsterAttackRange && |
||
4010 |
mType == ActorType::Monster && |
||
4011 |
mAction != BeingAction::DEAD) |
||
4012 |
{ |
||
4013 |
if (userPalette == nullptr) |
||
4014 |
{ |
||
4015 |
CompoundSprite::drawSimple(graphics, x, y); |
||
4016 |
return; |
||
4017 |
} |
||
4018 |
|||
4019 |
int attackRange; |
||
4020 |
if (mAttackRange != 0) |
||
4021 |
attackRange = mapTileSize * mAttackRange; |
||
4022 |
else |
||
4023 |
attackRange = mapTileSize; |
||
4024 |
|||
4025 |
graphics->setColor(userPalette->getColorWithAlpha( |
||
4026 |
UserColorId::MONSTER_ATTACK_RANGE)); |
||
4027 |
|||
4028 |
graphics->fillRectangle(Rect( |
||
4029 |
x - attackRange, y - attackRange, |
||
4030 |
2 * attackRange + mapTileSize, 2 * attackRange + mapTileSize)); |
||
4031 |
} |
||
4032 |
|||
4033 |
CompoundSprite::drawSimple(graphics, x, y); |
||
4034 |
|||
4035 |
if (mShowMobHP && |
||
4036 |
(mInfo != nullptr) && |
||
4037 |
(localPlayer != nullptr) && |
||
4038 |
localPlayer->getTarget() == this && |
||
4039 |
mType == ActorType::Monster) |
||
4040 |
{ |
||
4041 |
// show hp bar here |
||
4042 |
int maxHP = mMaxHP; |
||
4043 |
if (maxHP == 0) |
||
4044 |
maxHP = mInfo->getMaxHP(); |
||
4045 |
|||
4046 |
drawHpBar(graphics, |
||
4047 |
maxHP, |
||
4048 |
mHP, |
||
4049 |
mDamageTaken, |
||
4050 |
UserColorId::MONSTER_HP, |
||
4051 |
UserColorId::MONSTER_HP2, |
||
4052 |
x - 50 + mapTileSize / 2 + mInfo->getHpBarOffsetX(), |
||
4053 |
y + mapTileSize - 6 + mInfo->getHpBarOffsetY(), |
||
4054 |
2 * 50, |
||
4055 |
4); |
||
4056 |
} |
||
4057 |
} |
||
4058 |
|||
4059 |
void Being::drawHomunculusSpriteAt(Graphics *restrict const graphics, |
||
4060 |
const int x, |
||
4061 |
const int y) const restrict2 |
||
4062 |
{ |
||
4063 |
if (mHighlightMonsterAttackRange && |
||
4064 |
mAction != BeingAction::DEAD) |
||
4065 |
{ |
||
4066 |
if (userPalette == nullptr) |
||
4067 |
{ |
||
4068 |
CompoundSprite::drawSimple(graphics, x, y); |
||
4069 |
return; |
||
4070 |
} |
||
4071 |
|||
4072 |
int attackRange; |
||
4073 |
if (mAttackRange != 0) |
||
4074 |
attackRange = mapTileSize * mAttackRange; |
||
4075 |
else |
||
4076 |
attackRange = mapTileSize; |
||
4077 |
|||
4078 |
graphics->setColor(userPalette->getColorWithAlpha( |
||
4079 |
UserColorId::MONSTER_ATTACK_RANGE)); |
||
4080 |
|||
4081 |
graphics->fillRectangle(Rect( |
||
4082 |
x - attackRange, y - attackRange, |
||
4083 |
2 * attackRange + mapTileSize, 2 * attackRange + mapTileSize)); |
||
4084 |
} |
||
4085 |
|||
4086 |
CompoundSprite::drawSimple(graphics, x, y); |
||
4087 |
|||
4088 |
if (mShowMobHP && |
||
4089 |
(mInfo != nullptr)) |
||
4090 |
{ |
||
4091 |
const HomunculusInfo *const info = PlayerInfo::getHomunculus(); |
||
4092 |
if ((info != nullptr) && |
||
4093 |
mId == info->id) |
||
4094 |
{ |
||
4095 |
// show hp bar here |
||
4096 |
int maxHP = PlayerInfo::getStatBase(Attributes::HOMUN_MAX_HP); |
||
4097 |
if (maxHP == 0) |
||
4098 |
maxHP = mInfo->getMaxHP(); |
||
4099 |
|||
4100 |
drawHpBar(graphics, |
||
4101 |
maxHP, |
||
4102 |
PlayerInfo::getStatBase(Attributes::HOMUN_HP), |
||
4103 |
mDamageTaken, |
||
4104 |
UserColorId::HOMUN_HP, |
||
4105 |
UserColorId::HOMUN_HP2, |
||
4106 |
x - 50 + mapTileSize / 2 + mInfo->getHpBarOffsetX(), |
||
4107 |
y + mapTileSize - 6 + mInfo->getHpBarOffsetY(), |
||
4108 |
2 * 50, |
||
4109 |
4); |
||
4110 |
} |
||
4111 |
} |
||
4112 |
} |
||
4113 |
|||
4114 |
void Being::drawMercenarySpriteAt(Graphics *restrict const graphics, |
||
4115 |
const int x, |
||
4116 |
const int y) const restrict2 |
||
4117 |
{ |
||
4118 |
if (mHighlightMonsterAttackRange && |
||
4119 |
mAction != BeingAction::DEAD) |
||
4120 |
{ |
||
4121 |
if (userPalette == nullptr) |
||
4122 |
{ |
||
4123 |
CompoundSprite::drawSimple(graphics, x, y); |
||
4124 |
return; |
||
4125 |
} |
||
4126 |
|||
4127 |
int attackRange; |
||
4128 |
if (mAttackRange != 0) |
||
4129 |
attackRange = mapTileSize * mAttackRange; |
||
4130 |
else |
||
4131 |
attackRange = mapTileSize; |
||
4132 |
|||
4133 |
graphics->setColor(userPalette->getColorWithAlpha( |
||
4134 |
UserColorId::MONSTER_ATTACK_RANGE)); |
||
4135 |
|||
4136 |
graphics->fillRectangle(Rect( |
||
4137 |
x - attackRange, y - attackRange, |
||
4138 |
2 * attackRange + mapTileSize, 2 * attackRange + mapTileSize)); |
||
4139 |
} |
||
4140 |
|||
4141 |
CompoundSprite::drawSimple(graphics, x, y); |
||
4142 |
|||
4143 |
if (mShowMobHP && |
||
4144 |
(mInfo != nullptr)) |
||
4145 |
{ |
||
4146 |
const MercenaryInfo *const info = PlayerInfo::getMercenary(); |
||
4147 |
if ((info != nullptr) && |
||
4148 |
mId == info->id) |
||
4149 |
{ |
||
4150 |
// show hp bar here |
||
4151 |
int maxHP = PlayerInfo::getStatBase(Attributes::MERC_MAX_HP); |
||
4152 |
if (maxHP == 0) |
||
4153 |
maxHP = mInfo->getMaxHP(); |
||
4154 |
|||
4155 |
drawHpBar(graphics, |
||
4156 |
maxHP, |
||
4157 |
PlayerInfo::getStatBase(Attributes::MERC_HP), |
||
4158 |
mDamageTaken, |
||
4159 |
UserColorId::MERC_HP, |
||
4160 |
UserColorId::MERC_HP2, |
||
4161 |
x - 50 + mapTileSize / 2 + mInfo->getHpBarOffsetX(), |
||
4162 |
y + mapTileSize - 6 + mInfo->getHpBarOffsetY(), |
||
4163 |
2 * 50, |
||
4164 |
4); |
||
4165 |
} |
||
4166 |
} |
||
4167 |
} |
||
4168 |
|||
4169 |
void Being::drawElementalSpriteAt(Graphics *restrict const graphics, |
||
4170 |
const int x, |
||
4171 |
const int y) const restrict2 |
||
4172 |
{ |
||
4173 |
if (mHighlightMonsterAttackRange && |
||
4174 |
mAction != BeingAction::DEAD) |
||
4175 |
{ |
||
4176 |
if (userPalette == nullptr) |
||
4177 |
{ |
||
4178 |
CompoundSprite::drawSimple(graphics, x, y); |
||
4179 |
return; |
||
4180 |
} |
||
4181 |
|||
4182 |
int attackRange; |
||
4183 |
if (mAttackRange != 0) |
||
4184 |
attackRange = mapTileSize * mAttackRange; |
||
4185 |
else |
||
4186 |
attackRange = mapTileSize; |
||
4187 |
|||
4188 |
graphics->setColor(userPalette->getColorWithAlpha( |
||
4189 |
UserColorId::MONSTER_ATTACK_RANGE)); |
||
4190 |
|||
4191 |
graphics->fillRectangle(Rect( |
||
4192 |
x - attackRange, y - attackRange, |
||
4193 |
2 * attackRange + mapTileSize, 2 * attackRange + mapTileSize)); |
||
4194 |
} |
||
4195 |
|||
4196 |
CompoundSprite::drawSimple(graphics, x, y); |
||
4197 |
|||
4198 |
if (mShowMobHP && |
||
4199 |
(mInfo != nullptr)) |
||
4200 |
{ |
||
4201 |
if (mId == PlayerInfo::getElementalId()) |
||
4202 |
{ |
||
4203 |
// show hp bar here |
||
4204 |
int maxHP = PlayerInfo::getStatBase(Attributes::ELEMENTAL_MAX_HP); |
||
4205 |
if (maxHP == 0) |
||
4206 |
maxHP = mInfo->getMaxHP(); |
||
4207 |
|||
4208 |
drawHpBar(graphics, |
||
4209 |
maxHP, |
||
4210 |
PlayerInfo::getStatBase(Attributes::ELEMENTAL_HP), |
||
4211 |
mDamageTaken, |
||
4212 |
UserColorId::ELEMENTAL_HP, |
||
4213 |
UserColorId::ELEMENTAL_HP2, |
||
4214 |
x - 50 + mapTileSize / 2 + mInfo->getHpBarOffsetX(), |
||
4215 |
y + mapTileSize - 6 + mInfo->getHpBarOffsetY(), |
||
4216 |
2 * 50, |
||
4217 |
4); |
||
4218 |
} |
||
4219 |
} |
||
4220 |
} |
||
4221 |
|||
4222 |
void Being::drawPortalSpriteAt(Graphics *restrict const graphics, |
||
4223 |
const int x, |
||
4224 |
const int y) const restrict2 |
||
4225 |
{ |
||
4226 |
if (mHighlightMapPortals && |
||
4227 |
(mMap != nullptr) && |
||
4228 |
!mMap->getHasWarps()) |
||
4229 |
{ |
||
4230 |
if (userPalette == nullptr) |
||
4231 |
{ |
||
4232 |
CompoundSprite::drawSimple(graphics, x, y); |
||
4233 |
return; |
||
4234 |
} |
||
4235 |
|||
4236 |
graphics->setColor(userPalette-> |
||
4237 |
getColorWithAlpha(UserColorId::PORTAL_HIGHLIGHT)); |
||
4238 |
|||
4239 |
graphics->fillRectangle(Rect(x, y, |
||
4240 |
mapTileSize, mapTileSize)); |
||
4241 |
|||
4242 |
if (mDrawHotKeys && !mName.empty()) |
||
4243 |
{ |
||
4244 |
const Color &color = userPalette->getColor(UserColorId::BEING, |
||
4245 |
255U); |
||
4246 |
gui->getFont()->drawString(graphics, color, color, mName, x, y); |
||
4247 |
} |
||
4248 |
} |
||
4249 |
|||
4250 |
CompoundSprite::drawSimple(graphics, x, y); |
||
4251 |
} |
||
4252 |
|||
4253 |
void Being::drawHpBar(Graphics *restrict const graphics, |
||
4254 |
const int maxHP, |
||
4255 |
const int hp, |
||
4256 |
const int damage, |
||
4257 |
const UserColorIdT color1, |
||
4258 |
const UserColorIdT color2, |
||
4259 |
const int x, |
||
4260 |
const int y, |
||
4261 |
const int width, |
||
4262 |
const int height) const restrict2 |
||
4263 |
{ |
||
4264 |
if (maxHP <= 0 || (userPalette == nullptr)) |
||
4265 |
return; |
||
4266 |
|||
4267 |
float p; |
||
4268 |
|||
4269 |
if (hp != 0) |
||
4270 |
{ |
||
4271 |
p = static_cast<float>(maxHP) / static_cast<float>(hp); |
||
4272 |
} |
||
4273 |
else if (maxHP != damage) |
||
4274 |
{ |
||
4275 |
p = static_cast<float>(maxHP) |
||
4276 |
/ static_cast<float>(maxHP - damage); |
||
4277 |
} |
||
4278 |
else |
||
4279 |
{ |
||
4280 |
p = 1; |
||
4281 |
} |
||
4282 |
|||
4283 |
if (p <= 0 || p > width) |
||
4284 |
return; |
||
4285 |
|||
4286 |
const int dx = static_cast<int>(static_cast<float>(width) / p); |
||
4287 |
|||
4288 |
#ifdef TMWA_SUPPORT |
||
4289 |
if (!serverFeatures->haveServerHp()) |
||
4290 |
{ // old servers |
||
4291 |
if ((damage == 0 && (this != localPlayer || hp == maxHP)) |
||
4292 |
|| (hp == 0 && maxHP == damage)) |
||
4293 |
{ |
||
4294 |
graphics->setColor(userPalette->getColorWithAlpha(color1)); |
||
4295 |
graphics->fillRectangle(Rect( |
||
4296 |
x, y, dx, height)); |
||
4297 |
return; |
||
4298 |
} |
||
4299 |
else if (width - dx <= 0) |
||
4300 |
{ |
||
4301 |
graphics->setColor(userPalette->getColorWithAlpha(color2)); |
||
4302 |
graphics->fillRectangle(Rect( |
||
4303 |
x, y, width, height)); |
||
4304 |
return; |
||
4305 |
} |
||
4306 |
} |
||
4307 |
else |
||
4308 |
#endif // TMWA_SUPPORT |
||
4309 |
{ |
||
4310 |
if (hp == maxHP) |
||
4311 |
{ |
||
4312 |
graphics->setColor(userPalette->getColorWithAlpha(color1)); |
||
4313 |
graphics->fillRectangle(Rect( |
||
4314 |
x, y, dx, height)); |
||
4315 |
return; |
||
4316 |
} |
||
4317 |
else if (width - dx <= 0) |
||
4318 |
{ |
||
4319 |
graphics->setColor(userPalette->getColorWithAlpha(color2)); |
||
4320 |
graphics->fillRectangle(Rect( |
||
4321 |
x, y, width, height)); |
||
4322 |
return; |
||
4323 |
} |
||
4324 |
} |
||
4325 |
|||
4326 |
graphics->setColor(userPalette->getColorWithAlpha(color1)); |
||
4327 |
graphics->fillRectangle(Rect( |
||
4328 |
x, y, dx, height)); |
||
4329 |
|||
4330 |
graphics->setColor(userPalette->getColorWithAlpha(color2)); |
||
4331 |
graphics->fillRectangle(Rect(x + dx, y, width - dx, height)); |
||
4332 |
} |
||
4333 |
|||
4334 |
void Being::setHP(const int hp) restrict2 |
||
4335 |
{ |
||
4336 |
mHP = hp; |
||
4337 |
if (mMaxHP < mHP) |
||
4338 |
mMaxHP = mHP; |
||
4339 |
if (mType == ActorType::Monster) |
||
4340 |
updatePercentHP(); |
||
4341 |
} |
||
4342 |
|||
4343 |
void Being::setMaxHP(const int hp) restrict2 |
||
4344 |
{ |
||
4345 |
mMaxHP = hp; |
||
4346 |
if (mMaxHP < mHP) |
||
4347 |
mMaxHP = mHP; |
||
4348 |
} |
||
4349 |
|||
4350 |
void Being::resetCounters() restrict2 |
||
4351 |
{ |
||
4352 |
mMoveTime = 0; |
||
4353 |
mAttackTime = 0; |
||
4354 |
mTalkTime = 0; |
||
4355 |
mOtherTime = 0; |
||
4356 |
mTestTime = cur_time; |
||
4357 |
} |
||
4358 |
|||
4359 |
void Being::recalcSpritesOrder() restrict2 |
||
4360 |
{ |
||
4361 |
if (!mEnableReorderSprites) |
||
4362 |
return; |
||
4363 |
|||
4364 |
// logger->log("recalcSpritesOrder"); |
||
4365 |
const size_t sz = mSprites.size(); |
||
4366 |
if (sz < 1) |
||
4367 |
return; |
||
4368 |
|||
4369 |
STD_VECTOR<int> slotRemap; |
||
4370 |
IntMap itemSlotRemap; |
||
4371 |
|||
4372 |
STD_VECTOR<int>::iterator it; |
||
4373 |
int oldHide[20]; |
||
4374 |
bool updatedSprite[20]; |
||
4375 |
int dir = mSpriteDirection; |
||
4376 |
if (dir < 0 || dir >= 9) |
||
4377 |
dir = 0; |
||
4378 |
// hack for allow different logic in dead player |
||
4379 |
if (mAction == BeingAction::DEAD) |
||
4380 |
dir = 9; |
||
4381 |
|||
4382 |
const unsigned int hairSlot = charServerHandler->hairSprite(); |
||
4383 |
|||
4384 |
for (size_t slot = sz; slot < 20; slot ++) |
||
4385 |
{ |
||
4386 |
oldHide[slot] = 0; |
||
4387 |
updatedSprite[slot] = false; |
||
4388 |
} |
||
4389 |
|||
4390 |
for (size_t slot = 0; slot < sz; slot ++) |
||
4391 |
{ |
||
4392 |
oldHide[slot] = mSpriteHide[slot]; |
||
4393 |
mSpriteHide[slot] = 0; |
||
4394 |
updatedSprite[slot] = false; |
||
4395 |
} |
||
4396 |
|||
4397 |
size_t spriteIdSize = mSlots.size(); |
||
4398 |
if (reportTrue(spriteIdSize > 20)) |
||
4399 |
spriteIdSize = 20; |
||
4400 |
|||
4401 |
for (size_t slot = 0; slot < sz; slot ++) |
||
4402 |
{ |
||
4403 |
slotRemap.push_back(CAST_S32(slot)); |
||
4404 |
|||
4405 |
if (spriteIdSize <= slot) |
||
4406 |
continue; |
||
4407 |
|||
4408 |
const int id = mSlots[slot].spriteId; |
||
4409 |
if (id == 0) |
||
4410 |
continue; |
||
4411 |
|||
4412 |
const ItemInfo &info = ItemDB::get(id); |
||
4413 |
|||
4414 |
if (info.isRemoveSprites()) |
||
4415 |
{ |
||
4416 |
const SpriteToItemMap *restrict const spriteToItems |
||
4417 |
= info.getSpriteToItemReplaceMap(dir); |
||
4418 |
|||
4419 |
if (spriteToItems != nullptr) |
||
4420 |
{ |
||
4421 |
FOR_EACHP (SpriteToItemMapCIter, itr, spriteToItems) |
||
4422 |
{ |
||
4423 |
const int remSlot = itr->first; |
||
4424 |
const IntMap &restrict itemReplacer = itr->second; |
||
4425 |
if (remSlot >= 0) |
||
4426 |
{ // slot known |
||
4427 |
if (CAST_U32(remSlot) >= spriteIdSize) |
||
4428 |
continue; |
||
4429 |
if (itemReplacer.empty()) |
||
4430 |
{ |
||
4431 |
mSpriteHide[remSlot] = 1; |
||
4432 |
} |
||
4433 |
else if (mSpriteHide[remSlot] != 1) |
||
4434 |
{ |
||
4435 |
IntMapCIter repIt = itemReplacer.find( |
||
4436 |
mSlots[remSlot].spriteId); |
||
4437 |
if (repIt == itemReplacer.end()) |
||
4438 |
{ |
||
4439 |
repIt = itemReplacer.find(0); |
||
4440 |
if (repIt == itemReplacer.end() || |
||
4441 |
repIt->second == 0) |
||
4442 |
{ |
||
4443 |
repIt = itemReplacer.end(); |
||
4444 |
} |
||
4445 |
} |
||
4446 |
if (repIt != itemReplacer.end()) |
||
4447 |
{ |
||
4448 |
mSpriteHide[remSlot] = repIt->second; |
||
4449 |
if (repIt->second != 1) |
||
4450 |
{ |
||
4451 |
if (CAST_U32(remSlot) |
||
4452 |
!= hairSlot) |
||
4453 |
{ |
||
4454 |
setTempSprite(remSlot, |
||
4455 |
repIt->second); |
||
4456 |
} |
||
4457 |
else |
||
4458 |
{ |
||
4459 |
setHairTempSprite(remSlot, |
||
4460 |
repIt->second); |
||
4461 |
} |
||
4462 |
updatedSprite[remSlot] = true; |
||
4463 |
} |
||
4464 |
} |
||
4465 |
} |
||
4466 |
} |
||
4467 |
else |
||
4468 |
{ // slot unknown. Search for real slot, this can be slow |
||
4469 |
FOR_EACH (IntMapCIter, repIt, itemReplacer) |
||
4470 |
{ |
||
4471 |
for (unsigned int slot2 = 0; slot2 < sz; slot2 ++) |
||
4472 |
{ |
||
4473 |
if (mSlots[slot2].spriteId == repIt->first) |
||
4474 |
{ |
||
4475 |
mSpriteHide[slot2] = repIt->second; |
||
4476 |
if (repIt->second != 1) |
||
4477 |
{ |
||
4478 |
if (slot2 != hairSlot) |
||
4479 |
{ |
||
4480 |
setTempSprite(slot2, |
||
4481 |
repIt->second); |
||
4482 |
} |
||
4483 |
else |
||
4484 |
{ |
||
4485 |
setHairTempSprite(slot2, |
||
4486 |
repIt->second); |
||
4487 |
} |
||
4488 |
updatedSprite[slot2] = true; |
||
4489 |
} |
||
4490 |
} |
||
4491 |
} |
||
4492 |
} |
||
4493 |
} |
||
4494 |
} |
||
4495 |
} |
||
4496 |
} |
||
4497 |
|||
4498 |
if (info.mDrawBefore[dir] > 0) |
||
4499 |
{ |
||
4500 |
const int id2 = mSlots[info.mDrawBefore[dir]].spriteId; |
||
4501 |
if (itemSlotRemap.find(id2) != itemSlotRemap.end()) |
||
4502 |
{ |
||
4503 |
// logger->log("found duplicate (before)"); |
||
4504 |
const ItemInfo &info2 = ItemDB::get(id2); |
||
4505 |
if (info.mDrawPriority[dir] < info2.mDrawPriority[dir]) |
||
4506 |
{ |
||
4507 |
// logger->log("old more priority"); |
||
4508 |
continue; |
||
4509 |
} |
||
4510 |
else |
||
4511 |
{ |
||
4512 |
// logger->log("new more priority"); |
||
4513 |
itemSlotRemap.erase(id2); |
||
4514 |
} |
||
4515 |
} |
||
4516 |
|||
4517 |
itemSlotRemap[id] = -info.mDrawBefore[dir]; |
||
4518 |
} |
||
4519 |
else if (info.mDrawAfter[dir] > 0) |
||
4520 |
{ |
||
4521 |
const int id2 = mSlots[info.mDrawAfter[dir]].spriteId; |
||
4522 |
if (itemSlotRemap.find(id2) != itemSlotRemap.end()) |
||
4523 |
{ |
||
4524 |
const ItemInfo &info2 = ItemDB::get(id2); |
||
4525 |
if (info.mDrawPriority[dir] < info2.mDrawPriority[dir]) |
||
4526 |
{ |
||
4527 |
// logger->log("old more priority"); |
||
4528 |
continue; |
||
4529 |
} |
||
4530 |
else |
||
4531 |
{ |
||
4532 |
// logger->log("new more priority"); |
||
4533 |
itemSlotRemap.erase(id2); |
||
4534 |
} |
||
4535 |
} |
||
4536 |
|||
4537 |
itemSlotRemap[id] = info.mDrawAfter[dir]; |
||
4538 |
// logger->log("item slot->slot %d %d->%d", id, slot, itemSlotRemap[id]); |
||
4539 |
} |
||
4540 |
} |
||
4541 |
// logger->log("preparation end"); |
||
4542 |
|||
4543 |
int lastRemap = 0; |
||
4544 |
unsigned cnt = 0; |
||
4545 |
|||
4546 |
while (cnt < 15 && lastRemap >= 0) |
||
4547 |
{ |
||
4548 |
lastRemap = -1; |
||
4549 |
cnt ++; |
||
4550 |
// logger->log("iteration"); |
||
4551 |
|||
4552 |
for (unsigned int slot0 = 0; slot0 < sz; slot0 ++) |
||
4553 |
{ |
||
4554 |
const int slot = searchSlotValue(slotRemap, slot0); |
||
4555 |
const int val = slotRemap.at(slot); |
||
4556 |
int id = 0; |
||
4557 |
|||
4558 |
if (CAST_S32(spriteIdSize) > val) |
||
4559 |
id = mSlots[val].spriteId; |
||
4560 |
|||
4561 |
int idx = -1; |
||
4562 |
int idx1 = -1; |
||
4563 |
// logger->log("item %d, id=%d", slot, id); |
||
4564 |
int reorder = 0; |
||
4565 |
const IntMapCIter orderIt = itemSlotRemap.find(id); |
||
4566 |
if (orderIt != itemSlotRemap.end()) |
||
4567 |
reorder = orderIt->second; |
||
4568 |
|||
4569 |
if (reorder < 0) |
||
4570 |
{ |
||
4571 |
// logger->log("move item %d before %d", slot, -reorder); |
||
4572 |
searchSlotValueItr(it, idx, slotRemap, -reorder); |
||
4573 |
if (it == slotRemap.end()) |
||
4574 |
return; |
||
4575 |
searchSlotValueItr(it, idx1, slotRemap, val); |
||
4576 |
if (it == slotRemap.end()) |
||
4577 |
return; |
||
4578 |
lastRemap = idx1; |
||
4579 |
if (idx1 + 1 != idx) |
||
4580 |
{ |
||
4581 |
slotRemap.erase(it); |
||
4582 |
searchSlotValueItr(it, idx, slotRemap, -reorder); |
||
4583 |
slotRemap.insert(it, val); |
||
4584 |
} |
||
4585 |
} |
||
4586 |
else if (reorder > 0) |
||
4587 |
{ |
||
4588 |
// logger->log("move item %d after %d", slot, reorder); |
||
4589 |
searchSlotValueItr(it, idx, slotRemap, reorder); |
||
4590 |
searchSlotValueItr(it, idx1, slotRemap, val); |
||
4591 |
if (it == slotRemap.end()) |
||
4592 |
return; |
||
4593 |
lastRemap = idx1; |
||
4594 |
if (idx1 != idx + 1) |
||
4595 |
{ |
||
4596 |
slotRemap.erase(it); |
||
4597 |
searchSlotValueItr(it, idx, slotRemap, reorder); |
||
4598 |
if (it != slotRemap.end()) |
||
4599 |
{ |
||
4600 |
++ it; |
||
4601 |
if (it != slotRemap.end()) |
||
4602 |
slotRemap.insert(it, val); |
||
4603 |
else |
||
4604 |
slotRemap.push_back(val); |
||
4605 |
} |
||
4606 |
else |
||
4607 |
{ |
||
4608 |
slotRemap.push_back(val); |
||
4609 |
} |
||
4610 |
} |
||
4611 |
} |
||
4612 |
} |
||
4613 |
} |
||
4614 |
|||
4615 |
// logger->log("after remap"); |
||
4616 |
for (unsigned int slot = 0; slot < sz; slot ++) |
||
4617 |
{ |
||
4618 |
mSpriteRemap[slot] = slotRemap[slot]; |
||
4619 |
if (mSpriteHide[slot] == 0) |
||
4620 |
{ |
||
4621 |
if (oldHide[slot] != 0 && oldHide[slot] != 1) |
||
4622 |
{ |
||
4623 |
const BeingSlot &beingSlot = mSlots[slot]; |
||
4624 |
const int id = beingSlot.spriteId; |
||
4625 |
if (id == 0) |
||
4626 |
continue; |
||
4627 |
|||
4628 |
updatedSprite[slot] = true; |
||
4629 |
setTempSprite(slot, |
||
4630 |
id); |
||
4631 |
} |
||
4632 |
} |
||
4633 |
} |
||
4634 |
for (size_t slot = 0; slot < spriteIdSize; slot ++) |
||
4635 |
{ |
||
4636 |
if (mSpriteHide[slot] == 0) |
||
4637 |
{ |
||
4638 |
const BeingSlot &beingSlot = mSlots[slot]; |
||
4639 |
const int id = beingSlot.spriteId; |
||
4640 |
if (updatedSprite[slot] == false && |
||
4641 |
mSpriteDraw[slot] != id) |
||
4642 |
{ |
||
4643 |
setTempSprite(static_cast<unsigned int>(slot), |
||
4644 |
id); |
||
4645 |
} |
||
4646 |
} |
||
4647 |
} |
||
4648 |
} |
||
4649 |
|||
4650 |
int Being::searchSlotValue(const STD_VECTOR<int> &restrict slotRemap, |
||
4651 |
const int val) const restrict2 |
||
4652 |
{ |
||
4653 |
const size_t sz = mSprites.size(); |
||
4654 |
for (size_t slot = 0; slot < sz; slot ++) |
||
4655 |
{ |
||
4656 |
if (slotRemap[slot] == val) |
||
4657 |
return CAST_S32(slot); |
||
4658 |
} |
||
4659 |
return CompoundSprite::getNumberOfLayers() - 1; |
||
4660 |
} |
||
4661 |
|||
4662 |
void Being::searchSlotValueItr(STD_VECTOR<int>::iterator &restrict it, |
||
4663 |
int &restrict idx, |
||
4664 |
STD_VECTOR<int> &restrict slotRemap, |
||
4665 |
const int val) |
||
4666 |
{ |
||
4667 |
// logger->log("searching %d", val); |
||
4668 |
it = slotRemap.begin(); |
||
4669 |
const STD_VECTOR<int>::iterator it_end = slotRemap.end(); |
||
4670 |
idx = 0; |
||
4671 |
while (it != it_end) |
||
4672 |
{ |
||
4673 |
// logger->log("testing %d", *it); |
||
4674 |
if (*it == val) |
||
4675 |
{ |
||
4676 |
// logger->log("found at %d", idx); |
||
4677 |
return; |
||
4678 |
} |
||
4679 |
++ it; |
||
4680 |
idx ++; |
||
4681 |
} |
||
4682 |
// logger->log("not found"); |
||
4683 |
idx = -1; |
||
4684 |
} |
||
4685 |
|||
4686 |
void Being::updateHit(const int amount) restrict2 |
||
4687 |
{ |
||
4688 |
if (amount > 0) |
||
4689 |
{ |
||
4690 |
if ((mMinHit == 0) || amount < mMinHit) |
||
4691 |
mMinHit = amount; |
||
4692 |
if (amount != mCriticalHit && ((mMaxHit == 0) || amount > mMaxHit)) |
||
4693 |
mMaxHit = amount; |
||
4694 |
} |
||
4695 |
} |
||
4696 |
|||
4697 |
Equipment *Being::getEquipment() restrict2 |
||
4698 |
{ |
||
4699 |
Equipment *restrict const eq = new Equipment; |
||
4700 |
Equipment::Backend *restrict const bk = new BeingEquipBackend(this); |
||
4701 |
eq->setBackend(bk); |
||
4702 |
return eq; |
||
4703 |
} |
||
4704 |
|||
4705 |
void Being::undressItemById(const int id) restrict2 |
||
4706 |
{ |
||
4707 |
const size_t sz = mSlots.size(); |
||
4708 |
|||
4709 |
for (size_t f = 0; f < sz; f ++) |
||
4710 |
{ |
||
4711 |
if (id == mSlots[f].spriteId) |
||
4712 |
{ |
||
4713 |
unSetSprite(CAST_U32(f)); |
||
4714 |
break; |
||
4715 |
} |
||
4716 |
} |
||
4717 |
} |
||
4718 |
|||
4719 |
void Being::clearCache() |
||
4720 |
{ |
||
4721 |
delete_all(beingInfoCache); |
||
4722 |
beingInfoCache.clear(); |
||
4723 |
} |
||
4724 |
|||
4725 |
void Being::updateComment() restrict2 |
||
4726 |
{ |
||
4727 |
if (mGotComment || mName.empty()) |
||
4728 |
return; |
||
4729 |
|||
4730 |
mGotComment = true; |
||
4731 |
mComment = loadComment(mName, mType); |
||
4732 |
} |
||
4733 |
|||
4734 |
std::string Being::loadComment(const std::string &restrict name, |
||
4735 |
const ActorTypeT &restrict type) |
||
4736 |
{ |
||
4737 |
std::string str; |
||
4738 |
switch (type) |
||
4739 |
{ |
||
4740 |
case ActorType::Player: |
||
4741 |
str = settings.usersDir; |
||
4742 |
break; |
||
4743 |
case ActorType::Npc: |
||
4744 |
str = settings.npcsDir; |
||
4745 |
break; |
||
4746 |
case ActorType::Unknown: |
||
4747 |
case ActorType::Monster: |
||
4748 |
case ActorType::FloorItem: |
||
4749 |
case ActorType::Portal: |
||
4750 |
case ActorType::Avatar: |
||
4751 |
case ActorType::Mercenary: |
||
4752 |
case ActorType::Homunculus: |
||
4753 |
case ActorType::Pet: |
||
4754 |
case ActorType::SkillUnit: |
||
4755 |
case ActorType::Elemental: |
||
4756 |
default: |
||
4757 |
return ""; |
||
4758 |
} |
||
4759 |
|||
4760 |
str = pathJoin(str, stringToHexPath(name), "comment.txt"); |
||
4761 |
if (Files::existsLocal(str)) |
||
4762 |
{ |
||
4763 |
StringVect lines; |
||
4764 |
Files::loadTextFileLocal(str, lines); |
||
4765 |
if (lines.size() >= 2) |
||
4766 |
return lines[1]; |
||
4767 |
} |
||
4768 |
return std::string(); |
||
4769 |
} |
||
4770 |
|||
4771 |
void Being::saveComment(const std::string &restrict name, |
||
4772 |
const std::string &restrict comment, |
||
4773 |
const ActorTypeT &restrict type) |
||
4774 |
{ |
||
4775 |
std::string dir; |
||
4776 |
switch (type) |
||
4777 |
{ |
||
4778 |
case ActorType::Player: |
||
4779 |
dir = settings.usersDir; |
||
4780 |
break; |
||
4781 |
case ActorType::Npc: |
||
4782 |
dir = settings.npcsDir; |
||
4783 |
break; |
||
4784 |
case ActorType::Monster: |
||
4785 |
case ActorType::FloorItem: |
||
4786 |
case ActorType::Portal: |
||
4787 |
case ActorType::Avatar: |
||
4788 |
case ActorType::Unknown: |
||
4789 |
case ActorType::Pet: |
||
4790 |
case ActorType::Mercenary: |
||
4791 |
case ActorType::Homunculus: |
||
4792 |
case ActorType::SkillUnit: |
||
4793 |
case ActorType::Elemental: |
||
4794 |
default: |
||
4795 |
return; |
||
4796 |
} |
||
4797 |
dir = pathJoin(dir, stringToHexPath(name)); |
||
4798 |
Files::saveTextFile(dir, |
||
4799 |
"comment.txt", |
||
4800 |
(name + "\n").append(comment)); |
||
4801 |
} |
||
4802 |
|||
4803 |
void Being::setState(const uint8_t state) restrict2 |
||
4804 |
{ |
||
4805 |
const bool shop = ((state & BeingFlag::SHOP) != 0); |
||
4806 |
const bool away = ((state & BeingFlag::AWAY) != 0); |
||
4807 |
const bool inactive = ((state & BeingFlag::INACTIVE) != 0); |
||
4808 |
const bool needUpdate = (shop != mShop || away != mAway |
||
4809 |
|| inactive != mInactive); |
||
4810 |
|||
4811 |
if (Net::getNetworkType() == ServerType::TMWATHENA) |
||
4812 |
mShop = shop; |
||
4813 |
mAway = away; |
||
4814 |
mInactive = inactive; |
||
4815 |
updateAwayEffect(); |
||
4816 |
showShopBadge(mShop); |
||
4817 |
showInactiveBadge(mInactive); |
||
4818 |
showAwayBadge(mAway); |
||
4819 |
|||
4820 |
if (needUpdate) |
||
4821 |
{ |
||
4822 |
if (shop || away || inactive) |
||
4823 |
mAdvanced = true; |
||
4824 |
updateName(); |
||
4825 |
addToCache(); |
||
4826 |
} |
||
4827 |
} |
||
4828 |
|||
4829 |
void Being::setEmote(const uint8_t emotion, |
||
4830 |
const int emote_time) restrict2 |
||
4831 |
{ |
||
4832 |
if ((emotion & BeingFlag::SPECIAL) == BeingFlag::SPECIAL) |
||
4833 |
{ |
||
4834 |
setState(emotion); |
||
4835 |
mAdvanced = true; |
||
4836 |
} |
||
4837 |
else |
||
4838 |
{ |
||
4839 |
const int emotionIndex = emotion - 1; |
||
4840 |
if (emotionIndex >= 0 && emotionIndex <= EmoteDB::getLast()) |
||
4841 |
{ |
||
4842 |
delete2(mEmotionSprite) |
||
4843 |
const EmoteInfo *const info = EmoteDB::get2(emotionIndex, true); |
||
4844 |
if (info != nullptr) |
||
4845 |
{ |
||
4846 |
const EmoteSprite *restrict const sprite = |
||
4847 |
info->sprites.front(); |
||
4848 |
if (sprite != nullptr) |
||
4849 |
{ |
||
4850 |
mEmotionSprite = AnimatedSprite::clone(sprite->sprite); |
||
4851 |
if (mEmotionSprite != nullptr) |
||
4852 |
mEmotionTime = info->time; |
||
4853 |
else |
||
4854 |
mEmotionTime = emote_time; |
||
4855 |
} |
||
4856 |
const int effectId = info->effectId; |
||
4857 |
if (effectId >= 0) |
||
4858 |
{ |
||
4859 |
effectManager->trigger(effectId, this, 0); |
||
4860 |
} |
||
4861 |
} |
||
4862 |
} |
||
4863 |
|||
4864 |
if (mEmotionSprite != nullptr) |
||
4865 |
{ |
||
4866 |
mEmotionSprite->play(mSpriteAction); |
||
4867 |
mEmotionSprite->setSpriteDirection(mSpriteDirection); |
||
4868 |
} |
||
4869 |
else |
||
4870 |
{ |
||
4871 |
mEmotionTime = 0; |
||
4872 |
} |
||
4873 |
} |
||
4874 |
} |
||
4875 |
|||
4876 |
103 |
void Being::updatePercentHP() restrict2 |
|
4877 |
{ |
||
4878 |
✗✓ | 103 |
if (mMaxHP == 0) |
4879 |
return; |
||
4880 |
BLOCK_START("Being::updatePercentHP") |
||
4881 |
if (mHP != 0) |
||
4882 |
{ |
||
4883 |
const unsigned num = mHP * 100 / mMaxHP; |
||
4884 |
if (num != mNumber) |
||
4885 |
{ |
||
4886 |
mNumber = num; |
||
4887 |
if (updateNumber(mNumber)) |
||
4888 |
setAction(mAction, 0); |
||
4889 |
} |
||
4890 |
} |
||
4891 |
BLOCK_END("Being::updatePercentHP") |
||
4892 |
} |
||
4893 |
|||
4894 |
int Being::getSpriteID(const int slot) const restrict2 |
||
4895 |
{ |
||
4896 |
if (slot < 0 || CAST_SIZE(slot) >= mSlots.size()) |
||
4897 |
return -1; |
||
4898 |
|||
4899 |
return mSlots[slot].spriteId; |
||
4900 |
} |
||
4901 |
|||
4902 |
const BeingSlot &Being::getSpriteSlot(const int slot) const restrict2 |
||
4903 |
{ |
||
4904 |
if (slot < 0 || CAST_SIZE(slot) >= mSlots.size()) |
||
4905 |
return *emptyBeingSlot; |
||
4906 |
|||
4907 |
return mSlots[slot]; |
||
4908 |
} |
||
4909 |
|||
4910 |
ItemColor Being::getSpriteColor(const int slot) const restrict2 |
||
4911 |
{ |
||
4912 |
if (slot < 0 || CAST_SIZE(slot) >= mSlots.size()) |
||
4913 |
return ItemColor_one; |
||
4914 |
|||
4915 |
return mSlots[slot].colorId; |
||
4916 |
} |
||
4917 |
|||
4918 |
void Being::addAfkEffect() restrict2 |
||
4919 |
{ |
||
4920 |
addSpecialEffect(mAwayEffect); |
||
4921 |
} |
||
4922 |
|||
4923 |
void Being::removeAfkEffect() restrict2 |
||
4924 |
{ |
||
4925 |
removeSpecialEffect(); |
||
4926 |
} |
||
4927 |
|||
4928 |
void Being::addSpecialEffect(const int effect) restrict2 |
||
4929 |
{ |
||
4930 |
if ((effectManager != nullptr) && |
||
4931 |
ParticleEngine::enabled && |
||
4932 |
(mSpecialParticle == nullptr) && |
||
4933 |
effect != -1) |
||
4934 |
{ |
||
4935 |
mSpecialParticle = effectManager->triggerReturn(effect, |
||
4936 |
this, |
||
4937 |
0); |
||
4938 |
} |
||
4939 |
} |
||
4940 |
|||
4941 |
void Being::removeSpecialEffect() restrict2 |
||
4942 |
{ |
||
4943 |
if ((effectManager != nullptr) && (mSpecialParticle != nullptr)) |
||
4944 |
{ |
||
4945 |
mChildParticleEffects.removeLocally(mSpecialParticle); |
||
4946 |
mSpecialParticle = nullptr; |
||
4947 |
} |
||
4948 |
delete2(mAnimationEffect) |
||
4949 |
} |
||
4950 |
|||
4951 |
void Being::updateAwayEffect() restrict2 |
||
4952 |
{ |
||
4953 |
if (mAway) |
||
4954 |
addAfkEffect(); |
||
4955 |
else |
||
4956 |
removeAfkEffect(); |
||
4957 |
} |
||
4958 |
|||
4959 |
void Being::addEffect(const std::string &restrict name) restrict2 |
||
4960 |
{ |
||
4961 |
delete mAnimationEffect; |
||
4962 |
mAnimationEffect = AnimatedSprite::load( |
||
4963 |
paths.getStringValue("sprites") + name, |
||
4964 |
0); |
||
4965 |
} |
||
4966 |
|||
4967 |
void Being::playSfx(const SoundInfo &sound, |
||
4968 |
Being *const being, |
||
4969 |
const bool main, |
||
4970 |
const int x, const int y) const restrict2 |
||
4971 |
{ |
||
4972 |
BLOCK_START("Being::playSfx") |
||
4973 |
|||
4974 |
if (being != nullptr) |
||
4975 |
{ |
||
4976 |
// here need add timer and delay sound |
||
4977 |
const int time = tick_time; |
||
4978 |
if (main) |
||
4979 |
{ |
||
4980 |
being->mNextSound.sound = nullptr; |
||
4981 |
being->mNextSound.time = time + sound.delay; |
||
4982 |
soundManager.playSfx(sound.sound, x, y); |
||
4983 |
} |
||
4984 |
else if (mNextSound.time <= time) |
||
4985 |
{ // old event sound time is gone. we can play new sound |
||
4986 |
being->mNextSound.sound = nullptr; |
||
4987 |
being->mNextSound.time = time + sound.delay; |
||
4988 |
soundManager.playSfx(sound.sound, x, y); |
||
4989 |
} |
||
4990 |
else |
||
4991 |
{ // old event sound in progress. need save sound and wait |
||
4992 |
being->mNextSound.sound = &sound; |
||
4993 |
being->mNextSound.x = x; |
||
4994 |
being->mNextSound.y = y; |
||
4995 |
} |
||
4996 |
} |
||
4997 |
else |
||
4998 |
{ |
||
4999 |
soundManager.playSfx(sound.sound, x, y); |
||
5000 |
} |
||
5001 |
BLOCK_END("Being::playSfx") |
||
5002 |
} |
||
5003 |
|||
5004 |
void Being::setLook(const uint16_t look) restrict2 |
||
5005 |
{ |
||
5006 |
if (mType == ActorType::Player) |
||
5007 |
setSubtype(mSubType, look); |
||
5008 |
} |
||
5009 |
|||
5010 |
void Being::setTileCoords(const int x, const int y) restrict2 |
||
5011 |
{ |
||
5012 |
mX = x; |
||
5013 |
mY = y; |
||
5014 |
if (mMap != nullptr) |
||
5015 |
{ |
||
5016 |
mPixelOffsetY = 0; |
||
5017 |
mFixedOffsetY = mPixelOffsetY; |
||
5018 |
mOldHeight = mMap->getHeightOffset(mX, mY); |
||
5019 |
mNeedPosUpdate = true; |
||
5020 |
} |
||
5021 |
} |
||
5022 |
|||
5023 |
103 |
void Being::setMap(Map *restrict const map) restrict2 |
|
5024 |
{ |
||
5025 |
103 |
mCastEndTime = 0; |
|
5026 |
✗✓ | 103 |
delete2(mCastingEffect) |
5027 |
103 |
ActorSprite::setMap(map); |
|
5028 |
✓✓ | 103 |
if (mMap != nullptr) |
5029 |
{ |
||
5030 |
2 |
mPixelOffsetY = mMap->getHeightOffset(mX, mY); |
|
5031 |
2 |
mFixedOffsetY = mPixelOffsetY; |
|
5032 |
2 |
mOldHeight = 0; |
|
5033 |
2 |
mNeedPosUpdate = true; |
|
5034 |
} |
||
5035 |
103 |
} |
|
5036 |
|||
5037 |
103 |
void Being::removeAllItemsParticles() restrict2 |
|
5038 |
{ |
||
5039 |
✗✓ | 309 |
FOR_EACH (SpriteParticleInfoIter, it, mSpriteParticles) |
5040 |
delete (*it).second; |
||
5041 |
206 |
mSpriteParticles.clear(); |
|
5042 |
103 |
} |
|
5043 |
|||
5044 |
void Being::addItemParticles(const int id, |
||
5045 |
const SpriteDisplay &restrict display) restrict2 |
||
5046 |
{ |
||
5047 |
const SpriteParticleInfoIter it = mSpriteParticles.find(id); |
||
5048 |
ParticleInfo *restrict pi = nullptr; |
||
5049 |
if (it == mSpriteParticles.end()) |
||
5050 |
{ |
||
5051 |
pi = new ParticleInfo; |
||
5052 |
mSpriteParticles[id] = pi; |
||
5053 |
} |
||
5054 |
else |
||
5055 |
{ |
||
5056 |
pi = (*it).second; |
||
5057 |
} |
||
5058 |
|||
5059 |
if ((pi == nullptr) || !pi->particles.empty()) |
||
5060 |
return; |
||
5061 |
|||
5062 |
// setup particle effects |
||
5063 |
if (ParticleEngine::enabled && |
||
5064 |
(particleEngine != nullptr)) |
||
5065 |
{ |
||
5066 |
FOR_EACH (StringVectCIter, itr, display.particles) |
||
5067 |
{ |
||
5068 |
Particle *const p = particleEngine->addEffect(*itr, 0, 0, 0); |
||
5069 |
controlCustomParticle(p); |
||
5070 |
pi->files.push_back(*itr); |
||
5071 |
pi->particles.push_back(p); |
||
5072 |
} |
||
5073 |
} |
||
5074 |
else |
||
5075 |
{ |
||
5076 |
FOR_EACH (StringVectCIter, itr, display.particles) |
||
5077 |
pi->files.push_back(*itr); |
||
5078 |
} |
||
5079 |
} |
||
5080 |
|||
5081 |
void Being::addItemParticlesCards(const int id, |
||
5082 |
const SpriteDisplay &restrict display, |
||
5083 |
const CardsList &cards) restrict2 |
||
5084 |
{ |
||
5085 |
const SpriteParticleInfoIter it = mSpriteParticles.find(id); |
||
5086 |
ParticleInfo *restrict pi = nullptr; |
||
5087 |
if (it == mSpriteParticles.end()) |
||
5088 |
{ |
||
5089 |
pi = new ParticleInfo; |
||
5090 |
mSpriteParticles[id] = pi; |
||
5091 |
} |
||
5092 |
else |
||
5093 |
{ |
||
5094 |
pi = (*it).second; |
||
5095 |
} |
||
5096 |
|||
5097 |
if ((pi == nullptr) || !pi->particles.empty()) |
||
5098 |
return; |
||
5099 |
|||
5100 |
// setup particle effects |
||
5101 |
if (ParticleEngine::enabled && |
||
5102 |
(particleEngine != nullptr)) |
||
5103 |
{ |
||
5104 |
FOR_EACH (StringVectCIter, itr, display.particles) |
||
5105 |
{ |
||
5106 |
Particle *const p = particleEngine->addEffect(*itr, 0, 0, 0); |
||
5107 |
controlCustomParticle(p); |
||
5108 |
pi->files.push_back(*itr); |
||
5109 |
pi->particles.push_back(p); |
||
5110 |
} |
||
5111 |
for (int f = 0; f < maxCards; f ++) |
||
5112 |
{ |
||
5113 |
const int cardId = cards.cards[f]; |
||
5114 |
if (!Item::isItem(cardId)) |
||
5115 |
continue; |
||
5116 |
const ItemInfo &info = ItemDB::get(cardId); |
||
5117 |
const SpriteDisplay &restrict display2 = info.getDisplay(); |
||
5118 |
FOR_EACH (StringVectCIter, itr, display2.particles) |
||
5119 |
{ |
||
5120 |
Particle *const p = particleEngine->addEffect(*itr, 0, 0, 0); |
||
5121 |
controlCustomParticle(p); |
||
5122 |
pi->files.push_back(*itr); |
||
5123 |
pi->particles.push_back(p); |
||
5124 |
} |
||
5125 |
} |
||
5126 |
} |
||
5127 |
else |
||
5128 |
{ |
||
5129 |
FOR_EACH (StringVectCIter, itr, display.particles) |
||
5130 |
{ |
||
5131 |
pi->files.push_back(*itr); |
||
5132 |
} |
||
5133 |
for (int f = 0; f < maxCards; f ++) |
||
5134 |
{ |
||
5135 |
const int cardId = cards.cards[f]; |
||
5136 |
if (!Item::isItem(cardId)) |
||
5137 |
continue; |
||
5138 |
const ItemInfo &info = ItemDB::get(cardId); |
||
5139 |
const SpriteDisplay &restrict display2 = info.getDisplay(); |
||
5140 |
FOR_EACH (StringVectCIter, itr, display2.particles) |
||
5141 |
{ |
||
5142 |
pi->files.push_back(*itr); |
||
5143 |
} |
||
5144 |
} |
||
5145 |
} |
||
5146 |
} |
||
5147 |
|||
5148 |
void Being::removeItemParticles(const int id) restrict2 |
||
5149 |
{ |
||
5150 |
const SpriteParticleInfoIter it = mSpriteParticles.find(id); |
||
5151 |
if (it == mSpriteParticles.end()) |
||
5152 |
return; |
||
5153 |
ParticleInfo *restrict const pi = (*it).second; |
||
5154 |
if (pi != nullptr) |
||
5155 |
{ |
||
5156 |
FOR_EACH (STD_VECTOR<Particle*>::const_iterator, itp, pi->particles) |
||
5157 |
mChildParticleEffects.removeLocally(*itp); |
||
5158 |
delete pi; |
||
5159 |
} |
||
5160 |
mSpriteParticles.erase(it); |
||
5161 |
} |
||
5162 |
|||
5163 |
void Being::recreateItemParticles() restrict2 |
||
5164 |
{ |
||
5165 |
FOR_EACH (SpriteParticleInfoIter, it, mSpriteParticles) |
||
5166 |
{ |
||
5167 |
ParticleInfo *restrict const pi = (*it).second; |
||
5168 |
if ((pi != nullptr) && !pi->files.empty()) |
||
5169 |
{ |
||
5170 |
FOR_EACH (STD_VECTOR<Particle*>::const_iterator, |
||
5171 |
itp, pi->particles) |
||
5172 |
{ |
||
5173 |
mChildParticleEffects.removeLocally(*itp); |
||
5174 |
} |
||
5175 |
|||
5176 |
FOR_EACH (STD_VECTOR<std::string>::const_iterator, str, pi->files) |
||
5177 |
{ |
||
5178 |
Particle *const p = particleEngine->addEffect( |
||
5179 |
*str, 0, 0, 0); |
||
5180 |
controlCustomParticle(p); |
||
5181 |
pi->particles.push_back(p); |
||
5182 |
} |
||
5183 |
} |
||
5184 |
} |
||
5185 |
} |
||
5186 |
|||
5187 |
void Being::setTeamId(const uint16_t teamId) restrict2 |
||
5188 |
{ |
||
5189 |
if (mTeamId != teamId) |
||
5190 |
{ |
||
5191 |
mTeamId = teamId; |
||
5192 |
showTeamBadge(mTeamId != 0); |
||
5193 |
updateColors(); |
||
5194 |
} |
||
5195 |
} |
||
5196 |
|||
5197 |
void Being::showTeamBadge(const bool show) restrict2 |
||
5198 |
{ |
||
5199 |
delete2(mBadges[BadgeIndex::Team]) |
||
5200 |
if (show && |
||
5201 |
mTeamId != 0U && |
||
5202 |
mShowBadges != BadgeDrawType::Hide) |
||
5203 |
{ |
||
5204 |
const std::string name = paths.getStringValue("badges") + |
||
5205 |
paths.getStringValue(strprintf("team%dbadge", |
||
5206 |
mTeamId)); |
||
5207 |
if (!name.empty()) |
||
5208 |
mBadges[BadgeIndex::Team] = AnimatedSprite::load(name, 0); |
||
5209 |
} |
||
5210 |
updateBadgesCount(); |
||
5211 |
updateBadgesPosition(); |
||
5212 |
} |
||
5213 |
|||
5214 |
void Being::showBadges(const bool show) restrict2 |
||
5215 |
{ |
||
5216 |
showTeamBadge(show); |
||
5217 |
showGuildBadge(show); |
||
5218 |
showGmBadge(show); |
||
5219 |
showPartyBadge(show); |
||
5220 |
showNameBadge(show); |
||
5221 |
showShopBadge(show); |
||
5222 |
showInactiveBadge(show); |
||
5223 |
showAwayBadge(show); |
||
5224 |
} |
||
5225 |
|||
5226 |
void Being::showPartyBadge(const bool show) restrict2 |
||
5227 |
{ |
||
5228 |
delete2(mBadges[BadgeIndex::Party]) |
||
5229 |
if (show && |
||
5230 |
!mPartyName.empty() && |
||
5231 |
mShowBadges != BadgeDrawType::Hide) |
||
5232 |
{ |
||
5233 |
const std::string badge = BadgesDB::getPartyBadge(mPartyName); |
||
5234 |
if (!badge.empty()) |
||
5235 |
{ |
||
5236 |
mBadges[BadgeIndex::Party] = AnimatedSprite::load( |
||
5237 |
paths.getStringValue("badges") + badge, |
||
5238 |
0); |
||
5239 |
} |
||
5240 |
} |
||
5241 |
updateBadgesCount(); |
||
5242 |
updateBadgesPosition(); |
||
5243 |
} |
||
5244 |
|||
5245 |
|||
5246 |
void Being::setPartyName(const std::string &restrict name) restrict2 |
||
5247 |
{ |
||
5248 |
if (mPartyName != name) |
||
5249 |
{ |
||
5250 |
mPartyName = name; |
||
5251 |
showPartyBadge(!mPartyName.empty()); |
||
5252 |
} |
||
5253 |
} |
||
5254 |
|||
5255 |
void Being::showShopBadge(const bool show) restrict2 |
||
5256 |
{ |
||
5257 |
delete2(mBadges[BadgeIndex::Shop]) |
||
5258 |
if (show && |
||
5259 |
mShop && |
||
5260 |
mShowBadges != BadgeDrawType::Hide) |
||
5261 |
{ |
||
5262 |
const std::string badge = paths.getStringValue("shopbadge"); |
||
5263 |
if (!badge.empty()) |
||
5264 |
{ |
||
5265 |
mBadges[BadgeIndex::Shop] = AnimatedSprite::load( |
||
5266 |
paths.getStringValue("badges") + badge, |
||
5267 |
0); |
||
5268 |
} |
||
5269 |
} |
||
5270 |
updateBadgesCount(); |
||
5271 |
updateBadgesPosition(); |
||
5272 |
} |
||
5273 |
|||
5274 |
void Being::showInactiveBadge(const bool show) restrict2 |
||
5275 |
{ |
||
5276 |
delete2(mBadges[BadgeIndex::Inactive]) |
||
5277 |
if (show && |
||
5278 |
mInactive && |
||
5279 |
mShowBadges != BadgeDrawType::Hide) |
||
5280 |
{ |
||
5281 |
const std::string badge = paths.getStringValue("inactivebadge"); |
||
5282 |
if (!badge.empty()) |
||
5283 |
{ |
||
5284 |
mBadges[BadgeIndex::Inactive] = AnimatedSprite::load( |
||
5285 |
paths.getStringValue("badges") + badge, |
||
5286 |
0); |
||
5287 |
} |
||
5288 |
} |
||
5289 |
updateBadgesCount(); |
||
5290 |
updateBadgesPosition(); |
||
5291 |
} |
||
5292 |
|||
5293 |
void Being::showAwayBadge(const bool show) restrict2 |
||
5294 |
{ |
||
5295 |
delete2(mBadges[BadgeIndex::Away]) |
||
5296 |
if (show && |
||
5297 |
mAway && |
||
5298 |
mShowBadges != BadgeDrawType::Hide) |
||
5299 |
{ |
||
5300 |
const std::string badge = paths.getStringValue("awaybadge"); |
||
5301 |
if (!badge.empty()) |
||
5302 |
{ |
||
5303 |
mBadges[BadgeIndex::Away] = AnimatedSprite::load( |
||
5304 |
paths.getStringValue("badges") + badge, |
||
5305 |
0); |
||
5306 |
} |
||
5307 |
} |
||
5308 |
updateBadgesCount(); |
||
5309 |
updateBadgesPosition(); |
||
5310 |
} |
||
5311 |
|||
5312 |
void Being::updateBadgesCount() restrict2 |
||
5313 |
{ |
||
5314 |
mBadgesCount = 0; |
||
5315 |
for_each_badges() |
||
5316 |
{ |
||
5317 |
if (mBadges[f] != nullptr) |
||
5318 |
mBadgesCount ++; |
||
5319 |
} |
||
5320 |
} |
||
5321 |
|||
5322 |
void Being::setChat(ChatObject *restrict const obj) restrict2 |
||
5323 |
{ |
||
5324 |
delete mChat; |
||
5325 |
mChat = obj; |
||
5326 |
} |
||
5327 |
|||
5328 |
void Being::setSellBoard(const std::string &restrict text) restrict2 |
||
5329 |
{ |
||
5330 |
mShop = !text.empty() || !mBuyBoard.empty(); |
||
5331 |
mSellBoard = text; |
||
5332 |
updateName(); |
||
5333 |
showShopBadge(mShop); |
||
5334 |
} |
||
5335 |
|||
5336 |
void Being::setBuyBoard(const std::string &restrict text) restrict2 |
||
5337 |
{ |
||
5338 |
mShop = !text.empty() || !mSellBoard.empty(); |
||
5339 |
mBuyBoard = text; |
||
5340 |
updateName(); |
||
5341 |
showShopBadge(mShop); |
||
5342 |
} |
||
5343 |
|||
5344 |
void Being::enableShop(const bool b) restrict2 |
||
5345 |
{ |
||
5346 |
mShop = b; |
||
5347 |
updateName(); |
||
5348 |
showShopBadge(mShop); |
||
5349 |
} |
||
5350 |
|||
5351 |
bool Being::isBuyShopEnabled() const restrict2 |
||
5352 |
{ |
||
5353 |
return mShop && (Net::getNetworkType() == ServerType::TMWATHENA || |
||
5354 |
!mBuyBoard.empty()); |
||
5355 |
} |
||
5356 |
|||
5357 |
bool Being::isSellShopEnabled() const restrict2 |
||
5358 |
{ |
||
5359 |
return mShop && (Net::getNetworkType() == ServerType::TMWATHENA || |
||
5360 |
!mSellBoard.empty()); |
||
5361 |
} |
||
5362 |
|||
5363 |
void Being::serverRemove() restrict2 noexcept2 |
||
5364 |
{ |
||
5365 |
// remove some flags what can survive player remove and next visible |
||
5366 |
mTrickDead = false; |
||
5367 |
} |
||
5368 |
|||
5369 |
void Being::addCast(const int dstX, |
||
5370 |
const int dstY, |
||
5371 |
const int skillId, |
||
5372 |
const int skillLevel, |
||
5373 |
const int range, |
||
5374 |
const int waitTimeTicks) |
||
5375 |
{ |
||
5376 |
if (waitTimeTicks <= 0) |
||
5377 |
{ |
||
5378 |
mCastEndTime = 0; |
||
5379 |
return; |
||
5380 |
} |
||
5381 |
mCastEndTime = tick_time + waitTimeTicks; |
||
5382 |
SkillData *const data = skillDialog->getSkillDataByLevel( |
||
5383 |
skillId, |
||
5384 |
skillLevel); |
||
5385 |
delete2(mCastingEffect) |
||
5386 |
if (data != nullptr) |
||
5387 |
{ |
||
5388 |
const std::string castingAnimation = data->castingAnimation; |
||
5389 |
mCastingEffect = new CastingEffect(skillId, |
||
5390 |
skillLevel, |
||
5391 |
castingAnimation, |
||
5392 |
dstX, |
||
5393 |
dstY, |
||
5394 |
range); |
||
5395 |
mCastingEffect->setMap(mMap); |
||
5396 |
} |
||
5397 |
else |
||
5398 |
{ |
||
5399 |
reportAlways("Want to draw casting for unknown skill %d", |
||
5400 |
skillId) |
||
5401 |
} |
||
5402 |
} |
||
5403 |
|||
5404 |
103 |
void Being::removeHorse() restrict2 |
|
5405 |
{ |
||
5406 |
206 |
delete_all(mUpHorseSprites); |
|
5407 |
206 |
mUpHorseSprites.clear(); |
|
5408 |
206 |
delete_all(mDownHorseSprites); |
|
5409 |
206 |
mDownHorseSprites.clear(); |
|
5410 |
103 |
} |
|
5411 |
|||
5412 |
void Being::setRiding(const bool b) restrict2 |
||
5413 |
{ |
||
5414 |
if (serverFeatures->haveExtendedRiding()) |
||
5415 |
return; |
||
5416 |
|||
5417 |
if (b == (mHorseId != 0)) |
||
5418 |
return; |
||
5419 |
if (b) |
||
5420 |
setHorse(1); |
||
5421 |
else |
||
5422 |
setHorse(0); |
||
5423 |
} |
||
5424 |
|||
5425 |
void Being::setHorse(const int horseId) restrict2 |
||
5426 |
{ |
||
5427 |
if (mHorseId == horseId) |
||
5428 |
return; |
||
5429 |
mHorseId = horseId; |
||
5430 |
setAction(mAction, 0); |
||
5431 |
removeHorse(); |
||
5432 |
if (mHorseId != 0) |
||
5433 |
{ |
||
5434 |
mHorseInfo = HorseDB::get(horseId, false); |
||
5435 |
if (mHorseInfo != nullptr) |
||
5436 |
{ |
||
5437 |
FOR_EACH (SpriteRefs, it, mHorseInfo->downSprites) |
||
5438 |
{ |
||
5439 |
const SpriteReference *restrict const ref = *it; |
||
5440 |
AnimatedSprite *const sprite = AnimatedSprite::load( |
||
5441 |
ref->sprite, |
||
5442 |
ref->variant); |
||
5443 |
mDownHorseSprites.push_back(sprite); |
||
5444 |
sprite->play(mSpriteAction); |
||
5445 |
sprite->setSpriteDirection(mSpriteDirection); |
||
5446 |
} |
||
5447 |
FOR_EACH (SpriteRefs, it, mHorseInfo->upSprites) |
||
5448 |
{ |
||
5449 |
const SpriteReference *restrict const ref = *it; |
||
5450 |
AnimatedSprite *const sprite = AnimatedSprite::load( |
||
5451 |
ref->sprite, |
||
5452 |
ref->variant); |
||
5453 |
mUpHorseSprites.push_back(sprite); |
||
5454 |
sprite->play(mSpriteAction); |
||
5455 |
sprite->setSpriteDirection(mSpriteDirection); |
||
5456 |
} |
||
5457 |
} |
||
5458 |
} |
||
5459 |
else |
||
5460 |
{ |
||
5461 |
mHorseInfo = nullptr; |
||
5462 |
} |
||
5463 |
} |
||
5464 |
|||
5465 |
void Being::setTrickDead(const bool b) restrict2 |
||
5466 |
{ |
||
5467 |
if (b != mTrickDead) |
||
5468 |
{ |
||
5469 |
mTrickDead = b; |
||
5470 |
setAction(mAction, 0); |
||
5471 |
} |
||
5472 |
} |
||
5473 |
|||
5474 |
void Being::setSpiritBalls(const unsigned int balls) restrict2 |
||
5475 |
{ |
||
5476 |
if (!ParticleEngine::enabled) |
||
5477 |
{ |
||
5478 |
mSpiritBalls = balls; |
||
5479 |
return; |
||
5480 |
} |
||
5481 |
|||
5482 |
if (balls > mSpiritBalls) |
||
5483 |
{ |
||
5484 |
const int effectId = paths.getIntValue("spiritEffectId"); |
||
5485 |
if (effectId != -1) |
||
5486 |
addSpiritBalls(balls - mSpiritBalls, effectId); |
||
5487 |
} |
||
5488 |
else if (balls < mSpiritBalls) |
||
5489 |
{ |
||
5490 |
removeSpiritBalls(mSpiritBalls - balls); |
||
5491 |
} |
||
5492 |
mSpiritBalls = balls; |
||
5493 |
} |
||
5494 |
|||
5495 |
void Being::addSpiritBalls(const unsigned int balls, |
||
5496 |
const int effectId) restrict2 |
||
5497 |
{ |
||
5498 |
if (effectManager == nullptr) |
||
5499 |
return; |
||
5500 |
for (unsigned int f = 0; f < balls; f ++) |
||
5501 |
{ |
||
5502 |
Particle *const particle = effectManager->triggerReturn( |
||
5503 |
effectId, |
||
5504 |
this, |
||
5505 |
0); |
||
5506 |
mSpiritParticles.push_back(particle); |
||
5507 |
} |
||
5508 |
} |
||
5509 |
|||
5510 |
void Being::removeSpiritBalls(const unsigned int balls) restrict2 |
||
5511 |
{ |
||
5512 |
if (particleEngine == nullptr) |
||
5513 |
return; |
||
5514 |
for (unsigned int f = 0; f < balls && !mSpiritParticles.empty(); f ++) |
||
5515 |
{ |
||
5516 |
const Particle *restrict const particle = mSpiritParticles.back(); |
||
5517 |
mChildParticleEffects.removeLocally(particle); |
||
5518 |
mSpiritParticles.pop_back(); |
||
5519 |
} |
||
5520 |
} |
||
5521 |
|||
5522 |
void Being::stopCast(const bool b) |
||
5523 |
{ |
||
5524 |
if (b && mAction == BeingAction::CAST) |
||
5525 |
setAction(BeingAction::STAND, 0); |
||
5526 |
} |
||
5527 |
|||
5528 |
void Being::fixDirectionOffsets(int &offsetX, |
||
5529 |
int &offsetY) const |
||
5530 |
{ |
||
5531 |
const uint8_t dir = mDirection; |
||
5532 |
if ((dir & BeingDirection::DOWN) != 0) |
||
5533 |
{ |
||
5534 |
// do nothing |
||
5535 |
} |
||
5536 |
else if ((dir & BeingDirection::UP) != 0) |
||
5537 |
{ |
||
5538 |
offsetX = -offsetX; |
||
5539 |
offsetY = -offsetY; |
||
5540 |
} |
||
5541 |
else if ((dir & BeingDirection::LEFT) != 0) |
||
5542 |
{ |
||
5543 |
const int tmp = offsetY; |
||
5544 |
offsetY = offsetX; |
||
5545 |
offsetX = -tmp; |
||
5546 |
} |
||
5547 |
else if ((dir & BeingDirection::RIGHT) != 0) |
||
5548 |
{ |
||
5549 |
const int tmp = offsetY; |
||
5550 |
offsetY = -offsetX; |
||
5551 |
offsetX = tmp; |
||
5552 |
} |
||
5553 |
} |
||
5554 |
|||
5555 |
void Being::setLanguageId(const int lang) restrict2 noexcept2 |
||
5556 |
{ |
||
5557 |
if (lang != mLanguageId) |
||
5558 |
{ |
||
5559 |
delete2(mBadges[BadgeIndex::Lang]) |
||
5560 |
const std::string &badge = LanguageDb::getIcon(lang); |
||
5561 |
if (!badge.empty()) |
||
5562 |
{ |
||
5563 |
mBadges[BadgeIndex::Lang] = AnimatedSprite::load(pathJoin( |
||
5564 |
paths.getStringValue("languageIcons"), |
||
5565 |
badge), |
||
5566 |
0); |
||
5567 |
} |
||
5568 |
|||
5569 |
mLanguageId = lang; |
||
5570 |
} |
||
5571 |
updateBadgesCount(); |
||
5572 |
updateBadgesPosition(); |
||
5573 |
} |
||
5574 |
|||
5575 |
9 |
Being *Being::createBeing(const BeingId id, |
|
5576 |
const ActorTypeT type, |
||
5577 |
const BeingTypeId subType, |
||
5578 |
Map *const map) |
||
5579 |
{ |
||
5580 |
Being *const being = new Being(id, |
||
5581 |
✓✗ | 9 |
type); |
5582 |
being->postInit(subType, |
||
5583 |
9 |
map); |
|
5584 |
9 |
return being; |
|
5585 |
} |
||
5586 |
|||
5587 |
void Being::setGroupId(const int id) |
||
5588 |
{ |
||
5589 |
if (mGroupId != id) |
||
5590 |
{ |
||
5591 |
mGroupId = id; |
||
5592 |
const bool gm = GroupDb::getHighlightName(mGroupId); |
||
5593 |
if (mIsGM != gm) |
||
5594 |
{ |
||
5595 |
mIsGM = gm; |
||
5596 |
updateColors(); |
||
5597 |
} |
||
5598 |
showGmBadge(id != 0); |
||
5599 |
} |
||
5600 |
✓✗✓✗ |
3 |
} |
Generated by: GCOVR (Version 3.3) |