diff --git a/include/game/Mobs.h b/include/game/Mobs.h index ff79442..15e4034 100644 --- a/include/game/Mobs.h +++ b/include/game/Mobs.h @@ -34,6 +34,7 @@ typedef std::uint32_t MobID; typedef std::uint8_t MobLevel; typedef std::vector TowerImmunities; typedef std::vector EffectImmunities; +typedef std::pair EffectDuration; class MobStats { private: @@ -71,6 +72,7 @@ private: PlayerID m_Sender; MobLevel m_Level; Direction m_Direction; + std::vector m_Effects; float m_X = 0, m_Y = 0; public: @@ -80,7 +82,7 @@ public: virtual MobType getType() const = 0; - virtual void tick(std::uint64_t delta) {} + virtual void tick(std::uint64_t delta); const TowerImmunities& getTowerImmunities() const { return getMobTowerImmunities(getType(), m_Level); } const EffectImmunities& getEffectImmunities() const { return getMobEffectImmunities(getType(), m_Level); } @@ -99,10 +101,19 @@ public: float getY() const { return m_Y; } void setY(float y) { m_Y = y; } + bool isImmuneTo(TowerType type); + + bool isImmuneTo(EffectType type); + void addEffect(EffectType type, float durationSec); + bool hasEffect(EffectType type); + + Direction getDirection() const { return m_Direction; } void setDirection(Direction dir) { m_Direction = dir; } protected: void initHealth() { m_Health = (float)getStats()->getMaxLife(); } +private: + void updateEffects(std::uint64_t delta); }; typedef std::shared_ptr MobPtr; diff --git a/include/game/World.h b/include/game/World.h index 68cda93..f7933c9 100644 --- a/include/game/World.h +++ b/include/game/World.h @@ -187,6 +187,7 @@ public: virtual void OnArrowShot(MobPtr target, Tower* shooter); private: void moveMobs(std::uint64_t delta); + void tickMobs(std::uint64_t delta); void cleanDeadMobs(); }; diff --git a/src/game/Mobs.cpp b/src/game/Mobs.cpp index 21a182d..273b795 100644 --- a/src/game/Mobs.cpp +++ b/src/game/Mobs.cpp @@ -1,9 +1,53 @@ #include "game/Mobs.h" + #include +#include namespace td { namespace game { +bool Mob::isImmuneTo(TowerType type) { + return std::find(getTowerImmunities().begin(), getTowerImmunities().end(), type) != getTowerImmunities().end(); +} + +bool Mob::isImmuneTo(EffectType type) { + return std::find(getEffectImmunities().begin(), getEffectImmunities().end(), type) != getEffectImmunities().end(); +} + +void Mob::addEffect(EffectType effectType, float durationSec) { + if (isImmuneTo(effectType)) + return; + if (hasEffect(effectType)) { + auto it = std::find_if(m_Effects.begin(), m_Effects.end(), [&effectType](EffectDuration effect){ return effect.first == effectType;}); + EffectDuration& effect = *it; + if(effect.second < durationSec) + effect.second = durationSec; // setting new duration if it's greater then the actual + } else { + m_Effects.push_back({ effectType, durationSec }); + } +} + +void Mob::tick(std::uint64_t delta) { + updateEffects(delta); +} + +void Mob::updateEffects(std::uint64_t delta) { + float deltaSec = (float)delta / 1000.0f; + for (auto it = m_Effects.begin(); it != m_Effects.end(); it++) { + EffectDuration& effect = *it; + effect.second -= deltaSec; + if (effect.second < 0) // effect has gone + m_Effects.erase(it); + } +} + +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(); +} + + + + typedef std::pair MobKey; const std::map MobConstants = { diff --git a/src/game/Towers.cpp b/src/game/Towers.cpp index 0f8950b..e6e82eb 100644 --- a/src/game/Towers.cpp +++ b/src/game/Towers.cpp @@ -7,7 +7,7 @@ namespace td { namespace game { bool Tower::isMobInRange(MobPtr mob) { - if(!mob->isAlive()) + if (!mob->isAlive()) return false; return (m_X - mob->getX()) * (m_X - mob->getX()) + (m_Y - mob->getY()) * (m_Y - mob->getY()) < (getStats()->getRange() * getStats()->getRange()); } @@ -28,7 +28,7 @@ const std::map, TowerStats> TowerConstants = { {{TowerType::Ice, {1, TowerPath::Top}}, {1, 0, 10}}, {{TowerType::Ice, {2, TowerPath::Top}}, {1, 0, 12}}, {{TowerType::Ice, {3, TowerPath::Top}}, {1, 0, 13}}, - {{TowerType::Ice, {4, TowerPath::Top}}, {1, 0, 15}}, + {{TowerType::Ice, {4, TowerPath::Top}}, {1, 4, 15}}, //----------------------------------------------------------------- @@ -175,7 +175,7 @@ void ArcherTower::tick(std::uint64_t delta, World* world) { if (isMobInRange(mob)) { world->OnArrowShot(mob, this); arrowsShot++; - if(arrowsShot >= arrows) + if (arrowsShot >= arrows) break; } } @@ -183,7 +183,15 @@ void ArcherTower::tick(std::uint64_t delta, World* world) { } void IceTower::tick(std::uint64_t delta, World* world) { - + if (m_Timer.update(delta)) { + float damage = getStats()->getDamage(); + for (MobPtr mob : world->getMobList()) { + if (isMobInRange(mob)) { + mob->addEffect(EffectType::Slowness, 1); // slowness for 1s every second + mob->damage(damage); + } + } + } } void MageTower::tick(std::uint64_t delta, World* world) { diff --git a/src/game/World.cpp b/src/game/World.cpp index b05d332..c282061 100644 --- a/src/game/World.cpp +++ b/src/game/World.cpp @@ -321,6 +321,7 @@ bool World::saveMap(const std::string& fileName) const { void World::tick(std::uint64_t delta) { moveMobs(delta); + tickMobs(delta); for(TowerPtr tower : m_Towers){ tower->tick(delta, this); } @@ -341,6 +342,12 @@ TowerPtr World::placeTowerAt(TowerID id, TowerType type, std::int32_t x, std::in return tower; } +void World::tickMobs(std::uint64_t delta) { + for(MobPtr mob : m_Mobs) { + mob->tick(delta); + } +} + void World::moveMobs(std::uint64_t delta) { for (MobPtr mob : m_Mobs) { TilePtr tile = getTile(mob->getX(), mob->getY()); @@ -354,6 +361,9 @@ void World::moveMobs(std::uint64_t delta) { float walkAmount = mobWalkSpeed * ((float)delta / 1000.0f); + if(mob->hasEffect(EffectType::Slowness)) + walkAmount *= 0.70; + switch (mob->getDirection()) { case Direction::NegativeX: { mob->setX(mob->getX() - walkAmount);