1/**
2 * The Forgotten Server - a free and open-source MMORPG server emulator
3 * Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20#ifndef FS_PLAYER_H_4083D3D3A05B4EDE891B31BB720CD06F
21#define FS_PLAYER_H_4083D3D3A05B4EDE891B31BB720CD06F
22
23#include "auras.h"
24#include "container.h"
25#include "creature.h"
26#include "cylinder.h"
27#include "depotchest.h"
28#include "depotlocker.h"
29#include "enums.h"
30#include "groups.h"
31#include "guild.h"
32#include "inbox.h"
33#include "ioguild.h"
34#include "mounts.h"
35#include "outfit.h"
36#include "party.h"
37#include "protocolgame.h"
38#include "runeeffects.h"
39#include "shaders.h"
40#include "town.h"
41#include "vocation.h"
42#include "wings.h"
43
44class House;
45class NetworkMessage;
46class Weapon;
47class ProtocolGame;
48class Npc;
49class Party;
50class SchedulerTask;
51class Bed;
52class Guild;
53
54enum skillsid_t {
55 SKILLVALUE_LEVEL = 0,
56 SKILLVALUE_TRIES = 1,
57 SKILLVALUE_PERCENT = 2,
58};
59
60enum fightMode_t : uint8_t {
61 FIGHTMODE_ATTACK = 1,
62 FIGHTMODE_BALANCED = 2,
63 FIGHTMODE_DEFENSE = 3,
64};
65
66enum pvpMode_t : uint8_t {
67 PVP_MODE_DOVE = 0,
68 PVP_MODE_WHITE_HAND = 1,
69 PVP_MODE_YELLOW_HAND = 2,
70 PVP_MODE_RED_FIST = 3,
71};
72
73enum tradestate_t : uint8_t {
74 TRADE_NONE,
75 TRADE_INITIATED,
76 TRADE_ACCEPT,
77 TRADE_ACKNOWLEDGE,
78 TRADE_TRANSFER,
79};
80
81struct VIPEntry {
82 VIPEntry(uint32_t guid, std::string name, std::string description,
83 uint32_t icon, bool notify)
84 : guid(guid), name(std::move(name)), description(std::move(description)),
85 icon(icon), notify(notify) {}
86
87 uint32_t guid;
88 std::string name;
89 std::string description;
90 uint32_t icon;
91 bool notify;
92};
93
94struct OpenContainer {
95 Container *container;
96 uint16_t index;
97};
98
99struct OutfitEntry {
100 constexpr OutfitEntry(uint16_t lookType, uint8_t addons)
101 : lookType(lookType), addons(addons) {}
102
103 uint16_t lookType;
104 uint8_t addons;
105};
106
107struct Skill {
108 uint64_t tries = 0;
109 uint16_t level = 10;
110 uint8_t percent = 0;
111};
112
113using MuteCountMap = std::map<uint32_t, uint32_t>;
114
115static constexpr int32_t PLAYER_MAX_SPEED = 1500;
116static constexpr int32_t PLAYER_MIN_SPEED = 10;
117
118class Player final : public Creature, public Cylinder {
119public:
120 explicit Player(ProtocolGame_ptr p);
121 ~Player();
122
123 // non-copyable
124 Player(const Player &) = delete;
125 Player &operator=(const Player &) = delete;
126
127 Player *getPlayer() override { return this; }
128 const Player *getPlayer() const override { return this; }
129
130 void setID() override {
131 if (id == 0) {
132 id = playerAutoID++;
133 }
134 }
135
136 static MuteCountMap muteCountMap;
137
138 const std::string &getName() const override { return name; }
139 void setName(std::string name) { this->name = std::move(name); }
140 const std::string &getNameDescription() const override { return name; }
141 std::string getDescription(int32_t lookDistance) const override;
142
143 CreatureType_t getType() const override { return CREATURETYPE_PLAYER; }
144
145 uint8_t getCurrentMount() const;
146 void setCurrentMount(uint8_t mountId);
147 bool isMounted() const { return defaultOutfit.lookMount != 0; }
148 bool hasMount() const { return defaultOutfit.lookMount != 0; }
149 bool hasAura() const { return defaultOutfit.lookAura != 0; }
150 bool hasWings() const { return defaultOutfit.lookWings != 0; }
151 bool hasShader() const { return defaultOutfit.lookShader != 0; }
152 bool toggleMount(bool mount);
153 bool tameMount(uint8_t mountId);
154 bool untameMount(uint8_t mountId);
155 bool hasMount(const Mount *mount) const;
156 void dismount();
157
158 bool hasWing(const Wing *wing) const;
159 bool addWing(uint8_t wingId);
160 uint8_t getCurrentAura() const;
161 void setCurrentAura(uint8_t auraId);
162 bool hasAura(const Aura *aura) const;
163 bool addAura(uint8_t auraId);
164 uint8_t getCurrentWing() const;
165 void setCurrentWing(uint8_t wingId);
166 bool hasShader(const Shader *shader) const;
167 bool addShader(uint8_t shaderId);
168 bool hasRuneEffect(const RuneEffect *runeEffect) const;
169 bool addRuneEffect(uint8_t runeEffectId);
170 uint8_t getCurrentRuneEffect() const;
171 void setCurrentRuneEffect(uint8_t runeEffectId);
172 int32_t calculateRuneBaseDamage() const;
173
174 void sendFYIBox(const std::string &message) {
175 if (client) {
176 client->sendFYIBox(message);
177 }
178 }
179
180 void setGUID(uint32_t guid) { this->guid = guid; }
181 uint32_t getGUID() const { return guid; }
182 bool canSeeInvisibility() const override {
183 return hasFlag(PlayerFlag_CanSenseInvisibility) || group->access;
184 }
185
186 void removeList() override;
187 void addList() override;
188 void kickPlayer(bool displayEffect);
189
190 static uint64_t getExpForLevel(int32_t lv) {
191 lv--;
192 return ((50ULL * lv * lv * lv) - (150ULL * lv * lv) + (400ULL * lv)) / 3ULL;
193 }
194
195 uint16_t getStaminaMinutes() const { return staminaMinutes; }
196
197 bool addOfflineTrainingTries(skills_t skill, uint64_t tries);
198
199 void addOfflineTrainingTime(int32_t addTime) {
200 offlineTrainingTime =
201 std::min<int32_t>(12 * 3600 * 1000, offlineTrainingTime + addTime);
202 }
203 void removeOfflineTrainingTime(int32_t removeTime) {
204 offlineTrainingTime =
205 std::max<int32_t>(0, offlineTrainingTime - removeTime);
206 }
207 int32_t getOfflineTrainingTime() const { return offlineTrainingTime; }
208
209 int32_t getOfflineTrainingSkill() const { return offlineTrainingSkill; }
210 void setOfflineTrainingSkill(int32_t skill) { offlineTrainingSkill = skill; }
211
212 uint64_t getBankBalance() const { return bankBalance; }
213 void setBankBalance(uint64_t balance) { bankBalance = balance; }
214
215 Guild *getGuild() const { return guild; }
216
217 uint16_t getAttackOutfitLookType() const override;
218 void setGuild(Guild *guild);
219
220 GuildRank_ptr getGuildRank() const { return guildRank; }
221 void setGuildRank(GuildRank_ptr newGuildRank) { guildRank = newGuildRank; }
222
223 bool isGuildMate(const Player *player) const;
224
225 const std::string &getGuildNick() const { return guildNick; }
226 void setGuildNick(std::string nick) { guildNick = nick; }
227
228 bool isInWar(const Player *player) const;
229 bool isInWarList(uint32_t guildId) const;
230
231 void setLastWalkthroughAttempt(int64_t walkthroughAttempt) {
232 lastWalkthroughAttempt = walkthroughAttempt;
233 }
234 void setLastWalkthroughPosition(Position walkthroughPosition) {
235 lastWalkthroughPosition = walkthroughPosition;
236 }
237
238 Inbox *getInbox() const { return inbox; }
239
240 uint16_t getClientIcons() const;
241
242 const GuildWarVector &getGuildWarVector() const { return guildWarVector; }
243
244 Vocation *getVocation() const { return vocation; }
245
246 OperatingSystem_t getOperatingSystem() const { return operatingSystem; }
247 void setOperatingSystem(OperatingSystem_t clientos) {
248 operatingSystem = clientos;
249 }
250
251 uint16_t getProtocolVersion() const {
252 if (!client) {
253 return 0;
254 }
255
256 return client->getVersion();
257 }
258
259 bool hasSecureMode() const { return secureMode; }
260
261 void setParty(Party *party) { this->party = party; }
262 Party *getParty() const { return party; }
263 PartyShields_t getPartyShield(const Player *player) const;
264 bool isInviting(const Player *player) const;
265 bool isPartner(const Player *player) const;
266 void sendPlayerPartyIcons(Player *player);
267 bool addPartyInvitation(Party *party);
268 void removePartyInvitation(Party *party);
269 void clearPartyInvitations();
270
271 GuildEmblems_t getGuildEmblem(const Player *player) const;
272
273 uint64_t getSpentMana() const { return manaSpent; }
274
275 bool hasFlag(PlayerFlags value) const { return (group->flags & value) != 0; }
276
277 BedItem *getBedItem() { return bedItem; }
278 void setBedItem(BedItem *b) { bedItem = b; }
279
280 void addBlessing(uint8_t blessing) { blessings |= blessing; }
281 void removeBlessing(uint8_t blessing) { blessings &= ~blessing; }
282 bool hasBlessing(uint8_t value) const {
283 return (blessings & (static_cast<uint8_t>(1) << value)) != 0;
284 }
285
286 bool isOffline() const { return (getID() == 0); }
287 void disconnect() {
288 if (client) {
289 client->disconnect();
290 }
291 }
292 uint32_t getIP() const;
293
294 void addContainer(uint8_t cid, Container *container);
295 void closeContainer(uint8_t cid);
296 void setContainerIndex(uint8_t cid, uint16_t index);
297
298 Container *getContainerByID(uint8_t cid);
299 int8_t getContainerID(const Container *container) const;
300 uint16_t getContainerIndex(uint8_t cid) const;
301
302 bool canOpenCorpse(uint32_t ownerId) const;
303
304 void addStorageValue(const uint32_t key, const int32_t value,
305 const bool isLogin = false);
306 bool getStorageValue(const uint32_t key, int32_t &value) const;
307 void genReservedStorageRange();
308
309 void setGroup(Group *newGroup) { group = newGroup; }
310 Group *getGroup() const { return group; }
311
312 void setInMarket(bool value) { inMarket = value; }
313 bool isInMarket() const { return inMarket; }
314
315 void setLastDepotId(int16_t newId) { lastDepotId = newId; }
316 int16_t getLastDepotId() const { return lastDepotId; }
317
318 void resetIdleTime() { idleTime = 0; }
319
320 bool isInGhostMode() const override { return ghostMode; }
321 void switchGhostMode() { ghostMode = !ghostMode; }
322
323 uint32_t getAccount() const { return accountNumber; }
324 AccountType_t getAccountType() const { return accountType; }
325 uint32_t getLevel() const { return level; }
326 uint8_t getLevelPercent() const { return levelPercent; }
327 uint32_t getMagicLevel() const {
328 return std::max<int32_t>(0, magLevel + varStats[STAT_MAGICPOINTS]);
329 }
330 uint32_t getBaseMagicLevel() const { return magLevel; }
331 uint8_t getMagicLevelPercent() const { return magLevelPercent; }
332 uint8_t getSoul() const { return soul; }
333 bool isAccessPlayer() const { return group->access; }
334 bool isPremium() const;
335 void setPremiumDays(int32_t v);
336
337 uint16_t getHelpers() const;
338
339 bool setVocation(uint16_t vocId);
340 uint16_t getVocationId() const { return vocation->getId(); }
341
342 PlayerSex_t getSex() const { return sex; }
343 void setSex(PlayerSex_t);
344 uint64_t getExperience() const { return experience; }
345
346 time_t getLastLoginSaved() const { return lastLoginSaved; }
347
348 time_t getLastLogout() const { return lastLogout; }
349
350 const Position &getLoginPosition() const { return loginPosition; }
351 const Position &getTemplePosition() const {
352 return town->getTemplePosition();
353 }
354 Town *getTown() const { return town; }
355 void setTown(Town *town) { this->town = town; }
356
357 void clearModalWindows();
358 bool hasModalWindowOpen(uint32_t modalWindowId) const;
359 void onModalWindowHandled(uint32_t modalWindowId);
360
361 bool isPushable() const override;
362 uint32_t isMuted() const;
363 void addMessageBuffer();
364 void removeMessageBuffer();
365
366 bool removeItemOfType(uint16_t itemId, uint32_t amount, int32_t subType,
367 bool ignoreEquipped = false) const;
368
369 uint32_t getCapacity() const {
370 if (hasFlag(PlayerFlag_CannotPickupItem)) {
371 return 0;
372 } else if (hasFlag(PlayerFlag_HasInfiniteCapacity)) {
373 return std::numeric_limits<uint32_t>::max();
374 }
375 return capacity;
376 }
377
378 uint32_t getFreeCapacity() const {
379 if (hasFlag(PlayerFlag_CannotPickupItem)) {
380 return 0;
381 } else if (hasFlag(PlayerFlag_HasInfiniteCapacity)) {
382 return std::numeric_limits<uint32_t>::max();
383 } else {
384 return std::max<int32_t>(0, capacity - inventoryWeight);
385 }
386 }
387
388 int32_t getMaxHealth() const override {
389 return std::max<int32_t>(1, healthMax + varStats[STAT_MAXHITPOINTS]);
390 }
391 uint32_t getMana() const { return mana; }
392 uint32_t getMaxMana() const {
393 return std::max<int32_t>(0, manaMax + varStats[STAT_MAXMANAPOINTS]);
394 }
395
396 Item *getInventoryItem(slots_t slot) const;
397
398 bool isItemAbilityEnabled(slots_t slot) const {
399 return inventoryAbilities[slot];
400 }
401 void setItemAbility(slots_t slot, bool enabled) {
402 inventoryAbilities[slot] = enabled;
403 }
404
405 void setVarSkill(skills_t skill, int32_t modifier) {
406 varSkills[skill] += modifier;
407 }
408
409 void setVarSpecialSkill(SpecialSkills_t skill, int32_t modifier) {
410 varSpecialSkills[skill] += modifier;
411 }
412
413 void setVarStats(stats_t stat, int32_t modifier);
414 int32_t getDefaultStats(stats_t stat) const;
415
416 void addConditionSuppressions(uint32_t conditions);
417 void removeConditionSuppressions(uint32_t conditions);
418
419 DepotChest *getDepotChest(uint32_t depotId, bool autoCreate);
420 DepotLocker *getDepotLocker(uint32_t depotId);
421 void onReceiveMail() const;
422 bool isNearDepotBox() const;
423
424 bool canSee(const Position &pos) const override;
425 bool canSeeCreature(const Creature *creature) const override;
426
427 bool canWalkthrough(const Creature *creature) const;
428 bool canWalkthroughEx(const Creature *creature) const;
429
430 RaceType_t getRace() const override { return RACE_BLOOD; }
431
432 uint64_t getMoney() const;
433
434 // safe-trade functions
435 void setTradeState(tradestate_t state) { tradeState = state; }
436 tradestate_t getTradeState() const { return tradeState; }
437 Item *getTradeItem() { return tradeItem; }
438
439 // shop functions
440 void setShopOwner(Npc *owner, int32_t onBuy, int32_t onSell) {
441 shopOwner = owner;
442 purchaseCallback = onBuy;
443 saleCallback = onSell;
444 }
445
446 Npc *getShopOwner(int32_t &onBuy, int32_t &onSell) {
447 onBuy = purchaseCallback;
448 onSell = saleCallback;
449 return shopOwner;
450 }
451
452 const Npc *getShopOwner(int32_t &onBuy, int32_t &onSell) const {
453 onBuy = purchaseCallback;
454 onSell = saleCallback;
455 return shopOwner;
456 }
457
458 // V.I.P. functions
459 void notifyStatusChange(Player *loginPlayer, VipStatus_t status);
460 bool removeVIP(uint32_t vipGuid);
461 bool addVIP(uint32_t vipGuid, const std::string &vipName, VipStatus_t status);
462 bool addVIPInternal(uint32_t vipGuid);
463 bool editVIP(uint32_t vipGuid, const std::string &description, uint32_t icon,
464 bool notify);
465
466 // follow functions
467 bool setFollowCreature(Creature *creature) override;
468 void goToFollowCreature() override;
469
470 // follow events
471 void onFollowCreature(const Creature *creature) override;
472
473 // walk events
474 void onWalk(Direction &dir) override;
475 void onWalkAborted() override;
476 void onWalkComplete() override;
477
478 void stopWalk();
479 void openShopWindow(Npc *npc, const std::list<ShopInfo> &shop);
480 bool closeShopWindow(bool sendCloseShopWindow = true);
481 bool updateSaleShopList(const Item *item);
482 bool hasShopItemForSale(uint32_t itemId, uint8_t subType) const;
483
484 void setChaseMode(bool mode);
485 void setFightMode(fightMode_t mode) { fightMode = mode; }
486 void setSecureMode(bool mode) { secureMode = mode; }
487
488 // combat functions
489 bool setAttackedCreature(Creature *creature) override;
490 bool isImmune(CombatType_t type) const override;
491 bool isImmune(ConditionType_t type) const override;
492 bool hasShield() const;
493 bool isAttackable() const override;
494 static bool lastHitIsPlayer(Creature *lastHitCreature);
495
496 void changeHealth(int32_t healthChange,
497 bool sendHealthChange = true) override;
498 void changeMana(int32_t manaChange);
499 void changeSoul(int32_t soulChange);
500
501 bool isPzLocked() const { return pzLocked; }
502 BlockType_t blockHit(Creature *attacker, CombatType_t combatType,
503 int32_t &damage, bool checkDefense = false,
504 bool checkArmor = false, bool field = false) override;
505 void doAttacking(uint32_t interval) override;
506 bool hasExtraSwing() override {
507 return lastAttack > 0 && ((OTSYS_TIME() - lastAttack) >= getAttackSpeed());
508 }
509
510 uint16_t getSpecialSkill(uint8_t skill) const {
511 return std::max<int32_t>(0, varSpecialSkills[skill]);
512 }
513 uint16_t getSkillLevel(uint8_t skill) const {
514 return std::max<int32_t>(0, skills[skill].level + varSkills[skill]);
515 }
516 uint16_t getBaseSkill(uint8_t skill) const { return skills[skill].level; }
517 uint8_t getSkillPercent(uint8_t skill) const { return skills[skill].percent; }
518
519 bool getAddAttackSkill() const { return addAttackSkillPoint; }
520 BlockType_t getLastAttackBlockType() const { return lastAttackBlockType; }
521
522 Item *getWeapon(slots_t slot, bool ignoreAmmo) const;
523 Item *getWeapon(bool ignoreAmmo = false) const;
524 WeaponType_t getWeaponType() const;
525 int32_t getWeaponSkill(const Item *item) const;
526 void getShieldAndWeapon(const Item *&shield, const Item *&weapon) const;
527
528 void drainHealth(Creature *attacker, int32_t damage) override;
529 void drainMana(Creature *attacker, int32_t manaLoss);
530 void addManaSpent(uint64_t amount);
531 void addSkillAdvance(skills_t skill, uint64_t count);
532
533 int32_t getArmor() const override;
534 int32_t getDefense() const override;
535 float getAttackFactor() const override;
536 float getDefenseFactor() const override;
537
538 void addInFightTicks(bool pzlock = false);
539
540 uint64_t getGainedExperience(Creature *attacker) const override;
541
542 // combat event functions
543 void onAddCondition(ConditionType_t type) override;
544 void onAddCombatCondition(ConditionType_t type) override;
545 void onEndCondition(ConditionType_t type) override;
546 void onCombatRemoveCondition(Condition *condition) override;
547 void onAttackedCreature(Creature *target, bool addFightTicks = true) override;
548 void onAttacked() override;
549 void onAttackedCreatureDrainHealth(Creature *target, int32_t points) override;
550 void onTargetCreatureGainHealth(Creature *target, int32_t points) override;
551 bool onKilledCreature(Creature *target, bool lastHit = true) override;
552 void onGainExperience(uint64_t gainExp, Creature *target) override;
553 void onGainSharedExperience(uint64_t gainExp, Creature *source);
554 void onAttackedCreatureBlockHit(BlockType_t blockType) override;
555 void onBlockHit() override;
556 void onChangeZone(ZoneType_t zone) override;
557 void onAttackedCreatureChangeZone(ZoneType_t zone) override;
558 void onIdleStatus() override;
559 void onPlacedCreature() override;
560
561 LightInfo getCreatureLight() const override;
562
563 Skulls_t getSkull() const override;
564 Skulls_t getSkullClient(const Creature *creature) const override;
565 int64_t getSkullTicks() const { return skullTicks; }
566 void setSkullTicks(int64_t ticks) { skullTicks = ticks; }
567
568 bool hasAttacked(const Player *attacked) const;
569 void addAttacked(const Player *attacked);
570 void removeAttacked(const Player *attacked);
571 void clearAttacked();
572 void addUnjustifiedDead(const Player *attacked);
573 void sendCreatureSkull(const Creature *creature) const {
574 if (client) {
575 client->sendCreatureSkull(creature);
576 }
577 }
578 void checkSkullTicks(int64_t ticks);
579
580 bool canWear(uint32_t lookType, uint8_t addons) const;
581 bool hasOutfit(uint32_t lookType, uint8_t addons);
582 void addOutfit(uint16_t lookType, uint8_t addons);
583 bool removeOutfit(uint16_t lookType);
584 bool removeOutfitAddon(uint16_t lookType, uint8_t addons);
585 bool getOutfitAddons(const Outfit &outfit, uint8_t &addons) const;
586
587 bool canLogout();
588
589 size_t getMaxVIPEntries() const;
590 size_t getMaxDepotItems() const;
591
592 // tile
593 // send methods
594 void sendAddTileItem(const Tile *tile, const Position &pos,
595 const Item *item) {
596 if (client) {
597 int32_t stackpos = tile->getStackposOfItem(this, item);
598 if (stackpos != -1) {
599 client->sendAddTileItem(pos, stackpos, item);
600 }
601 }
602 }
603 void sendUpdateTileItem(const Tile *tile, const Position &pos,
604 const Item *item) {
605 if (client) {
606 int32_t stackpos = tile->getStackposOfItem(this, item);
607 if (stackpos != -1) {
608 client->sendUpdateTileItem(pos, stackpos, item);
609 }
610 }
611 }
612 void sendRemoveTileThing(const Position &pos, int32_t stackpos) {
613 if (stackpos != -1 && client) {
614 client->sendRemoveTileThing(pos, stackpos);
615 }
616 }
617 void sendUpdateTile(const Tile *tile, const Position &pos) {
618 if (client) {
619 client->sendUpdateTile(tile, pos);
620 }
621 }
622
623 void sendChannelMessage(const std::string &author, const std::string &text,
624 SpeakClasses type, uint16_t channel) {
625 if (client) {
626 client->sendChannelMessage(author, text, type, channel);
627 }
628 }
629 void sendChannelEvent(uint16_t channelId, const std::string &playerName,
630 ChannelEvent_t channelEvent) {
631 if (client) {
632 client->sendChannelEvent(channelId, playerName, channelEvent);
633 }
634 }
635 void sendCreatureAppear(const Creature *creature, const Position &pos,
636 bool isLogin) {
637 if (client) {
638 client->sendAddCreature(
639 creature, pos,
640 creature->getTile()->getStackposOfCreature(this, creature), isLogin);
641 }
642 }
643 void sendCreatureMove(const Creature *creature, const Position &newPos,
644 int32_t newStackPos, const Position &oldPos,
645 int32_t oldStackPos, bool teleport) {
646 if (client) {
647 client->sendMoveCreature(creature, newPos, newStackPos, oldPos,
648 oldStackPos, teleport);
649 }
650 }
651 void sendCreatureTurn(const Creature *creature) {
652 if (client && canSeeCreature(creature)) {
653 int32_t stackpos =
654 creature->getTile()->getStackposOfCreature(this, creature);
655 if (stackpos != -1) {
656 client->sendCreatureTurn(creature, stackpos);
657 }
658 }
659 }
660 void sendCreatureSay(const Creature *creature, SpeakClasses type,
661 const std::string &text, const Position *pos = nullptr) {
662 if (client) {
663 client->sendCreatureSay(creature, type, text, pos);
664 }
665 }
666 void sendPrivateMessage(const Player *speaker, SpeakClasses type,
667 const std::string &text) {
668 if (client) {
669 client->sendPrivateMessage(speaker, type, text);
670 }
671 }
672 void sendCreatureSquare(const Creature *creature, SquareColor_t color) {
673 if (client) {
674 client->sendCreatureSquare(creature, color);
675 }
676 }
677 void sendCreatureChangeOutfit(const Creature *creature,
678 const Outfit_t &outfit) {
679 if (client) {
680 client->sendCreatureOutfit(creature, outfit);
681 }
682 }
683 void sendCreatureAttackPulse(const Creature *creature, const Outfit_t &outfit,
684 uint32_t duration) {
685 if (client) {
686 client->sendCreatureAttackPulse(creature, outfit, duration);
687 }
688 }
689 void sendCreatureChangeVisible(const Creature *creature, bool visible) {
690 if (!client) {
691 return;
692 }
693
694 if (creature->getPlayer()) {
695 if (visible) {
696 client->sendCreatureOutfit(creature, creature->getCurrentOutfit());
697 } else {
698 static Outfit_t outfit;
699 client->sendCreatureOutfit(creature, outfit);
700 }
701 } else if (canSeeInvisibility()) {
702 client->sendCreatureOutfit(creature, creature->getCurrentOutfit());
703 } else {
704 int32_t stackpos =
705 creature->getTile()->getStackposOfCreature(this, creature);
706 if (stackpos == -1) {
707 return;
708 }
709
710 if (visible) {
711 client->sendAddCreature(creature, creature->getPosition(), stackpos,
712 false);
713 } else {
714 client->sendRemoveTileThing(creature->getPosition(), stackpos);
715 }
716 }
717 }
718 void sendCreatureLight(const Creature *creature) {
719 if (client) {
720 client->sendCreatureLight(creature);
721 }
722 }
723 void sendCreatureWalkthrough(const Creature *creature, bool walkthrough) {
724 if (client) {
725 client->sendCreatureWalkthrough(creature, walkthrough);
726 }
727 }
728 void sendCreatureShield(const Creature *creature) {
729 if (client) {
730 client->sendCreatureShield(creature);
731 }
732 }
733 void sendCreatureType(uint32_t creatureId, uint8_t creatureType) {
734 if (client) {
735 client->sendCreatureType(creatureId, creatureType);
736 }
737 }
738 void sendCreatureHelpers(uint32_t creatureId, uint16_t helpers) {
739 if (client) {
740 client->sendCreatureHelpers(creatureId, helpers);
741 }
742 }
743 void sendSpellCooldown(uint8_t spellId, uint32_t time) {
744 if (client) {
745 client->sendSpellCooldown(spellId, time);
746 }
747 }
748 void sendSpellGroupCooldown(SpellGroup_t groupId, uint32_t time) {
749 if (client) {
750 client->sendSpellGroupCooldown(groupId, time);
751 }
752 }
753 void sendModalWindow(const ModalWindow &modalWindow);
754
755 // container
756 void sendAddContainerItem(const Container *container, const Item *item);
757 void sendUpdateContainerItem(const Container *container, uint16_t slot,
758 const Item *newItem);
759 void sendRemoveContainerItem(const Container *container, uint16_t slot);
760 void sendContainer(uint8_t cid, const Container *container, bool hasParent,
761 uint16_t firstIndex) {
762 if (client) {
763 client->sendContainer(cid, container, hasParent, firstIndex);
764 }
765 }
766
767 // inventory
768 void sendInventoryItem(slots_t slot, const Item *item) {
769 if (client) {
770 client->sendInventoryItem(slot, item);
771 }
772 }
773 void sendItems() {
774 if (client) {
775 client->sendItems();
776 }
777 }
778
779 // event methods
780 void onUpdateTileItem(const Tile *tile, const Position &pos,
781 const Item *oldItem, const ItemType &oldType,
782 const Item *newItem, const ItemType &newType) override;
783 void onRemoveTileItem(const Tile *tile, const Position &pos,
784 const ItemType &iType, const Item *item) override;
785
786 void onCreatureAppear(Creature *creature, bool isLogin) override;
787 void onRemoveCreature(Creature *creature, bool isLogout) override;
788 void onCreatureMove(Creature *creature, const Tile *newTile,
789 const Position &newPos, const Tile *oldTile,
790 const Position &oldPos, bool teleport) override;
791
792 void onAttackedCreatureDisappear(bool isLogout) override;
793 void onFollowCreatureDisappear(bool isLogout) override;
794
795 // container
796 void onAddContainerItem(const Item *item);
797 void onUpdateContainerItem(const Container *container, const Item *oldItem,
798 const Item *newItem);
799 void onRemoveContainerItem(const Container *container, const Item *item);
800
801 void onCloseContainer(const Container *container);
802 void onSendContainer(const Container *container);
803 void autoCloseContainers(const Container *container);
804
805 // inventory
806 void onUpdateInventoryItem(Item *oldItem, Item *newItem);
807 void onRemoveInventoryItem(Item *item);
808
809 void sendCancelMessage(const std::string &msg) const {
810 if (client) {
811 client->sendTextMessage(TextMessage(MESSAGE_STATUS_SMALL, msg));
812 }
813 }
814 void sendCancelMessage(ReturnValue message) const;
815 void sendCancelTarget() const {
816 if (client) {
817 client->sendCancelTarget();
818 }
819 }
820 void sendCancelWalk() const {
821 if (client) {
822 client->sendCancelWalk();
823 }
824 }
825 void sendNewCancelWalk() const {
826 if (client) {
827 client->sendNewCancelWalk();
828 }
829 }
830 void sendChangeSpeed(const Creature *creature, uint32_t newSpeed) const {
831 if (client) {
832 client->sendChangeSpeed(creature, newSpeed);
833 }
834 }
835 void sendCreatureHealth(const Creature *creature) const {
836 if (client) {
837 client->sendCreatureHealth(creature);
838 }
839 }
840 void sendDistanceShoot(const Position &from, const Position &to,
841 unsigned char type) const {
842 if (client) {
843 client->sendDistanceShoot(from, to, type);
844 }
845 }
846 void sendHouseWindow(House *house, uint32_t listId) const;
847 void sendCreatePrivateChannel(uint16_t channelId,
848 const std::string &channelName) {
849 if (client) {
850 client->sendCreatePrivateChannel(channelId, channelName);
851 }
852 }
853 void sendClosePrivate(uint16_t channelId);
854 void sendIcons() const {
855 if (client) {
856 client->sendIcons(getClientIcons());
857 }
858 }
859 void sendMagicEffect(const Position &pos, uint16_t type) const {
860 if (client) {
861 client->sendMagicEffect(pos, type);
862 }
863 }
864 void sendPing();
865 void sendPingBack() const {
866 if (client) {
867 client->sendPingBack();
868 }
869 }
870 void sendStats();
871 void sendBasicData() const {
872 if (client) {
873 client->sendBasicData();
874 }
875 }
876 void sendSkills() const {
877 if (client) {
878 client->sendSkills();
879 }
880 }
881 void sendTextMessage(MessageClasses mclass,
882 const std::string &message) const {
883 if (client) {
884 client->sendTextMessage(TextMessage(mclass, message));
885 }
886 }
887 void sendTextMessage(const TextMessage &message) const {
888 if (client) {
889 client->sendTextMessage(message);
890 }
891 }
892 void sendReLoginWindow(uint8_t unfairFightReduction) const {
893 if (client) {
894 client->sendReLoginWindow(unfairFightReduction);
895 }
896 }
897 void sendTextWindow(Item *item, uint16_t maxlen, bool canWrite) const {
898 if (client) {
899 client->sendTextWindow(windowTextId, item, maxlen, canWrite);
900 }
901 }
902 void sendTextWindow(uint32_t itemId, const std::string &text) const {
903 if (client) {
904 client->sendTextWindow(windowTextId, itemId, text);
905 }
906 }
907 void sendToChannel(const Creature *creature, SpeakClasses type,
908 const std::string &text, uint16_t channelId) const {
909 if (client) {
910 client->sendToChannel(creature, type, text, channelId);
911 }
912 }
913 void sendShop(Npc *npc) const {
914 if (client) {
915 client->sendShop(npc, shopItemList);
916 }
917 }
918 void sendSaleItemList() const {
919 if (client) {
920 client->sendSaleItemList(shopItemList);
921 }
922 }
923 void sendCloseShop() const {
924 if (client) {
925 client->sendCloseShop();
926 }
927 }
928 void sendMarketEnter(uint32_t depotId) const {
929 if (client) {
930 client->sendMarketEnter(depotId);
931 }
932 }
933 void sendMarketLeave() {
934 inMarket = false;
935 if (client) {
936 client->sendMarketLeave();
937 }
938 }
939 void sendMarketBrowseItem(uint16_t itemId, const MarketOfferList &buyOffers,
940 const MarketOfferList &sellOffers) const {
941 if (client) {
942 client->sendMarketBrowseItem(itemId, buyOffers, sellOffers);
943 }
944 }
945 void sendMarketBrowseOwnOffers(const MarketOfferList &buyOffers,
946 const MarketOfferList &sellOffers) const {
947 if (client) {
948 client->sendMarketBrowseOwnOffers(buyOffers, sellOffers);
949 }
950 }
951 void
952 sendMarketBrowseOwnHistory(const HistoryMarketOfferList &buyOffers,
953 const HistoryMarketOfferList &sellOffers) const {
954 if (client) {
955 client->sendMarketBrowseOwnHistory(buyOffers, sellOffers);
956 }
957 }
958 void sendMarketDetail(uint16_t itemId) const {
959 if (client) {
960 client->sendMarketDetail(itemId);
961 }
962 }
963 void sendMarketAcceptOffer(const MarketOfferEx &offer) const {
964 if (client) {
965 client->sendMarketAcceptOffer(offer);
966 }
967 }
968 void sendMarketCancelOffer(const MarketOfferEx &offer) const {
969 if (client) {
970 client->sendMarketCancelOffer(offer);
971 }
972 }
973 void sendTradeItemRequest(const std::string &traderName, const Item *item,
974 bool ack) const {
975 if (client) {
976 client->sendTradeItemRequest(traderName, item, ack);
977 }
978 }
979 void sendTradeClose() const {
980 if (client) {
981 client->sendCloseTrade();
982 }
983 }
984 void sendWorldLight(LightInfo lightInfo) {
985 if (client) {
986 client->sendWorldLight(lightInfo);
987 }
988 }
989 void sendChannelsDialog() {
990 if (client) {
991 client->sendChannelsDialog();
992 }
993 }
994 void sendOpenPrivateChannel(const std::string &receiver) {
995 if (client) {
996 client->sendOpenPrivateChannel(receiver);
997 }
998 }
999 void sendOutfitWindow() {
1000 if (client) {
1001 client->sendOutfitWindow();
1002 }
1003 }
1004 void sendCloseContainer(uint8_t cid) {
1005 if (client) {
1006 client->sendCloseContainer(cid);
1007 }
1008 }
1009
1010 void sendChannel(uint16_t channelId, const std::string &channelName,
1011 const UsersMap *channelUsers,
1012 const InvitedMap *invitedUsers) {
1013 if (client) {
1014 client->sendChannel(channelId, channelName, channelUsers, invitedUsers);
1015 }
1016 }
1017 void sendTutorial(uint8_t tutorialId) {
1018 if (client) {
1019 client->sendTutorial(tutorialId);
1020 }
1021 }
1022 void sendAddMarker(const Position &pos, uint8_t markType,
1023 const std::string &desc) {
1024 if (client) {
1025 client->sendAddMarker(pos, markType, desc);
1026 }
1027 }
1028 void sendQuestLog() {
1029 if (client) {
1030 client->sendQuestLog();
1031 }
1032 }
1033 void sendQuestLine(const Quest *quest) {
1034 if (client) {
1035 client->sendQuestLine(quest);
1036 }
1037 }
1038 void sendEnterWorld() {
1039 if (client) {
1040 client->sendEnterWorld();
1041 }
1042 }
1043 void sendFightModes() {
1044 if (client) {
1045 client->sendFightModes();
1046 }
1047 }
1048 void sendNetworkMessage(const NetworkMessage &message) {
1049 if (client) {
1050 client->writeToOutputBuffer(message);
1051 }
1052 }
1053
1054 void receivePing() { lastPong = OTSYS_TIME(); }
1055
1056 void setFPS(uint16_t value) { fps = value; }
1057 void setLocalPing(uint16_t value) { localPing = value; }
1058 uint16_t getFPS() const { return fps; }
1059 uint16_t getLocalPing() const { return localPing; }
1060 uint16_t getOTCv8Version() const {
1061 if (client)
1062 return client->otclientV8;
1063 return 0;
1064 }
1065
1066 void onThink(uint32_t interval) override;
1067
1068 void postAddNotification(Thing *thing, const Cylinder *oldParent,
1069 int32_t index,
1070 cylinderlink_t link = LINK_OWNER) override;
1071 void postRemoveNotification(Thing *thing, const Cylinder *newParent,
1072 int32_t index,
1073 cylinderlink_t link = LINK_OWNER) override;
1074
1075 void setNextAction(int64_t time) {
1076 if (time > nextAction) {
1077 nextAction = time;
1078 }
1079 }
1080 bool canDoAction() const { return nextAction <= OTSYS_TIME(); }
1081 uint32_t getNextActionTime() const;
1082
1083 Item *getWriteItem(uint32_t &windowTextId, uint16_t &maxWriteLen);
1084 void setWriteItem(Item *item, uint16_t maxWriteLen = 0);
1085
1086 House *getEditHouse(uint32_t &windowTextId, uint32_t &listId);
1087 void setEditHouse(House *house, uint32_t listId = 0);
1088
1089 void learnInstantSpell(const std::string &spellName);
1090 void forgetInstantSpell(const std::string &spellName);
1091 bool hasLearnedInstantSpell(const std::string &spellName) const;
1092
1093 void addEffect(uint16_t effectId);
1094
1095private:
1096 std::forward_list<Condition *> getMuteConditions() const;
1097
1098 void checkTradeState(const Item *item);
1099 bool hasCapacity(const Item *item, uint32_t count) const;
1100
1101 void gainExperience(uint64_t gainExp, Creature *source);
1102 void addExperience(Creature *source, uint64_t exp, bool sendText = false);
1103 void removeExperience(uint64_t exp, bool sendText = false);
1104
1105 void updateInventoryWeight();
1106
1107 void setNextWalkActionTask(SchedulerTask *task);
1108 void setNextWalkTask(SchedulerTask *task);
1109 void setNextActionTask(SchedulerTask *task, bool resetIdleTime = true);
1110
1111 void death(Creature *lastHitCreature) override;
1112 bool dropCorpse(Creature *lastHitCreature, Creature *mostDamageCreature,
1113 bool lastHitUnjustified, bool mostDamageUnjustified) override;
1114 Item *getCorpse(Creature *lastHitCreature,
1115 Creature *mostDamageCreature) override;
1116
1117 // cylinder implementations
1118 ReturnValue queryAdd(int32_t index, const Thing &thing, uint32_t count,
1119 uint32_t flags,
1120 Creature *actor = nullptr) const override;
1121 ReturnValue queryMaxCount(int32_t index, const Thing &thing, uint32_t count,
1122 uint32_t &maxQueryCount,
1123 uint32_t flags) const override;
1124 ReturnValue queryRemove(const Thing &thing, uint32_t count,
1125 uint32_t flags) const override;
1126 Cylinder *queryDestination(int32_t &index, const Thing &thing,
1127 Item **destItem, uint32_t &flags) override;
1128
1129 void addThing(Thing *) override {}
1130 void addThing(int32_t index, Thing *thing) override;
1131
1132 void updateThing(Thing *thing, uint16_t itemId, uint32_t count) override;
1133 void replaceThing(uint32_t index, Thing *thing) override;
1134
1135 void removeThing(Thing *thing, uint32_t count) override;
1136
1137 int32_t getThingIndex(const Thing *thing) const override;
1138 size_t getFirstIndex() const override;
1139 size_t getLastIndex() const override;
1140 uint32_t getItemTypeCount(uint16_t itemId,
1141 int32_t subType = -1) const override;
1142 std::map<uint32_t, uint32_t> &
1143 getAllItemTypeCount(std::map<uint32_t, uint32_t> &countMap) const override;
1144 Thing *getThing(size_t index) const override;
1145
1146 void internalAddThing(Thing *thing) override;
1147 void internalAddThing(uint32_t index, Thing *thing) override;
1148
1149 std::unordered_set<uint32_t> attackedSet;
1150 std::unordered_set<uint32_t> VIPList;
1151
1152 std::map<uint8_t, OpenContainer> openContainers;
1153 std::map<uint32_t, DepotLocker *> depotLockerMap;
1154 std::map<uint32_t, DepotChest *> depotChests;
1155 std::map<uint32_t, int32_t> storageMap;
1156
1157 std::vector<OutfitEntry> outfits;
1158 GuildWarVector guildWarVector;
1159
1160 std::list<ShopInfo> shopItemList;
1161
1162 std::forward_list<Party *> invitePartyList;
1163 std::forward_list<uint32_t> modalWindows;
1164 std::forward_list<std::string> learnedInstantSpellList;
1165 std::forward_list<Condition *>
1166 storedConditionList; // TODO: This variable is only temporarily used when
1167 // logging in, get rid of it somehow
1168
1169 std::string name;
1170 std::string guildNick;
1171
1172 Skill skills[SKILL_LAST + 1];
1173 LightInfo itemsLight;
1174 Position loginPosition;
1175 Position lastWalkthroughPosition;
1176
1177 time_t lastLoginSaved = 0;
1178 time_t lastLogout = 0;
1179
1180 uint64_t experience = 0;
1181 uint64_t manaSpent = 0;
1182 uint64_t lastAttack = 0;
1183 uint64_t bankBalance = 0;
1184 uint64_t lastQuestlogUpdate = 0;
1185 int64_t lastFailedFollow = 0;
1186 int64_t skullTicks = 0;
1187 int64_t lastWalkthroughAttempt = 0;
1188 int64_t lastToggleMount = 0;
1189 int64_t lastPing;
1190 int64_t lastPong;
1191 int64_t nextAction = 0;
1192 uint64_t lastRuneDamageTick = 0;
1193
1194 BedItem *bedItem = nullptr;
1195 Guild *guild = nullptr;
1196 GuildRank_ptr guildRank = nullptr;
1197 Group *group = nullptr;
1198 Inbox *inbox;
1199 Item *tradeItem = nullptr;
1200 Item *inventory[CONST_SLOT_LAST + 1] = {};
1201 Item *writeItem = nullptr;
1202 House *editHouse = nullptr;
1203 Npc *shopOwner = nullptr;
1204 Party *party = nullptr;
1205 Player *tradePartner = nullptr;
1206 ProtocolGame_ptr client;
1207 SchedulerTask *walkTask = nullptr;
1208 Town *town = nullptr;
1209 Vocation *vocation = nullptr;
1210
1211 uint32_t inventoryWeight = 0;
1212 uint32_t attackSpeed = 0;
1213 uint32_t capacity = 40000;
1214 uint32_t damageImmunities = 0;
1215 uint32_t conditionImmunities = 0;
1216 uint32_t conditionSuppressions = 0;
1217 uint32_t level = 1;
1218 uint32_t magLevel = 0;
1219 uint32_t actionTaskEvent = 0;
1220 uint32_t nextStepEvent = 0;
1221 uint32_t walkTaskEvent = 0;
1222 uint32_t MessageBufferTicks = 0;
1223 uint32_t lastIP = 0;
1224 uint32_t accountNumber = 0;
1225 uint32_t guid = 0;
1226 uint32_t windowTextId = 0;
1227 uint32_t editListId = 0;
1228 uint32_t mana = 0;
1229 uint32_t manaMax = 0;
1230 int32_t varSkills[SKILL_LAST + 1] = {};
1231 int32_t varSpecialSkills[SPECIALSKILL_LAST + 1] = {};
1232 int32_t varStats[STAT_LAST + 1] = {};
1233 int32_t purchaseCallback = -1;
1234 int32_t saleCallback = -1;
1235 int32_t MessageBufferCount = 0;
1236 int32_t premiumDays = 0;
1237 int32_t bloodHitCount = 0;
1238 int32_t shieldBlockCount = 0;
1239 int32_t offlineTrainingSkill = -1;
1240 int32_t offlineTrainingTime = 0;
1241 int32_t idleTime = 0;
1242
1243 uint16_t lastStatsTrainingTime = 0;
1244 uint16_t staminaMinutes = 2520;
1245 uint16_t maxWriteLen = 0;
1246 uint16_t localPing = 0;
1247 uint16_t fps = 0;
1248 int16_t lastDepotId = -1;
1249
1250 uint8_t soul = 0;
1251 uint8_t blessings = 0;
1252 uint8_t levelPercent = 0;
1253 uint8_t magLevelPercent = 0;
1254
1255 PlayerSex_t sex = PLAYERSEX_FEMALE;
1256 OperatingSystem_t operatingSystem = CLIENTOS_NONE;
1257 BlockType_t lastAttackBlockType = BLOCK_NONE;
1258 tradestate_t tradeState = TRADE_NONE;
1259 fightMode_t fightMode = FIGHTMODE_ATTACK;
1260 AccountType_t accountType = ACCOUNT_TYPE_NORMAL;
1261
1262 bool chaseMode = false;
1263 bool secureMode = false;
1264 bool inMarket = false;
1265 bool wasMounted = false;
1266 bool ghostMode = false;
1267 bool pzLocked = false;
1268 bool isConnecting = false;
1269 bool addAttackSkillPoint = false;
1270 bool inventoryAbilities[CONST_SLOT_LAST + 1] = {};
1271
1272 static uint32_t playerAutoID;
1273
1274 void updateItemsLight(bool internal = false);
1275 int32_t getStepSpeed() const override;
1276 void updateBaseSpeed() {
1277 if (!hasFlag(PlayerFlag_SetMaxSpeed)) {
1278 baseSpeed = vocation->getBaseSpeed() + (2 * (level - 1));
1279 } else {
1280 baseSpeed = PLAYER_MAX_SPEED;
1281 }
1282 }
1283
1284 bool isPromoted() const;
1285
1286 uint32_t getAttackSpeed() const {
1287 if (attackSpeed > 0) {
1288 return attackSpeed;
1289 }
1290 return vocation->getAttackSpeed();
1291 }
1292
1293 void setAttackSpeed(uint32_t speed) { attackSpeed = speed; }
1294
1295 static uint8_t getPercentLevel(uint64_t count, uint64_t nextLevelCount);
1296 double getLostPercent() const;
1297 uint64_t getLostExperience() const override {
1298 return skillLoss ? static_cast<uint64_t>(experience * getLostPercent()) : 0;
1299 }
1300 uint32_t getDamageImmunities() const override { return damageImmunities; }
1301 uint32_t getConditionImmunities() const override {
1302 return conditionImmunities;
1303 }
1304 uint32_t getConditionSuppressions() const override {
1305 return conditionSuppressions;
1306 }
1307 uint16_t getLookCorpse() const override;
1308 void getPathSearchParams(const Creature *creature,
1309 FindPathParams &fpp) const override;
1310
1311 friend class Game;
1312 friend class Npc;
1313 friend class LuaScriptInterface;
1314 friend class Map;
1315 friend class Actions;
1316 friend class IOLoginData;
1317 friend class ProtocolGame;
1318};
1319
1320#endif
1321