#pragma once #include "Towers.h" #include "Types.h" #include "Team.h" #include "misc/ObjectNotifier.h" #include #include #include namespace td { namespace game { struct WalkableTile; enum class EffectType : std::uint8_t { Slowness = 0, Stun, Fire, Poison, Heal, }; enum class MobType : std::uint8_t { Zombie = 0, Spider, Skeleton, Pigman, Creeper, Silverfish, Blaze, Witch, Slime, Giant, MOB_COUNT }; typedef std::uint32_t MobID; typedef std::uint8_t MobLevel; typedef std::vector TowerImmunities; typedef std::vector EffectImmunities; class MobStats { private: float m_Damage; float m_Speed; glm::vec2 m_Size; std::uint16_t m_MoneyCost; std::uint16_t m_ExpCost; std::uint16_t m_MaxLife; std::uint16_t m_ExpReward; public: MobStats(float damage, float speed, glm::vec2 size, std::uint16_t moneyCost, std::uint16_t expCost, std::uint16_t expReward, std::uint16_t maxLife) : m_Damage(damage), m_Speed(speed), m_Size(size), m_MoneyCost(moneyCost), m_ExpCost(expCost), m_MaxLife(maxLife), m_ExpReward(expReward) { } float getDamage() const { return m_Damage; } float getMovementSpeed() const { return m_Speed; } const glm::vec2& getSize() const { return m_Size; } std::uint16_t getMoneyCost() const { return m_MoneyCost; } std::uint16_t getExpCost() const { return m_ExpCost; } std::uint16_t getExpReward() const { return m_ExpReward; } std::uint16_t getMaxLife() const { return m_MaxLife; } }; struct EffectDuration { EffectType type; float duration; // in seconds Tower* tower; // the tower that gived the effect }; const MobStats* getMobStats(MobType type, std::uint8_t level); const TowerImmunities& getMobTowerImmunities(MobType type, std::uint8_t level); const EffectImmunities& getMobEffectImmunities(MobType type, std::uint8_t level); class Mob : public utils::shape::Rectangle { protected: float m_Health; private: MobID m_ID; PlayerID m_Sender; MobLevel m_Level; Direction m_Direction; std::vector m_Effects; const Tower* m_LastDamage; // the last tower that damaged the mob utils::Timer m_EffectFireTimer; utils::Timer m_EffectPoisonTimer; utils::Timer m_EffectHealTimer; TeamCastle* m_CastleTarget; utils::CooldownTimer m_AttackTimer; public: Mob(MobID id, MobLevel level, PlayerID sender) : m_Sender(sender), m_Level(level), m_EffectFireTimer(1000), m_EffectPoisonTimer(1000), m_EffectHealTimer(1000), m_CastleTarget(nullptr), m_AttackTimer(1000) { } virtual MobType getType() const = 0; virtual void tick(std::uint64_t delta, World* world); virtual bool OnDeath(World* world) { return true; } MobID getMobID() const { return m_ID; } const TowerImmunities& getTowerImmunities() const { return getMobTowerImmunities(getType(), m_Level); } const EffectImmunities& getEffectImmunities() const { return getMobEffectImmunities(getType(), m_Level); } PlayerID getSender() const { return m_Sender; } MobLevel getLevel() const { return m_Level; } const MobStats* getStats() const { return getMobStats(getType(), m_Level); } void setHealth(float newHealth) { m_Health = newHealth; } float getHealth() const { return m_Health; } bool isDead() const { return m_Health <= 0; } bool isAlive() const { return m_Health > 0; } const Tower* getLastDamageTower() { return m_LastDamage; } bool hasReachedEnemyCastle() { return m_CastleTarget != nullptr; } void damage(float dmg, const Tower* damager) { m_Health = std::max(0.0f, m_Health - dmg); m_LastDamage = damager; } void heal(float heal) { m_Health = std::min(static_cast(getStats()->getMaxLife()), m_Health + heal); } void setMobReachedCastle(TeamCastle* castle) { m_CastleTarget = castle; } // used when mob is in front of the castle bool isImmuneTo(TowerType type); bool isImmuneTo(EffectType type); void addEffect(EffectType type, float durationSec, Tower* tower); bool hasEffect(EffectType type); float getTileX() { return getCenterX() - static_cast(static_cast(getCenterX())); } // returns a float between 0 and 1 excluded float getTileY() { return getCenterY() - static_cast(static_cast(getCenterY())); } // returns a float between 0 and 1 excluded Direction getDirection() const { return m_Direction; } void setDirection(Direction dir) { m_Direction = dir; } protected: void initMob() { m_Health = static_cast(getStats()->getMaxLife()); setSize(getStats()->getSize().x, getStats()->getSize().y); } private: void updateEffects(std::uint64_t delta, World* world); void attackCastle(std::uint64_t delta, World* world); void move(std::uint64_t delta, World* world); void walk(std::uint64_t delta, World* world); void moveBack(const TeamCastle& castle, World* world); void changeDirection(const WalkableTile& tile, World* world); bool isTouchingCastle(const TeamCastle& castle) const; EffectDuration& getEffect(EffectType type); }; typedef std::shared_ptr MobPtr; class Zombie : public Mob { public: Zombie(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { initMob(); } virtual MobType getType() const { return MobType::Zombie; } }; class Spider : public Mob { public: Spider(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { initMob(); } virtual MobType getType() const { return MobType::Spider; } }; class Skeleton : public Mob { public: Skeleton(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { initMob(); } virtual MobType getType() const { return MobType::Skeleton; } }; class PigMan : public Mob { public: PigMan(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { initMob(); } virtual MobType getType() const { return MobType::Pigman; } }; class Creeper : public Mob { public: Creeper(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { initMob(); } virtual MobType getType() const { return MobType::Creeper; } }; class Silverfish : public Mob { public: Silverfish(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { initMob(); } virtual MobType getType() const { return MobType::Silverfish; } }; class Blaze : public Mob { public: Blaze(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { initMob(); } virtual MobType getType() const { return MobType::Blaze; } }; class Witch : public Mob { public: Witch(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { initMob(); } virtual MobType getType() const { return MobType::Witch; } }; class Slime : public Mob { public: Slime(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { initMob(); } virtual MobType getType() const { return MobType::Slime; } }; class Giant : public Mob { public: Giant(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { initMob(); } virtual MobType getType() const { return MobType::Giant; } }; namespace MobFactory { MobPtr createMob(MobID id, MobType type, std::uint8_t level, PlayerID sender); std::string getMobName(MobType type); } class MobListener { public: virtual void OnMobSpawn(Mob* mob) {} virtual void OnMobDie(Mob* mob) {} virtual void OnMobDamage(Mob* target, float damage, Tower* damager) {} virtual void OnMobTouchCastle(Mob* damager, TeamCastle* enemyCastle) {} virtual void OnMobCastleDamage(Mob* damager, TeamCastle* enemyCastle, float damage) {} }; typedef utils::ObjectNotifier MobNotifier; } // namespace game } // namespace td