251 lines
7.7 KiB
C++
251 lines
7.7 KiB
C++
#pragma once
|
|
|
|
#include "Towers.h"
|
|
#include "Types.h"
|
|
#include "Team.h"
|
|
|
|
#include "misc/ObjectNotifier.h"
|
|
|
|
#include <vector>
|
|
#include <memory>
|
|
|
|
#include <glm/glm.hpp>
|
|
|
|
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<TowerType> TowerImmunities;
|
|
typedef std::vector<EffectType> 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<EffectDuration> 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<float>(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<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())); } // 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<float>(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<Mob> 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<MobListener> MobNotifier;
|
|
|
|
} // namespace game
|
|
} // namespace td
|
|
|