#pragma once #include "td/Defines.h" #include "Towers.h" #include "Types.h" #include "Team.h" #include "td/misc/ObjectNotifier.h" #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; Vec2f 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, Vec2f 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 Vec2f& 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 float m_HitCooldown; 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_ID(id), m_Sender(sender), m_Level(level), m_HitCooldown(0), 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; m_HitCooldown = 0.1; } 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); bool HasTakenDamage() { return m_HitCooldown > 0; } 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