248 lines
5.6 KiB
C++
248 lines
5.6 KiB
C++
#pragma once
|
|
|
|
#include <td/game/Towers.h>
|
|
|
|
#include <td/Maths.h>
|
|
#include <td/Types.h>
|
|
#include <td/game/Team.h>
|
|
|
|
#include <memory>
|
|
#include <vector>
|
|
|
|
namespace td {
|
|
using Vec2fp = Vec2<FpFloat>;
|
|
|
|
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<TowerType> TowerImmunities;
|
|
typedef std::vector<EffectType> 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 {
|
|
protected:
|
|
float m_Health;
|
|
|
|
private:
|
|
Vec2fp m_Position;
|
|
MobID m_ID;
|
|
PlayerID m_Sender;
|
|
MobLevel m_Level;
|
|
Direction m_Direction;
|
|
std::vector<EffectDuration> 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 bool OnDeath(World* world) {
|
|
return true;
|
|
}
|
|
|
|
Vec2fp& GetPosition() {
|
|
return m_Position;
|
|
}
|
|
|
|
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<float>(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<float>(static_cast<std::int32_t>(GetCenterX()));
|
|
// }
|
|
|
|
// // returns a float between 0 and 1 excluded
|
|
// float GetTileY() {
|
|
// return GetCenterY() - static_cast<float>(static_cast<std::int32_t>(GetCenterY()));
|
|
// }
|
|
|
|
Direction GetDirection() const {
|
|
return m_Direction;
|
|
}
|
|
void SetDirection(Direction dir) {
|
|
m_Direction = dir;
|
|
}
|
|
|
|
protected:
|
|
void InitMob() {
|
|
m_Health = static_cast<float>(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<Mob> MobPtr;
|
|
|
|
template <MobType MT>
|
|
class ConcreteMob : public Mob {
|
|
public:
|
|
ConcreteMob(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) {
|
|
InitMob();
|
|
}
|
|
|
|
virtual ~ConcreteMob() {}
|
|
|
|
virtual constexpr MobType GetType() const override {
|
|
return MT;
|
|
}
|
|
};
|
|
|
|
using Zombie = ConcreteMob<MobType::Zombie>;
|
|
using Spider = ConcreteMob<MobType::Spider>;
|
|
using Skeleton = ConcreteMob<MobType::Skeleton>;
|
|
using PigMan = ConcreteMob<MobType::Pigman>;
|
|
using Creeper = ConcreteMob<MobType::Creeper>;
|
|
using Silverfish = ConcreteMob<MobType::Silverfish>;
|
|
using Blaze = ConcreteMob<MobType::Blaze>;
|
|
using Witch = ConcreteMob<MobType::Witch>;
|
|
using Slime = ConcreteMob<MobType::Slime>;
|
|
using Giant = ConcreteMob<MobType::Giant>;
|
|
|
|
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<MobListener> MobNotifier;
|
|
|
|
} // namespace game
|
|
} // namespace td
|