feat: add kill reward + effect damages
This commit is contained in:
@@ -36,7 +36,6 @@ typedef std::uint32_t MobID;
|
|||||||
typedef std::uint8_t MobLevel;
|
typedef std::uint8_t MobLevel;
|
||||||
typedef std::vector<TowerType> TowerImmunities;
|
typedef std::vector<TowerType> TowerImmunities;
|
||||||
typedef std::vector<EffectType> EffectImmunities;
|
typedef std::vector<EffectType> EffectImmunities;
|
||||||
typedef std::pair<EffectType, float> EffectDuration;
|
|
||||||
|
|
||||||
class MobStats {
|
class MobStats {
|
||||||
private:
|
private:
|
||||||
@@ -62,6 +61,12 @@ public:
|
|||||||
std::uint16_t getMaxLife() const { return m_MaxLife; }
|
std::uint16_t getMaxLife() const { return m_MaxLife; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct EffectDuration{
|
||||||
|
EffectType type;
|
||||||
|
float duration; // in seconds
|
||||||
|
const Tower* tower; // the tower that gived the effect
|
||||||
|
};
|
||||||
|
|
||||||
const MobStats* getMobStats(MobType type, std::uint8_t level);
|
const MobStats* getMobStats(MobType type, std::uint8_t level);
|
||||||
const TowerImmunities& getMobTowerImmunities(MobType type, std::uint8_t level);
|
const TowerImmunities& getMobTowerImmunities(MobType type, std::uint8_t level);
|
||||||
const EffectImmunities& getMobEffectImmunities(MobType type, std::uint8_t level);
|
const EffectImmunities& getMobEffectImmunities(MobType type, std::uint8_t level);
|
||||||
@@ -75,10 +80,16 @@ private:
|
|||||||
MobLevel m_Level;
|
MobLevel m_Level;
|
||||||
Direction m_Direction;
|
Direction m_Direction;
|
||||||
std::vector<EffectDuration> m_Effects;
|
std::vector<EffectDuration> m_Effects;
|
||||||
|
const Tower* m_KillTower; // the tower that killed the mob
|
||||||
|
|
||||||
|
utils::Timer m_EffectFireTimer;
|
||||||
|
utils::Timer m_EffectPoisonTimer;
|
||||||
|
utils::Timer m_EffectHealTimer;
|
||||||
|
|
||||||
float m_X = 0, m_Y = 0;
|
float m_X = 0, m_Y = 0;
|
||||||
public:
|
public:
|
||||||
Mob(MobID id, MobLevel level, PlayerID sender) : m_Sender(sender), m_Level(level) {
|
Mob(MobID id, MobLevel level, PlayerID sender) : m_Sender(sender), m_Level(level),
|
||||||
|
m_EffectFireTimer(1000), m_EffectPoisonTimer(1000), m_EffectHealTimer(1000) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,13 +97,18 @@ public:
|
|||||||
|
|
||||||
virtual void tick(std::uint64_t delta);
|
virtual void tick(std::uint64_t delta);
|
||||||
|
|
||||||
|
virtual void OnDeath(World* world){}
|
||||||
|
|
||||||
const TowerImmunities& getTowerImmunities() const { return getMobTowerImmunities(getType(), m_Level); }
|
const TowerImmunities& getTowerImmunities() const { return getMobTowerImmunities(getType(), m_Level); }
|
||||||
const EffectImmunities& getEffectImmunities() const { return getMobEffectImmunities(getType(), m_Level); }
|
const EffectImmunities& getEffectImmunities() const { return getMobEffectImmunities(getType(), m_Level); }
|
||||||
PlayerID getSender() const { return m_Sender; }
|
PlayerID getSender() const { return m_Sender; }
|
||||||
MobLevel getLevel() const { return m_Level; }
|
MobLevel getLevel() const { return m_Level; }
|
||||||
const MobStats* getStats() const { return getMobStats(getType(), m_Level); }
|
const MobStats* getStats() const { return getMobStats(getType(), m_Level); }
|
||||||
float getHealth() const { return m_Health; }
|
float getHealth() const { return m_Health; }
|
||||||
|
bool isDead() const { return m_Health <= 0; }
|
||||||
bool isAlive() const { return m_Health > 0; }
|
bool isAlive() const { return m_Health > 0; }
|
||||||
|
const Tower* getKillTower() { return m_KillTower; }
|
||||||
|
void setKillTower(const Tower* killTower) { m_KillTower = killTower; }
|
||||||
|
|
||||||
void damage(float dmg) { m_Health -= dmg; }
|
void damage(float dmg) { m_Health -= dmg; }
|
||||||
void heal(float heal) { m_Health = std::min((float)getStats()->getMaxLife(), m_Health + heal); }
|
void heal(float heal) { m_Health = std::min((float)getStats()->getMaxLife(), m_Health + heal); }
|
||||||
@@ -106,7 +122,7 @@ public:
|
|||||||
bool isImmuneTo(TowerType type);
|
bool isImmuneTo(TowerType type);
|
||||||
|
|
||||||
bool isImmuneTo(EffectType type);
|
bool isImmuneTo(EffectType type);
|
||||||
void addEffect(EffectType type, float durationSec);
|
void addEffect(EffectType type, float durationSec, const Tower* tower);
|
||||||
bool hasEffect(EffectType type);
|
bool hasEffect(EffectType type);
|
||||||
|
|
||||||
|
|
||||||
@@ -116,6 +132,7 @@ protected:
|
|||||||
void initHealth() { m_Health = (float)getStats()->getMaxLife(); }
|
void initHealth() { m_Health = (float)getStats()->getMaxLife(); }
|
||||||
private:
|
private:
|
||||||
void updateEffects(std::uint64_t delta);
|
void updateEffects(std::uint64_t delta);
|
||||||
|
EffectDuration& getEffect(EffectType type);
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::shared_ptr<Mob> MobPtr;
|
typedef std::shared_ptr<Mob> MobPtr;
|
||||||
|
|||||||
@@ -12,14 +12,14 @@ class Player {
|
|||||||
private:
|
private:
|
||||||
game::TeamColor m_TeamColor;
|
game::TeamColor m_TeamColor;
|
||||||
|
|
||||||
std::uint32_t m_Gold = 0;
|
std::uint32_t m_Gold;
|
||||||
std::uint32_t m_EXP = 0;
|
std::uint32_t m_EXP;
|
||||||
std::string m_Name;
|
std::string m_Name;
|
||||||
std::uint8_t m_ID;
|
std::uint8_t m_ID;
|
||||||
|
|
||||||
std::uint8_t m_GoldPerSecond = 5;
|
std::uint8_t m_GoldPerSecond;
|
||||||
public:
|
public:
|
||||||
Player(std::uint8_t id = 0) : m_TeamColor(game::TeamColor::None), m_ID(id) {}
|
Player(std::uint8_t id = 0) : m_TeamColor(game::TeamColor::None), m_Gold(0), m_EXP(0), m_ID(id), m_GoldPerSecond(5) {}
|
||||||
|
|
||||||
const std::string& getName() const { return m_Name; }
|
const std::string& getName() const { return m_Name; }
|
||||||
void setName(const std::string& name) { m_Name = name; }
|
void setName(const std::string& name) { m_Name = name; }
|
||||||
@@ -32,9 +32,13 @@ public:
|
|||||||
|
|
||||||
std::uint32_t getGold() const { return m_Gold; }
|
std::uint32_t getGold() const { return m_Gold; }
|
||||||
void setGold(std::uint32_t gold) { m_Gold = gold; }
|
void setGold(std::uint32_t gold) { m_Gold = gold; }
|
||||||
|
void addGold(std::uint32_t gold) { m_Gold += gold; }
|
||||||
|
void removeGold(std::uint32_t gold) { m_Gold -= gold; }
|
||||||
|
|
||||||
std::uint32_t getEXP() const { return m_EXP; }
|
std::uint32_t getEXP() const { return m_EXP; }
|
||||||
void setEXP(std::uint32_t exp) { m_EXP = exp; }
|
void setEXP(std::uint32_t exp) { m_EXP = exp; }
|
||||||
|
void addEXP(std::uint32_t exp) { m_EXP += exp; }
|
||||||
|
void removeEXP(std::uint32_t exp) { m_EXP -= exp; }
|
||||||
|
|
||||||
std::uint8_t getID() const { return m_ID; }
|
std::uint8_t getID() const { return m_ID; }
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -115,6 +115,7 @@ public:
|
|||||||
std::uint16_t getY() const { return m_Y; }
|
std::uint16_t getY() const { return m_Y; }
|
||||||
const TowerLevel& getLevel() const { return m_Level; }
|
const TowerLevel& getLevel() const { return m_Level; }
|
||||||
const TowerStats* getStats() const { return getTowerStats(m_Type, m_Level); }
|
const TowerStats* getStats() const { return getTowerStats(m_Type, m_Level); }
|
||||||
|
PlayerID getBuilder() const { return m_Builder; }
|
||||||
|
|
||||||
bool isMobInRange(MobPtr mob);
|
bool isMobInRange(MobPtr mob);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -14,16 +14,19 @@ bool Mob::isImmuneTo(EffectType type) {
|
|||||||
return std::find(getEffectImmunities().begin(), getEffectImmunities().end(), type) != getEffectImmunities().end();
|
return std::find(getEffectImmunities().begin(), getEffectImmunities().end(), type) != getEffectImmunities().end();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mob::addEffect(EffectType effectType, float durationSec) {
|
EffectDuration& Mob::getEffect(EffectType effectType){
|
||||||
|
return *std::find_if(m_Effects.begin(), m_Effects.end(), [&effectType](EffectDuration effect) { return effect.type == effectType;});
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mob::addEffect(EffectType effectType, float durationSec, const Tower* tower) {
|
||||||
if (isImmuneTo(effectType))
|
if (isImmuneTo(effectType))
|
||||||
return;
|
return;
|
||||||
if (hasEffect(effectType)) {
|
if (hasEffect(effectType)) {
|
||||||
auto it = std::find_if(m_Effects.begin(), m_Effects.end(), [&effectType](EffectDuration effect) { return effect.first == effectType;});
|
EffectDuration& effect = getEffect(effectType);
|
||||||
EffectDuration& effect = *it;
|
if (effect.duration < durationSec)
|
||||||
if (effect.second < durationSec)
|
effect.duration = durationSec; // setting new duration if it's greater then the actual
|
||||||
effect.second = durationSec; // setting new duration if it's greater then the actual
|
|
||||||
} else {
|
} else {
|
||||||
m_Effects.push_back({ effectType, durationSec });
|
m_Effects.push_back({ effectType, durationSec, tower });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,14 +38,54 @@ void Mob::updateEffects(std::uint64_t delta) {
|
|||||||
float deltaSec = (float)delta / 1000.0f;
|
float deltaSec = (float)delta / 1000.0f;
|
||||||
for (std::size_t i = 0; i < m_Effects.size(); i++) {
|
for (std::size_t i = 0; i < m_Effects.size(); i++) {
|
||||||
EffectDuration& effect = m_Effects[i];
|
EffectDuration& effect = m_Effects[i];
|
||||||
effect.second -= deltaSec;
|
effect.duration -= deltaSec;
|
||||||
if (effect.second < 0) // effect has gone
|
if (effect.duration < 0){ // effect has gone
|
||||||
m_Effects.erase(m_Effects.begin() + i);
|
m_Effects.erase(m_Effects.begin() + i);
|
||||||
|
switch(effect.type){
|
||||||
|
case EffectType::Fire:{
|
||||||
|
m_EffectFireTimer.reset();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case EffectType::Poison:{
|
||||||
|
m_EffectPoisonTimer.reset();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case EffectType::Heal:{
|
||||||
|
m_EffectHealTimer.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(hasEffect(EffectType::Fire)){
|
||||||
|
if(m_EffectFireTimer.update(delta)){
|
||||||
|
damage(3);
|
||||||
|
if(isDead()){
|
||||||
|
setKillTower(getEffect(EffectType::Fire).tower);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(hasEffect(EffectType::Poison)){
|
||||||
|
if(m_EffectPoisonTimer.update(delta)){
|
||||||
|
damage(1);
|
||||||
|
if(isDead()){
|
||||||
|
setKillTower(getEffect(EffectType::Poison).tower);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(hasEffect(EffectType::Heal)){
|
||||||
|
if(m_EffectFireTimer.update(delta)){
|
||||||
|
heal(10);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Mob::hasEffect(EffectType type) {
|
bool Mob::hasEffect(EffectType type) {
|
||||||
return std::find_if(m_Effects.begin(), m_Effects.end(), [&type](EffectDuration effect) { return effect.first == type;}) != m_Effects.end();
|
return std::find_if(m_Effects.begin(), m_Effects.end(), [&type](EffectDuration effect) { return effect.type == type;}) != m_Effects.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -192,7 +192,7 @@ void IceTower::tick(std::uint64_t delta, World* world) {
|
|||||||
bool wasTowerActive = false;
|
bool wasTowerActive = false;
|
||||||
for (MobPtr mob : world->getMobList()) {
|
for (MobPtr mob : world->getMobList()) {
|
||||||
if (isMobInRange(mob)) {
|
if (isMobInRange(mob)) {
|
||||||
mob->addEffect(EffectType::Slowness, 1); // slowness for 1s every second
|
mob->addEffect(EffectType::Slowness, 1, this); // slowness for 1s every second
|
||||||
mob->damage(damage);
|
mob->damage(damage);
|
||||||
wasTowerActive = true;
|
wasTowerActive = true;
|
||||||
}
|
}
|
||||||
@@ -207,7 +207,7 @@ void MageTower::tick(std::uint64_t delta, World* world) {
|
|||||||
bool wasTowerActive = false;
|
bool wasTowerActive = false;
|
||||||
for (MobPtr mob : world->getMobList()) {
|
for (MobPtr mob : world->getMobList()) {
|
||||||
if (isMobInRange(mob)) {
|
if (isMobInRange(mob)) {
|
||||||
mob->addEffect(EffectType::Fire, getLevel().getLevel()); // slowness for 1s every second
|
mob->addEffect(EffectType::Fire, getLevel().getLevel() * 5, this);
|
||||||
wasTowerActive = true;
|
wasTowerActive = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -243,6 +243,15 @@ void World::cleanDeadMobs() {
|
|||||||
for (std::size_t i = 0; i < m_Mobs.size(); i++) {
|
for (std::size_t i = 0; i < m_Mobs.size(); i++) {
|
||||||
MobPtr mob = m_Mobs[i];
|
MobPtr mob = m_Mobs[i];
|
||||||
if (!mob->isAlive()) {
|
if (!mob->isAlive()) {
|
||||||
|
mob->OnDeath(this);
|
||||||
|
|
||||||
|
//reward players
|
||||||
|
Player& sender = m_Game->getPlayerById(mob->getSender());
|
||||||
|
sender.addEXP(mob->getStats()->getExpReward());
|
||||||
|
|
||||||
|
Player& killer = m_Game->getPlayerById(mob->getKillTower()->getBuilder());
|
||||||
|
killer.addGold(mob->getStats()->getMoneyCost());
|
||||||
|
|
||||||
m_Mobs.erase(m_Mobs.begin() + i);
|
m_Mobs.erase(m_Mobs.begin() + i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -271,6 +280,8 @@ void World::OnArrowShot(MobPtr target, Tower* shooter) {
|
|||||||
// aoe damage
|
// aoe damage
|
||||||
} else {
|
} else {
|
||||||
target->damage(shooter->getStats()->getDamage());
|
target->damage(shooter->getStats()->getDamage());
|
||||||
|
if(target->isDead())
|
||||||
|
target->setKillTower(shooter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user