#pragma once
#include
#include |
#include |
#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;
struct MobStats {
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;
};
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_Sender(sender), m_Level(level), m_HitCooldown(0), m_CastleTarget(nullptr) {}
virtual ~Mob() {}
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()->m_MaxLife), 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;
}
// returns a float between 0 and 1 excluded
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()));
}
Direction GetDirection() const {
return m_Direction;
}
void SetDirection(Direction dir) {
m_Direction = dir;
}
protected:
void InitMob() {
m_Health = static_cast(GetStats()->m_MaxLife);
SetSize(GetStats()->m_Size.x, GetStats()->m_Size.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;
template
class ConcreteMob : public Mob {
public:
ConcreteMob(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) {
InitMob();
}
virtual ~ConcreteMob() {}
virtual void Tick(std::uint64_t delta, World* world) {}
virtual constexpr MobType GetType() const {
return MT;
}
};
using Zombie = ConcreteMob;
using Spider = ConcreteMob;
using Skeleton = ConcreteMob;
using PigMan = ConcreteMob;
using Creeper = ConcreteMob;
using Silverfish = ConcreteMob;
using Blaze = ConcreteMob;
using Witch = ConcreteMob;
using Slime = ConcreteMob;
using Giant = ConcreteMob;
namespace MobFactory {
MobPtr CreateMob(MobID id, MobType type, std::uint8_t level, PlayerID sender);
std::string GetMobName(MobType type);
} // namespace MobFactory
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
|