SabrehavenServer/src/creature.h
2019-09-16 20:38:16 +03:00

549 lines
16 KiB
C++

/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef FS_CREATURE_H_5363C04015254E298F84E6D59A139508
#define FS_CREATURE_H_5363C04015254E298F84E6D59A139508
#include "map.h"
#include "position.h"
#include "condition.h"
#include "const.h"
#include "tile.h"
#include "enums.h"
#include "creatureevent.h"
typedef std::list<Condition*> ConditionList;
typedef std::list<CreatureEvent*> CreatureEventList;
enum slots_t : uint8_t {
CONST_SLOT_WHEREEVER = 0,
CONST_SLOT_HEAD = 1,
CONST_SLOT_NECKLACE = 2,
CONST_SLOT_BACKPACK = 3,
CONST_SLOT_ARMOR = 4,
CONST_SLOT_RIGHT = 5,
CONST_SLOT_LEFT = 6,
CONST_SLOT_LEGS = 7,
CONST_SLOT_FEET = 8,
CONST_SLOT_RING = 9,
CONST_SLOT_AMMO = 10,
CONST_SLOT_FIRST = CONST_SLOT_HEAD,
CONST_SLOT_LAST = CONST_SLOT_AMMO,
};
struct FindPathParams {
bool fullPathSearch = true;
bool clearSight = true;
bool allowDiagonal = true;
bool keepDistance = false;
int32_t maxSearchDist = 0;
int32_t minTargetDist = -1;
int32_t maxTargetDist = -1;
};
class Map;
class Thing;
class Container;
class Player;
class Monster;
class Npc;
class Item;
class Tile;
class Combat;
static constexpr int32_t EVENT_CREATURECOUNT = 10;
static constexpr int32_t EVENT_CREATURE_THINK_INTERVAL = 1000;
static constexpr int32_t EVENT_CHECK_CREATURE_INTERVAL = (EVENT_CREATURE_THINK_INTERVAL / EVENT_CREATURECOUNT);
class FrozenPathingConditionCall
{
public:
explicit FrozenPathingConditionCall(Position targetPos) : targetPos(std::move(targetPos)) {}
bool operator()(const Position& startPos, const Position& testPos,
const FindPathParams& fpp, int32_t& bestMatchDist) const;
bool isInRange(const Position& startPos, const Position& testPos,
const FindPathParams& fpp) const;
protected:
Position targetPos;
};
//////////////////////////////////////////////////////////////////////
// Defines the Base class for all creatures and base functions which
// every creature has
class Creature : virtual public Thing
{
protected:
Creature();
public:
virtual ~Creature();
// non-copyable
Creature(const Creature&) = delete;
Creature& operator=(const Creature&) = delete;
Creature* getCreature() final {
return this;
}
const Creature* getCreature() const final {
return this;
}
virtual Player* getPlayer() {
return nullptr;
}
virtual const Player* getPlayer() const {
return nullptr;
}
virtual Npc* getNpc() {
return nullptr;
}
virtual const Npc* getNpc() const {
return nullptr;
}
virtual Monster* getMonster() {
return nullptr;
}
virtual const Monster* getMonster() const {
return nullptr;
}
virtual const std::string& getName() const = 0;
virtual const std::string& getNameDescription() const = 0;
virtual void setID() = 0;
void setRemoved() {
isInternalRemoved = true;
}
uint32_t getID() const {
return id;
}
virtual void removeList() = 0;
virtual void addList() = 0;
virtual bool canSee(const Position& pos) const;
virtual bool canSeeCreature(const Creature* creature) const;
virtual RaceType_t getRace() const {
return RACE_NONE;
}
virtual Skulls_t getSkull() const {
return skull;
}
virtual Skulls_t getSkullClient(const Creature* creature) const {
return creature->getSkull();
}
void setSkull(Skulls_t newSkull);
Direction getDirection() const {
return direction;
}
void setDirection(Direction dir) {
direction = dir;
}
int32_t getThrowRange() const final {
return 1;
}
bool isPushable() const override {
return getWalkDelay() <= 0;
}
bool isRemoved() const final {
return isInternalRemoved;
}
virtual bool canSeeInvisibility() const {
return false;
}
virtual bool isInGhostMode() const {
return false;
}
int32_t getWalkDelay(Direction dir) const;
int32_t getWalkDelay() const;
int64_t getTimeSinceLastMove() const;
int64_t getEventStepTicks(bool onlyDelay = false) const;
int64_t getStepDuration(Direction dir) const;
int64_t getStepDuration() const;
virtual int32_t getStepSpeed() const {
return getSpeed();
}
int32_t getSpeed() const {
if (baseSpeed == 0) {
return 0;
}
return (2 * (varSpeed + baseSpeed)) + 80;
}
void setSpeed(int32_t varSpeedDelta) {
int32_t oldSpeed = getSpeed();
varSpeed += varSpeedDelta;
if (getSpeed() <= 0) {
stopEventWalk();
cancelNextWalk = true;
} else if (oldSpeed <= 0 && !listWalkDir.empty()) {
addEventWalk();
}
}
void setBaseSpeed(uint32_t newBaseSpeed) {
baseSpeed = newBaseSpeed;
}
uint32_t getBaseSpeed() const {
return baseSpeed;
}
int32_t getHealth() const {
return health;
}
virtual int32_t getMaxHealth() const {
return healthMax;
}
const Outfit_t getCurrentOutfit() const {
return currentOutfit;
}
void setCurrentOutfit(Outfit_t outfit) {
currentOutfit = outfit;
}
const Outfit_t getDefaultOutfit() const {
return defaultOutfit;
}
bool isInvisible() const;
ZoneType_t getZone() const {
return getTile()->getZone();
}
//walk functions
void startAutoWalk(const std::forward_list<Direction>& listDir);
void addEventWalk(bool firstStep = false);
void stopEventWalk();
virtual void goToFollowCreature();
//walk events
virtual void onWalk(Direction& dir);
virtual void onWalkAborted() {}
virtual void onWalkComplete() {}
//follow functions
Creature* getFollowCreature() const {
return followCreature;
}
virtual bool setFollowCreature(Creature* creature);
//follow events
virtual void onFollowCreature(const Creature*) {}
virtual void onFollowCreatureComplete(const Creature*) {}
//combat functions
Creature* getAttackedCreature() {
return attackedCreature;
}
virtual bool setAttackedCreature(Creature* creature);
virtual BlockType_t blockHit(Creature* attacker, CombatType_t combatType, int32_t& damage,
bool checkDefense = false, bool checkArmor = false, bool field = false);
void setMaster(Creature* creature) {
master = creature;
}
bool isSummon() const {
return master != nullptr;
}
Creature* getMaster() const {
return master;
}
void addSummon(Creature* creature);
void removeSummon(Creature* creature);
const std::list<Creature*>& getSummons() const {
return summons;
}
virtual int32_t getArmor() const {
return 0;
}
virtual int32_t getDefense() {
return 0;
}
bool addCondition(Condition* condition, bool force = false);
bool addCombatCondition(Condition* condition);
void removeCondition(ConditionType_t type, ConditionId_t conditionId, bool force = false);
void removeCondition(ConditionType_t type, bool force = false);
void removeCondition(Condition* condition, bool force = false);
void removeCombatCondition(ConditionType_t type);
Condition* getCondition(ConditionType_t type) const;
Condition* getCondition(ConditionType_t type, ConditionId_t conditionId, uint32_t subId = 0) const;
void executeConditions(uint32_t interval);
bool hasCondition(ConditionType_t type, uint32_t subId = 0) const;
virtual bool isImmune(ConditionType_t type) const;
virtual bool isImmune(CombatType_t type) const;
virtual bool isSuppress(ConditionType_t type) const;
virtual uint32_t getDamageImmunities() const {
return 0;
}
virtual uint32_t getConditionImmunities() const {
return 0;
}
virtual uint32_t getConditionSuppressions() const {
return 0;
}
virtual bool isAttackable() const {
return true;
}
virtual void changeHealth(int32_t healthChange, bool sendHealthChange = true);
void gainHealth(Creature* attacker, int32_t healthGain);
virtual void drainHealth(Creature* attacker, int32_t damage);
virtual bool challengeCreature(Creature*) {
return false;
}
virtual bool convinceCreature(Creature*) {
return false;
}
void onDeath();
virtual uint64_t getGainedExperience(Creature* attacker) const;
void addDamagePoints(Creature* attacker, int32_t damagePoints);
bool hasBeenAttacked(uint32_t attackerId);
//combat event functions
virtual void onAddCondition(ConditionType_t type);
virtual void onAddCombatCondition(ConditionType_t type);
virtual void onEndCondition(ConditionType_t type);
void onTickCondition(ConditionType_t type, bool& bRemove);
virtual void onCombatRemoveCondition(Condition* condition);
virtual void onAttackedCreature(Creature*) {}
virtual void onAttacked();
virtual void onAttackedCreatureDrainHealth(Creature* target, int32_t points);
virtual void onTargetCreatureGainHealth(Creature*, int32_t) {}
virtual bool onKilledCreature(Creature* target, bool lastHit = true);
virtual void onGainExperience(uint64_t gainExp, Creature* target);
virtual void onAttackedCreatureBlockHit(BlockType_t) {}
virtual void onBlockHit() {}
virtual void onChangeZone(ZoneType_t zone);
virtual void onAttackedCreatureChangeZone(ZoneType_t zone);
virtual void onIdleStatus();
virtual void getCreatureLight(LightInfo& light) const;
virtual void setNormalCreatureLight();
void setCreatureLight(LightInfo light) {
internalLight = light;
}
virtual void onThink(uint32_t interval);
void onAttacking(uint32_t interval);
virtual void onWalk();
virtual bool getNextStep(Direction& dir, uint32_t& flags);
void onAddTileItem(const Tile* tile, const Position& pos);
virtual void onUpdateTileItem(const Tile* tile, const Position& pos, const Item* oldItem,
const ItemType& oldType, const Item* newItem, const ItemType& newType);
virtual void onRemoveTileItem(const Tile* tile, const Position& pos, const ItemType& iType,
const Item* item);
virtual void onCreatureAppear(Creature* creature, bool isLogin);
virtual void onRemoveCreature(Creature* creature, bool isLogout);
virtual void onCreatureMove(Creature* creature, const Tile* newTile, const Position& newPos,
const Tile* oldTile, const Position& oldPos, bool teleport);
virtual void onAttackedCreatureDisappear(bool) {}
virtual void onFollowCreatureDisappear(bool) {}
virtual void onCreatureSay(Creature*, SpeakClasses, const std::string&) {}
virtual void onCreatureConvinced(const Creature*, const Creature*) {}
virtual void onPlacedCreature() {}
virtual bool getCombatValues(int32_t&, int32_t&) {
return false;
}
size_t getSummonCount() const {
return summons.size();
}
void setDropLoot(bool lootDrop) {
this->lootDrop = lootDrop;
}
void setLossSkill(bool skillLoss) {
this->skillLoss = skillLoss;
}
//creature script events
bool registerCreatureEvent(const std::string& name);
bool unregisterCreatureEvent(const std::string& name);
Cylinder* getParent() const final {
return tile;
}
void setParent(Cylinder* cylinder) final {
tile = static_cast<Tile*>(cylinder);
position = tile->getPosition();
}
inline const Position& getPosition() const final {
return position;
}
Tile* getTile() final {
return tile;
}
const Tile* getTile() const final {
return tile;
}
int32_t getWalkCache(const Position& pos) const;
const Position& getLastPosition() const {
return lastPosition;
}
void setLastPosition(Position newLastPos) {
lastPosition = newLastPos;
}
static bool canSee(const Position& myPos, const Position& pos, int32_t viewRangeX, int32_t viewRangeY);
double getDamageRatio(Creature* attacker) const;
bool getPathTo(const Position& targetPos, std::forward_list<Direction>& dirList, const FindPathParams& fpp) const;
bool getPathTo(const Position& targetPos, std::forward_list<Direction>& dirList, int32_t minTargetDist, int32_t maxTargetDist, bool fullPathSearch = true, bool clearSight = true, int32_t maxSearchDist = 0) const;
void incrementReferenceCounter() {
++referenceCounter;
}
void decrementReferenceCounter() {
if (--referenceCounter == 0) {
delete this;
}
}
protected:
virtual bool useCacheMap() const {
return false;
}
struct CountBlock_t {
int32_t total;
int64_t ticks;
};
static constexpr int32_t mapWalkWidth = Map::maxViewportX * 2 + 1;
static constexpr int32_t mapWalkHeight = Map::maxViewportY * 2 + 1;
static constexpr int32_t maxWalkCacheWidth = (mapWalkWidth - 1) / 2;
static constexpr int32_t maxWalkCacheHeight = (mapWalkHeight - 1) / 2;
Position position;
typedef std::map<uint32_t, CountBlock_t> CountMap;
CountMap damageMap;
std::list<Creature*> summons;
CreatureEventList eventsList;
ConditionList conditions;
std::forward_list<Direction> listWalkDir;
Tile* tile = nullptr;
Creature* attackedCreature = nullptr;
Creature* master = nullptr;
Creature* followCreature = nullptr;
int64_t earliestDefendTime = 0;
int64_t lastDefendTime = 0;
uint64_t lastWalkUpdate = 0;
uint64_t lastStep = 0;
uint32_t referenceCounter = 0;
uint32_t id = 0;
uint32_t scriptEventsBitField = 0;
uint32_t eventWalk = 0;
uint32_t walkUpdateTicks = 0;
uint32_t lastHitCreatureId = 0;
uint32_t blockCount = 0;
uint32_t blockTicks = 0;
uint32_t lastStepCost = 1;
uint32_t baseSpeed = 70;
uint32_t latestKillEvent = 0;
int32_t varSpeed = 0;
int32_t health = 1000;
int32_t healthMax = 1000;
Outfit_t currentOutfit;
Outfit_t defaultOutfit;
Position lastPosition;
LightInfo internalLight;
Direction direction = DIRECTION_SOUTH;
Skulls_t skull = SKULL_NONE;
bool localMapCache[mapWalkHeight][mapWalkWidth] = {{ false }};
bool isInternalRemoved = false;
bool isMapLoaded = false;
bool isUpdatingPath = false;
bool creatureCheck = false;
bool inCheckCreaturesVector = false;
bool skillLoss = true;
bool lootDrop = true;
bool cancelNextWalk = false;
bool hasFollowPath = false;
bool forceUpdateFollowPath = false;
//creature script events
bool hasEventRegistered(CreatureEventType_t event) const {
return (0 != (scriptEventsBitField & (static_cast<uint32_t>(1) << event)));
}
CreatureEventList getCreatureEvents(CreatureEventType_t type);
void updateMapCache();
void updateTileCache(const Tile* tile, int32_t dx, int32_t dy);
void updateTileCache(const Tile* tile, const Position& pos);
void onCreatureDisappear(const Creature* creature, bool isLogout);
virtual void doAttacking(uint32_t) {}
virtual bool hasExtraSwing() {
return false;
}
virtual uint64_t getLostExperience() const {
return 0;
}
virtual void dropLoot(Container*, Creature*) {}
virtual uint16_t getLookCorpse() const {
return 0;
}
virtual void getPathSearchParams(const Creature* creature, FindPathParams& fpp) const;
virtual void death(Creature*) {}
virtual bool dropCorpse(Creature* lastHitCreature, Creature* mostDamageCreature, bool lastHitUnjustified, bool mostDamageUnjustified);
virtual Item* getCorpse(Creature* lastHitCreature, Creature* mostDamageCreature);
friend class Game;
friend class Map;
friend class LuaScriptInterface;
friend class Combat;
};
#endif