Compare commits
8 Commits
alpha-0.0.
...
alpha-0.0.
| Author | SHA1 | Date | |
|---|---|---|---|
| 384b7ad51e | |||
| fd9b448fa4 | |||
| c4a2b08416 | |||
| a241d7691b | |||
| 0af4cd506c | |||
| 6b5c56b37d | |||
| 1474220a77 | |||
| a802b5cef5 |
@@ -46,8 +46,8 @@ public:
|
|||||||
const PlayerList& getPlayers() const { return m_Players; }
|
const PlayerList& getPlayers() const { return m_Players; }
|
||||||
PlayerList& getPlayers() { return m_Players; }
|
PlayerList& getPlayers() { return m_Players; }
|
||||||
|
|
||||||
const Player& getPlayerById(PlayerID id) const { return m_Players.find(id)->second; }
|
const Player* getPlayerById(PlayerID id) const;
|
||||||
Player& getPlayerById(PlayerID id) { return m_Players.find(id)->second; }
|
Player* getPlayerById(PlayerID id);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
#include "Types.h"
|
#include "Types.h"
|
||||||
#include "Team.h"
|
#include "Team.h"
|
||||||
|
|
||||||
|
#include "misc/ObjectNotifier.h"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
@@ -12,6 +14,8 @@
|
|||||||
namespace td {
|
namespace td {
|
||||||
namespace game {
|
namespace game {
|
||||||
|
|
||||||
|
struct WalkableTile;
|
||||||
|
|
||||||
enum class EffectType : std::uint8_t {
|
enum class EffectType : std::uint8_t {
|
||||||
Slowness = 0,
|
Slowness = 0,
|
||||||
Stun,
|
Stun,
|
||||||
@@ -69,7 +73,7 @@ public:
|
|||||||
struct EffectDuration {
|
struct EffectDuration {
|
||||||
EffectType type;
|
EffectType type;
|
||||||
float duration; // in seconds
|
float duration; // in seconds
|
||||||
const Tower* tower; // the tower that gived the effect
|
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);
|
||||||
@@ -86,22 +90,24 @@ private:
|
|||||||
Direction m_Direction;
|
Direction m_Direction;
|
||||||
std::vector<EffectDuration> m_Effects;
|
std::vector<EffectDuration> m_Effects;
|
||||||
const Tower* m_LastDamage; // the last tower that damaged the mob
|
const Tower* m_LastDamage; // the last tower that damaged the mob
|
||||||
bool m_HasReachedCastle; // if true, no need to walk anymore
|
|
||||||
|
|
||||||
utils::Timer m_EffectFireTimer;
|
utils::Timer m_EffectFireTimer;
|
||||||
utils::Timer m_EffectPoisonTimer;
|
utils::Timer m_EffectPoisonTimer;
|
||||||
utils::Timer m_EffectHealTimer;
|
utils::Timer m_EffectHealTimer;
|
||||||
|
|
||||||
|
TeamCastle* m_CastleTarget;
|
||||||
|
utils::CooldownTimer m_AttackTimer;
|
||||||
|
|
||||||
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_HasReachedCastle(false), m_EffectFireTimer(1000), m_EffectPoisonTimer(1000),
|
m_EffectFireTimer(1000), m_EffectPoisonTimer(1000),
|
||||||
m_EffectHealTimer(1000) {
|
m_EffectHealTimer(1000), m_CastleTarget(nullptr), m_AttackTimer(1000) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual MobType getType() const = 0;
|
virtual MobType getType() const = 0;
|
||||||
|
|
||||||
virtual void tick(std::uint64_t delta);
|
virtual void tick(std::uint64_t delta, World* world);
|
||||||
|
|
||||||
virtual bool OnDeath(World* world) { return true; }
|
virtual bool OnDeath(World* world) { return true; }
|
||||||
|
|
||||||
@@ -114,16 +120,16 @@ public:
|
|||||||
bool isDead() const { return m_Health <= 0; }
|
bool isDead() const { return m_Health <= 0; }
|
||||||
bool isAlive() const { return m_Health > 0; }
|
bool isAlive() const { return m_Health > 0; }
|
||||||
const Tower* getLastDamageTower() { return m_LastDamage; }
|
const Tower* getLastDamageTower() { return m_LastDamage; }
|
||||||
bool hasReachedEnemyCastle() { return m_HasReachedCastle; }
|
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 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 heal(float heal) { m_Health = std::min(static_cast<float>(getStats()->getMaxLife()), m_Health + heal); }
|
||||||
void setMobReachedCastle() { m_HasReachedCastle = true; } // used when mob is in front of the castle
|
void setMobReachedCastle(TeamCastle* castle) { m_CastleTarget = castle; } // used when mob is in front of the castle
|
||||||
|
|
||||||
bool isImmuneTo(TowerType type);
|
bool isImmuneTo(TowerType type);
|
||||||
|
|
||||||
bool isImmuneTo(EffectType type);
|
bool isImmuneTo(EffectType type);
|
||||||
void addEffect(EffectType type, float durationSec, const Tower* tower);
|
void addEffect(EffectType type, float durationSec, Tower* tower);
|
||||||
bool hasEffect(EffectType type);
|
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 getTileX() { return getCenterX() - static_cast<float>(static_cast<std::int32_t>(getCenterX())); } // returns a float between 0 and 1 excluded
|
||||||
@@ -137,7 +143,13 @@ protected:
|
|||||||
setSize(getStats()->getSize().x, getStats()->getSize().y);
|
setSize(getStats()->getSize().x, getStats()->getSize().y);
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
void updateEffects(std::uint64_t delta);
|
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);
|
EffectDuration& getEffect(EffectType type);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -218,6 +230,18 @@ MobPtr createMob(MobID id, MobType type, std::uint8_t level, PlayerID sender);
|
|||||||
std::string getMobName(MobType type);
|
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 game
|
||||||
} // namespace td
|
} // namespace td
|
||||||
|
|||||||
@@ -10,8 +10,6 @@
|
|||||||
#include "Mobs.h"
|
#include "Mobs.h"
|
||||||
#include "Team.h"
|
#include "Team.h"
|
||||||
|
|
||||||
#include "misc/ObjectNotifier.h"
|
|
||||||
|
|
||||||
namespace td {
|
namespace td {
|
||||||
namespace game {
|
namespace game {
|
||||||
typedef std::pair<std::int16_t, std::int16_t> ChunkCoord;
|
typedef std::pair<std::int16_t, std::int16_t> ChunkCoord;
|
||||||
@@ -127,15 +125,11 @@ public:
|
|||||||
|
|
||||||
virtual void OnArrowShot(MobPtr target, bool fire, Tower* shooter) {}
|
virtual void OnArrowShot(MobPtr target, bool fire, Tower* shooter) {}
|
||||||
virtual void OnExplosion(utils::shape::Circle explosion, float centerDamage, Tower* shooter) {}
|
virtual void OnExplosion(utils::shape::Circle explosion, float centerDamage, Tower* shooter) {}
|
||||||
|
|
||||||
virtual void OnMobDamage(MobPtr target, float damage, Tower* damager) {}
|
|
||||||
|
|
||||||
virtual void OnMobDead(MobPtr mob) {}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef utils::ObjectNotifier<WorldListener> WorldNotifier;
|
typedef utils::ObjectNotifier<WorldListener> WorldNotifier;
|
||||||
|
|
||||||
class World : public WorldNotifier, public WorldListener {
|
class World : public WorldListener, public MobListener {
|
||||||
protected:
|
protected:
|
||||||
TowerTileColorPalette m_TowerPlacePalette;
|
TowerTileColorPalette m_TowerPlacePalette;
|
||||||
Color m_WalkablePalette;
|
Color m_WalkablePalette;
|
||||||
@@ -152,6 +146,9 @@ protected:
|
|||||||
TowerList m_Towers;
|
TowerList m_Towers;
|
||||||
|
|
||||||
Game* m_Game;
|
Game* m_Game;
|
||||||
|
|
||||||
|
WorldNotifier m_WorldNotifier;
|
||||||
|
MobNotifier m_MobNotifier;
|
||||||
public:
|
public:
|
||||||
World(Game* game);
|
World(Game* game);
|
||||||
|
|
||||||
@@ -211,6 +208,11 @@ public:
|
|||||||
const TowerList& getTowers() const { return m_Towers; };
|
const TowerList& getTowers() const { return m_Towers; };
|
||||||
TowerPtr getTowerById(TowerID tower);
|
TowerPtr getTowerById(TowerID tower);
|
||||||
|
|
||||||
|
const Player* getPlayerById(PlayerID id) const;
|
||||||
|
|
||||||
|
WorldNotifier& getWorldNotifier() { return m_WorldNotifier; }
|
||||||
|
MobNotifier& getMobNotifier() { return m_MobNotifier; }
|
||||||
|
|
||||||
// WorldListener
|
// WorldListener
|
||||||
|
|
||||||
virtual void OnArcherTowerShot(MobPtr target, ArcherTower* shooter);
|
virtual void OnArcherTowerShot(MobPtr target, ArcherTower* shooter);
|
||||||
@@ -218,13 +220,13 @@ public:
|
|||||||
virtual void OnArrowShot(MobPtr target, bool fire, Tower* shooter);
|
virtual void OnArrowShot(MobPtr target, bool fire, Tower* shooter);
|
||||||
virtual void OnExplosion(utils::shape::Circle explosion, float centerDamage, Tower* shooter);
|
virtual void OnExplosion(utils::shape::Circle explosion, float centerDamage, Tower* shooter);
|
||||||
|
|
||||||
virtual void OnMobDamage(MobPtr target, float damage, Tower* source);
|
// MobListener
|
||||||
|
|
||||||
|
virtual void OnMobDamage(Mob* target, float damage, Tower* source);
|
||||||
|
virtual void OnMobDie(Mob* mob);
|
||||||
|
virtual void OnMobCastleDamage(Mob* damager, TeamCastle* enemyCastle, float damage);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void moveMobs(std::uint64_t delta);
|
|
||||||
void moveMob(MobPtr mob, std::uint64_t delta);
|
|
||||||
void moveBackMob(MobPtr mob, const TeamCastle& castle);
|
|
||||||
void changeMobDirection(MobPtr mob, WalkableTilePtr tile);
|
|
||||||
bool isMobTouchingCastle(MobPtr mob, const TeamCastle& castle) const;
|
|
||||||
void tickMobs(std::uint64_t delta);
|
void tickMobs(std::uint64_t delta);
|
||||||
void cleanDeadMobs();
|
void cleanDeadMobs();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ public:
|
|||||||
std::uint64_t getInterval() const { return m_Interval; }
|
std::uint64_t getInterval() const { return m_Interval; }
|
||||||
};
|
};
|
||||||
|
|
||||||
// utililty class to call function at regular period of time with a cooldown (used for towers)
|
// utililty class to call function at regular period of time with a cooldown (used for towers and mobs )
|
||||||
class CooldownTimer {
|
class CooldownTimer {
|
||||||
private:
|
private:
|
||||||
std::uint64_t m_Cooldown; // in millis
|
std::uint64_t m_Cooldown; // in millis
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
|
|
||||||
#define TD_VERSION "alpha-0.0.4"
|
#define TD_VERSION "alpha-0.0.5"
|
||||||
|
|
||||||
namespace td {
|
namespace td {
|
||||||
namespace utils {
|
namespace utils {
|
||||||
|
|||||||
@@ -20,8 +20,10 @@ extern "C"
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
int main(int argc, const char* args[]) {
|
int main(int argc, const char* args[]) {
|
||||||
|
#if !defined(NDEBUG)
|
||||||
// setup signal handling
|
// setup signal handling
|
||||||
backward::SignalHandling sh;
|
backward::SignalHandling sh;
|
||||||
|
#endif
|
||||||
|
|
||||||
// remove the outdated binary
|
// remove the outdated binary
|
||||||
td::utils::Updater::removeOldFile();
|
td::utils::Updater::removeOldFile();
|
||||||
|
|||||||
@@ -17,5 +17,21 @@ void Game::tick(std::uint64_t delta) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Player* Game::getPlayerById(PlayerID id) {
|
||||||
|
auto it = m_Players.find(id);
|
||||||
|
|
||||||
|
if (it == m_Players.end()) return nullptr;
|
||||||
|
|
||||||
|
return &it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Player* Game::getPlayerById(PlayerID id) const {
|
||||||
|
auto it = m_Players.find(id);
|
||||||
|
|
||||||
|
if (it == m_Players.end()) return nullptr;
|
||||||
|
|
||||||
|
return &it->second;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace game
|
} // namespace game
|
||||||
} // namespace td
|
} // namespace td
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
#include "game/Mobs.h"
|
#include "game/Mobs.h"
|
||||||
|
#include "game/Player.h"
|
||||||
|
#include "game/World.h"
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
@@ -18,7 +20,7 @@ EffectDuration& Mob::getEffect(EffectType effectType) {
|
|||||||
return *std::find_if(m_Effects.begin(), m_Effects.end(), [&effectType](EffectDuration effect) { return effect.type == 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) {
|
void Mob::addEffect(EffectType effectType, float durationSec, Tower* tower) {
|
||||||
if (isImmuneTo(effectType))
|
if (isImmuneTo(effectType))
|
||||||
return;
|
return;
|
||||||
if (hasEffect(effectType)) {
|
if (hasEffect(effectType)) {
|
||||||
@@ -30,11 +32,176 @@ void Mob::addEffect(EffectType effectType, float durationSec, const Tower* tower
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mob::tick(std::uint64_t delta) {
|
void Mob::attackCastle(std::uint64_t delta, World* world) {
|
||||||
updateEffects(delta);
|
if(!hasReachedEnemyCastle()) return;
|
||||||
|
|
||||||
|
if (m_AttackTimer.update(delta)) {
|
||||||
|
world->getMobNotifier().notifyListeners(&MobListener::OnMobCastleDamage, this, m_CastleTarget, getStats()->getDamage());
|
||||||
|
m_AttackTimer.applyCooldown();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mob::updateEffects(std::uint64_t delta) {
|
void Mob::walk(std::uint64_t delta, World* world) {
|
||||||
|
float mobWalkSpeed = getStats()->getMovementSpeed();
|
||||||
|
|
||||||
|
float walkAmount = mobWalkSpeed * ((float)delta / 1000.0f);
|
||||||
|
|
||||||
|
if (hasEffect(EffectType::Slowness))
|
||||||
|
walkAmount *= 0.70; // walk 30% slower
|
||||||
|
|
||||||
|
switch (getDirection()) {
|
||||||
|
case Direction::NegativeX: {
|
||||||
|
setCenterX(getCenterX() - walkAmount);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Direction::PositiveX: {
|
||||||
|
setCenterX(getCenterX() + walkAmount);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Direction::NegativeY: {
|
||||||
|
setCenterY(getCenterY() - walkAmount);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Direction::PositiveY: {
|
||||||
|
setCenterY(getCenterY() + walkAmount);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mob::move(std::uint64_t delta, World* world) {
|
||||||
|
TilePtr tile = world->getTile(getCenter().getX(), getCenter().getY());
|
||||||
|
|
||||||
|
if (tile != nullptr && tile->getType() == TileType::Walk) {
|
||||||
|
WalkableTilePtr walkTile = std::static_pointer_cast<WalkableTile>(tile);
|
||||||
|
changeDirection(*walkTile, world);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasReachedEnemyCastle()) return;
|
||||||
|
|
||||||
|
walk(delta, world);
|
||||||
|
|
||||||
|
TeamColor mobTeam = world->getPlayerById(getSender())->getTeamColor();
|
||||||
|
|
||||||
|
TeamCastle* enemyCastle = nullptr;
|
||||||
|
|
||||||
|
if (mobTeam == TeamColor::Red) {
|
||||||
|
enemyCastle = &world->getBlueTeam().getCastle();
|
||||||
|
} else if (mobTeam == TeamColor::Blue) {
|
||||||
|
enemyCastle = &world->getRedTeam().getCastle();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isTouchingCastle(*enemyCastle)) {
|
||||||
|
moveBack(*enemyCastle, world);
|
||||||
|
setMobReachedCastle(enemyCastle);
|
||||||
|
|
||||||
|
world->getMobNotifier().notifyListeners(&MobListener::OnMobTouchCastle, this, enemyCastle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mob::moveBack(const TeamCastle& enemyCastle, World* world) {
|
||||||
|
switch (getDirection()) {
|
||||||
|
case Direction::NegativeX: {
|
||||||
|
setCenterX(enemyCastle.getBottomRight().getX() + getWidth() / 2.0f);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Direction::PositiveX: {
|
||||||
|
setCenterX(enemyCastle.getTopLeft().getX() - getWidth() / 2.0f);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Direction::NegativeY: {
|
||||||
|
setCenterY(enemyCastle.getBottomRight().getY() + getHeight() / 2.0f);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Direction::PositiveY: {
|
||||||
|
setCenterY(enemyCastle.getTopLeft().getY() - getHeight() / 2.0f);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mob::changeDirection(const WalkableTile& tile, World* world) {
|
||||||
|
if (getDirection() == tile.direction) return;
|
||||||
|
|
||||||
|
float tileX = static_cast<float>(static_cast<std::int32_t>(getCenterX()));
|
||||||
|
float tileY = static_cast<float>(static_cast<std::int32_t>(getCenterY()));
|
||||||
|
|
||||||
|
switch (getDirection()) {
|
||||||
|
|
||||||
|
case Direction::PositiveY: {
|
||||||
|
if (tile.direction == Direction::NegativeX) {
|
||||||
|
if (getTileY() > getTileX()) {
|
||||||
|
setCenterY(tileY + getTileX());
|
||||||
|
setDirection(tile.direction);
|
||||||
|
}
|
||||||
|
} else { // tile->direction = Direction::PositiveX
|
||||||
|
if (getTileY() > 1 - getTileX()) {
|
||||||
|
setCenterY(tileY + (1 - getTileX()));
|
||||||
|
setDirection(tile.direction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Direction::NegativeY: {
|
||||||
|
if (tile.direction == Direction::PositiveX) {
|
||||||
|
if (getTileY() < getTileX()) {
|
||||||
|
setCenterY(tileY + getTileX());
|
||||||
|
setDirection(tile.direction);
|
||||||
|
}
|
||||||
|
} else { // tile.direction = Direction::NegativeX
|
||||||
|
if (getTileY() < 1 - getTileX()) {
|
||||||
|
setCenterY(tileY + (1 - getTileX()));
|
||||||
|
setDirection(tile.direction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Direction::PositiveX: {
|
||||||
|
if (tile.direction == Direction::NegativeY) {
|
||||||
|
if (getTileX() > getTileY()) {
|
||||||
|
setCenterX(tileX + getTileY());
|
||||||
|
setDirection(tile.direction);
|
||||||
|
}
|
||||||
|
} else { // tile.direction = Direction::PositiveY
|
||||||
|
if (getTileX() > 1 - getTileY()) {
|
||||||
|
setCenterX(tileX + (1 - getTileY()));
|
||||||
|
setDirection(tile.direction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Direction::NegativeX: {
|
||||||
|
if (tile.direction == Direction::PositiveY) {
|
||||||
|
if (getTileX() < getTileY()) {
|
||||||
|
setCenterX(tileX + getTileY());
|
||||||
|
setDirection(tile.direction);
|
||||||
|
}
|
||||||
|
} else { // tile.direction = Direction::NegativeY
|
||||||
|
if (getTileX() < 1 - getTileY()) {
|
||||||
|
setCenterX(tileX + (1 - getTileY()));
|
||||||
|
setDirection(tile.direction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Mob::isTouchingCastle(const TeamCastle& enemyCastle) const {
|
||||||
|
return enemyCastle.collidesWith(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mob::tick(std::uint64_t delta, World* world) {
|
||||||
|
updateEffects(delta, world);
|
||||||
|
move(delta, world);
|
||||||
|
attackCastle(delta, world);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mob::updateEffects(std::uint64_t delta, World* world) {
|
||||||
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];
|
||||||
@@ -63,12 +230,12 @@ void Mob::updateEffects(std::uint64_t delta) {
|
|||||||
}
|
}
|
||||||
if (hasEffect(EffectType::Fire)) {
|
if (hasEffect(EffectType::Fire)) {
|
||||||
if (m_EffectFireTimer.update(delta)) {
|
if (m_EffectFireTimer.update(delta)) {
|
||||||
damage(3, getEffect(EffectType::Fire).tower);
|
world->getMobNotifier().notifyListeners(&MobListener::OnMobDamage, this, 3.0f, getEffect(EffectType::Fire).tower);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (hasEffect(EffectType::Poison)) {
|
if (hasEffect(EffectType::Poison)) {
|
||||||
if (m_EffectPoisonTimer.update(delta)) {
|
if (m_EffectPoisonTimer.update(delta)) {
|
||||||
damage(1, getEffect(EffectType::Poison).tower);
|
world->getMobNotifier().notifyListeners(&MobListener::OnMobDamage, this, 1.0f, getEffect(EffectType::Poison).tower);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (hasEffect(EffectType::Heal)) {
|
if (hasEffect(EffectType::Heal)) {
|
||||||
|
|||||||
@@ -213,7 +213,7 @@ void ArcherTower::tick(std::uint64_t delta, World* world) {
|
|||||||
std::uint8_t arrows = explosiveArrows ? 2 : getLevel().getLevel();
|
std::uint8_t arrows = explosiveArrows ? 2 : getLevel().getLevel();
|
||||||
for (MobPtr mob : world->getMobList()) {
|
for (MobPtr mob : world->getMobList()) {
|
||||||
if (isMobInRange(mob)) {
|
if (isMobInRange(mob)) {
|
||||||
world->notifyListeners(&WorldListener::OnArcherTowerShot, mob, this);
|
world->getWorldNotifier().notifyListeners(&WorldListener::OnArcherTowerShot, mob, this);
|
||||||
m_Timer.applyCooldown();
|
m_Timer.applyCooldown();
|
||||||
arrowsShot++;
|
arrowsShot++;
|
||||||
if (arrowsShot >= arrows)
|
if (arrowsShot >= arrows)
|
||||||
@@ -229,8 +229,8 @@ void IceTower::tick(std::uint64_t delta, World* world) {
|
|||||||
for (MobPtr mob : world->getMobList()) {
|
for (MobPtr mob : world->getMobList()) {
|
||||||
if (isMobInRange(mob)) {
|
if (isMobInRange(mob)) {
|
||||||
mob->addEffect(EffectType::Slowness, 1, this); // slowness for 1s every second
|
mob->addEffect(EffectType::Slowness, 1, this); // slowness for 1s every second
|
||||||
if(damage > 0)
|
if (damage > 0)
|
||||||
world->notifyListeners(&WorldListener::OnMobDamage, mob, damage, this);
|
world->getMobNotifier().notifyListeners(&MobListener::OnMobDamage, mob.get(), damage, this);
|
||||||
m_Timer.applyCooldown();
|
m_Timer.applyCooldown();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -253,7 +253,7 @@ void PoisonTower::tick(std::uint64_t delta, World* world) {
|
|||||||
for (MobPtr mob : world->getMobList()) {
|
for (MobPtr mob : world->getMobList()) {
|
||||||
if (isMobInRange(mob)) {
|
if (isMobInRange(mob)) {
|
||||||
if (getLevel().getPath() == TowerPath::Bottom) {
|
if (getLevel().getPath() == TowerPath::Bottom) {
|
||||||
world->notifyListeners(&WorldListener::OnMobDamage, mob, getStats()->getDamage(), this);
|
world->getMobNotifier().notifyListeners(&MobListener::OnMobDamage, mob.get(), getStats()->getDamage(), this);
|
||||||
} else {
|
} else {
|
||||||
float durationSec;
|
float durationSec;
|
||||||
switch (getLevel().getLevel()) {
|
switch (getLevel().getLevel()) {
|
||||||
|
|||||||
@@ -13,7 +13,8 @@ namespace td {
|
|||||||
namespace game {
|
namespace game {
|
||||||
|
|
||||||
World::World(Game* game) : m_Game(game) {
|
World::World(Game* game) : m_Game(game) {
|
||||||
bindListener(this);
|
getWorldNotifier().bindListener(this);
|
||||||
|
getMobNotifier().bindListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
TilePtr World::getTile(std::int32_t x, std::int32_t y) const {
|
TilePtr World::getTile(std::int32_t x, std::int32_t y) const {
|
||||||
@@ -101,7 +102,6 @@ bool World::saveMap(const std::string& fileName) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void World::tick(std::uint64_t delta) {
|
void World::tick(std::uint64_t delta) {
|
||||||
moveMobs(delta);
|
|
||||||
tickMobs(delta);
|
tickMobs(delta);
|
||||||
for (TowerPtr tower : m_Towers) {
|
for (TowerPtr tower : m_Towers) {
|
||||||
tower->tick(delta, this);
|
tower->tick(delta, this);
|
||||||
@@ -114,6 +114,7 @@ void World::spawnMobAt(MobID id, MobType type, std::uint8_t level, PlayerID send
|
|||||||
mob->setCenter({ x, y });
|
mob->setCenter({ x, y });
|
||||||
mob->setDirection(dir);
|
mob->setDirection(dir);
|
||||||
m_Mobs.push_back(mob);
|
m_Mobs.push_back(mob);
|
||||||
|
getMobNotifier().notifyListeners(&MobListener::OnMobSpawn, mob.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
TowerPtr World::placeTowerAt(TowerID id, TowerType type, std::int32_t x, std::int32_t y, PlayerID builder) {
|
TowerPtr World::placeTowerAt(TowerID id, TowerType type, std::int32_t x, std::int32_t y, PlayerID builder) {
|
||||||
@@ -135,161 +136,7 @@ TowerPtr World::removeTower(TowerID towerId) {
|
|||||||
|
|
||||||
void World::tickMobs(std::uint64_t delta) {
|
void World::tickMobs(std::uint64_t delta) {
|
||||||
for (MobPtr mob : m_Mobs) {
|
for (MobPtr mob : m_Mobs) {
|
||||||
mob->tick(delta);
|
mob->tick(delta, this);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void World::changeMobDirection(MobPtr mob, WalkableTilePtr tile) {
|
|
||||||
if (mob->getDirection() == tile->direction) return;
|
|
||||||
|
|
||||||
float tileX = static_cast<float>(static_cast<std::int32_t>(mob->getCenterX()));
|
|
||||||
float tileY = static_cast<float>(static_cast<std::int32_t>(mob->getCenterY()));
|
|
||||||
|
|
||||||
switch (mob->getDirection()) {
|
|
||||||
|
|
||||||
case Direction::PositiveY: {
|
|
||||||
if (tile->direction == Direction::NegativeX) {
|
|
||||||
if (mob->getTileY() > mob->getTileX()) {
|
|
||||||
mob->setCenterY(tileY + mob->getTileX());
|
|
||||||
mob->setDirection(tile->direction);
|
|
||||||
}
|
|
||||||
} else { // tile->direction = Direction::PositiveX
|
|
||||||
if (mob->getTileY() > 1 - mob->getTileX()) {
|
|
||||||
mob->setCenterY(tileY + (1 - mob->getTileX()));
|
|
||||||
mob->setDirection(tile->direction);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
case Direction::NegativeY: {
|
|
||||||
if (tile->direction == Direction::PositiveX) {
|
|
||||||
if (mob->getTileY() < mob->getTileX()) {
|
|
||||||
mob->setCenterY(tileY + mob->getTileX());
|
|
||||||
mob->setDirection(tile->direction);
|
|
||||||
}
|
|
||||||
} else { // tile->direction = Direction::NegativeX
|
|
||||||
if (mob->getTileY() < 1 - mob->getTileX()) {
|
|
||||||
mob->setCenterY(tileY + (1 - mob->getTileX()));
|
|
||||||
mob->setDirection(tile->direction);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
case Direction::PositiveX: {
|
|
||||||
if (tile->direction == Direction::NegativeY) {
|
|
||||||
if (mob->getTileX() > mob->getTileY()) {
|
|
||||||
mob->setCenterX(tileX + mob->getTileY());
|
|
||||||
mob->setDirection(tile->direction);
|
|
||||||
}
|
|
||||||
} else { // tile->direction = Direction::PositiveY
|
|
||||||
if (mob->getTileX() > 1 - mob->getTileY()) {
|
|
||||||
mob->setCenterX(tileX + (1 - mob->getTileY()));
|
|
||||||
mob->setDirection(tile->direction);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
case Direction::NegativeX: {
|
|
||||||
if (tile->direction == Direction::PositiveY) {
|
|
||||||
if (mob->getTileX() < mob->getTileY()) {
|
|
||||||
mob->setCenterX(tileX + mob->getTileY());
|
|
||||||
mob->setDirection(tile->direction);
|
|
||||||
}
|
|
||||||
} else { // tile->direction = Direction::NegativeY
|
|
||||||
if (mob->getTileX() < 1 - mob->getTileY()) {
|
|
||||||
mob->setCenterX(tileX + (1 - mob->getTileY()));
|
|
||||||
mob->setDirection(tile->direction);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void World::moveMobs(std::uint64_t delta) {
|
|
||||||
for (MobPtr mob : m_Mobs) {
|
|
||||||
TilePtr tile = getTile(mob->getCenter().getX(), mob->getCenter().getY());
|
|
||||||
|
|
||||||
if (tile != nullptr && tile->getType() == TileType::Walk) {
|
|
||||||
WalkableTilePtr walkTile = std::static_pointer_cast<WalkableTile>(tile);
|
|
||||||
changeMobDirection(mob, walkTile);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mob->hasReachedEnemyCastle()) continue;
|
|
||||||
|
|
||||||
moveMob(mob, delta);
|
|
||||||
|
|
||||||
TeamColor mobTeam = m_Game->getPlayerById(mob->getSender()).getTeamColor();
|
|
||||||
|
|
||||||
const TeamCastle* enemyCastle = nullptr;
|
|
||||||
|
|
||||||
if (mobTeam == TeamColor::Red) {
|
|
||||||
enemyCastle = &getBlueTeam().getCastle();
|
|
||||||
} else if (mobTeam == TeamColor::Blue) {
|
|
||||||
enemyCastle = &getRedTeam().getCastle();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isMobTouchingCastle(mob, *enemyCastle)) {
|
|
||||||
moveBackMob(mob, *enemyCastle);
|
|
||||||
mob->setMobReachedCastle();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void World::moveMob(MobPtr mob, std::uint64_t delta) {
|
|
||||||
float mobWalkSpeed = mob->getStats()->getMovementSpeed();
|
|
||||||
|
|
||||||
float walkAmount = mobWalkSpeed * ((float)delta / 1000.0f);
|
|
||||||
|
|
||||||
if (mob->hasEffect(EffectType::Slowness))
|
|
||||||
walkAmount *= 0.70; // walk 30% slower
|
|
||||||
|
|
||||||
switch (mob->getDirection()) {
|
|
||||||
case Direction::NegativeX: {
|
|
||||||
mob->setCenterX(mob->getCenterX() - walkAmount);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case Direction::PositiveX: {
|
|
||||||
mob->setCenterX(mob->getCenterX() + walkAmount);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case Direction::NegativeY: {
|
|
||||||
mob->setCenterY(mob->getCenterY() - walkAmount);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case Direction::PositiveY: {
|
|
||||||
mob->setCenterY(mob->getCenterY() + walkAmount);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool World::isMobTouchingCastle(MobPtr mob, const TeamCastle& enemyCastle) const {
|
|
||||||
return enemyCastle.collidesWith(*mob);
|
|
||||||
}
|
|
||||||
|
|
||||||
void World::moveBackMob(MobPtr mob, const TeamCastle& enemyCastle) {
|
|
||||||
switch (mob->getDirection()) {
|
|
||||||
case Direction::NegativeX: {
|
|
||||||
mob->setCenterX(enemyCastle.getBottomRight().getX() + mob->getWidth() / 2.0f);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case Direction::PositiveX: {
|
|
||||||
mob->setCenterX(enemyCastle.getTopLeft().getX() - mob->getWidth() / 2.0f);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case Direction::NegativeY: {
|
|
||||||
mob->setCenterY(enemyCastle.getBottomRight().getY() + mob->getHeight() / 2.0f);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case Direction::PositiveY: {
|
|
||||||
mob->setCenterY(enemyCastle.getTopLeft().getY() - mob->getHeight() / 2.0f);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -368,22 +215,25 @@ bool World::CanPlaceBigTower(const glm::vec2& worldPos, PlayerID playerID) const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void World::OnMobDie(Mob* mob) {
|
||||||
|
if (mob->OnDeath(this)) { // check if the mob is actually dead (slimes ...)
|
||||||
|
//reward players
|
||||||
|
Player* sender = m_Game->getPlayerById(mob->getSender());
|
||||||
|
sender->addExp(mob->getStats()->getExpReward());
|
||||||
|
|
||||||
|
Player* killer = m_Game->getPlayerById(mob->getLastDamageTower()->getBuilder());
|
||||||
|
killer->addGold(mob->getStats()->getMoneyCost());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void World::cleanDeadMobs() {
|
void World::cleanDeadMobs() {
|
||||||
|
// safely remove mobs when unused
|
||||||
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->isDead()) {
|
if (mob->isDead()) {
|
||||||
if (mob->OnDeath(this)) {
|
|
||||||
//reward players
|
|
||||||
Player& sender = m_Game->getPlayerById(mob->getSender());
|
|
||||||
sender.addExp(mob->getStats()->getExpReward());
|
|
||||||
|
|
||||||
Player& killer = m_Game->getPlayerById(mob->getLastDamageTower()->getBuilder());
|
|
||||||
killer.addGold(mob->getStats()->getMoneyCost());
|
|
||||||
|
|
||||||
m_Mobs.erase(m_Mobs.begin() + i);
|
m_Mobs.erase(m_Mobs.begin() + i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TowerPtr World::getTower(const glm::vec2& position) const {
|
TowerPtr World::getTower(const glm::vec2& position) const {
|
||||||
@@ -413,14 +263,14 @@ void World::OnArcherTowerShot(MobPtr target, ArcherTower* shooter) {
|
|||||||
bool fireArrows = shooter->getLevel().getPath() == TowerPath::Bottom;
|
bool fireArrows = shooter->getLevel().getPath() == TowerPath::Bottom;
|
||||||
bool explosiveArrows = shooter->getLevel().getLevel() == 4 && fireArrows;
|
bool explosiveArrows = shooter->getLevel().getLevel() == 4 && fireArrows;
|
||||||
|
|
||||||
notifyListeners(&WorldListener::OnArrowShot, target, fireArrows, shooter);
|
getWorldNotifier().notifyListeners(&WorldListener::OnArrowShot, target, fireArrows, shooter);
|
||||||
if (explosiveArrows) {
|
if (explosiveArrows) {
|
||||||
notifyListeners(&WorldListener::OnExplosion, utils::shape::Circle{ target->getCenterX(), target->getCenterY(), ArcherTower::ExplosionRadius }, shooter->getStats()->getDamage(), shooter);
|
getWorldNotifier().notifyListeners(&WorldListener::OnExplosion, utils::shape::Circle{ target->getCenterX(), target->getCenterY(), ArcherTower::ExplosionRadius }, shooter->getStats()->getDamage(), shooter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::OnArrowShot(MobPtr target, bool fireArrow, Tower* shooter) {
|
void World::OnArrowShot(MobPtr target, bool fireArrow, Tower* shooter) {
|
||||||
notifyListeners(&WorldListener::OnMobDamage, target, shooter->getStats()->getDamage(), shooter);
|
getMobNotifier().notifyListeners(&MobListener::OnMobDamage, target.get(), shooter->getStats()->getDamage(), shooter);
|
||||||
if (fireArrow) {
|
if (fireArrow) {
|
||||||
target->addEffect(EffectType::Fire, ArcherTower::FireDurationSec, shooter);
|
target->addEffect(EffectType::Fire, ArcherTower::FireDurationSec, shooter);
|
||||||
}
|
}
|
||||||
@@ -431,15 +281,22 @@ void World::OnExplosion(utils::shape::Circle explosion, float centerDamage, Towe
|
|||||||
if (mob->isAlive() && mob->collidesWith(explosion)) {
|
if (mob->isAlive() && mob->collidesWith(explosion)) {
|
||||||
// linear distance damage reduction
|
// linear distance damage reduction
|
||||||
float explosionDamage = mob->distance(explosion) / explosion.getRadius() * centerDamage;
|
float explosionDamage = mob->distance(explosion) / explosion.getRadius() * centerDamage;
|
||||||
notifyListeners(&WorldListener::OnMobDamage, mob, explosionDamage, shooter);
|
getMobNotifier().notifyListeners(&MobListener::OnMobDamage, mob.get(), explosionDamage, shooter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::OnMobDamage(MobPtr target, float damage, Tower* source) {
|
void World::OnMobCastleDamage(Mob* damager, TeamCastle* enemyCastle, float damage) {
|
||||||
|
enemyCastle->damage(damage);
|
||||||
|
if (enemyCastle->getLife() <= 0) {
|
||||||
|
// TODO: a team has won
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::OnMobDamage(Mob* target, float damage, Tower* source) {
|
||||||
target->damage(damage, source);
|
target->damage(damage, source);
|
||||||
if (target->isDead()) {
|
if (target->isDead()) {
|
||||||
notifyListeners(&WorldListener::OnMobDead, target);
|
getMobNotifier().notifyListeners(&MobListener::OnMobDie, target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -467,5 +324,9 @@ const Team& World::getTeam(TeamColor team) const {
|
|||||||
return m_Game->getTeam(team);
|
return m_Game->getTeam(team);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Player* World::getPlayerById(PlayerID id) const {
|
||||||
|
return m_Game->getPlayerById(id);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace game
|
} // namespace game
|
||||||
} // namespace td
|
} // namespace td
|
||||||
|
|||||||
@@ -37,14 +37,14 @@ void WorldClient::HandlePacket(const protocol::UpgradeTowerPacket* packet) {
|
|||||||
void WorldClient::HandlePacket(const protocol::WorldAddTowerPacket* packet) {
|
void WorldClient::HandlePacket(const protocol::WorldAddTowerPacket* packet) {
|
||||||
game::TowerPtr newTower = placeTowerAt(packet->getTowerID(), packet->getTowerType(), packet->getTowerX(), packet->getTowerY(), packet->getBuilder());
|
game::TowerPtr newTower = placeTowerAt(packet->getTowerID(), packet->getTowerType(), packet->getTowerX(), packet->getTowerY(), packet->getBuilder());
|
||||||
|
|
||||||
notifyListeners(&WorldListener::OnTowerAdd, newTower);
|
getWorldNotifier().notifyListeners(&WorldListener::OnTowerAdd, newTower);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldClient::HandlePacket(const protocol::RemoveTowerPacket* packet) {
|
void WorldClient::HandlePacket(const protocol::RemoveTowerPacket* packet) {
|
||||||
game::TowerPtr tower = removeTower(packet->getTowerID());
|
game::TowerPtr tower = removeTower(packet->getTowerID());
|
||||||
|
|
||||||
if (tower != nullptr) {
|
if (tower != nullptr) {
|
||||||
notifyListeners(&WorldListener::OnTowerRemove, tower);
|
getWorldNotifier().notifyListeners(&WorldListener::OnTowerRemove, tower);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -160,7 +160,7 @@ void ServerConnexion::HandlePacket(const protocol::PlaceTowerPacket* packet) {
|
|||||||
|
|
||||||
game::TowerPtr tower = world->placeTowerAt(towerType, packet->getTowerX(), packet->getTowerY(), m_ID);
|
game::TowerPtr tower = world->placeTowerAt(towerType, packet->getTowerX(), packet->getTowerY(), m_ID);
|
||||||
|
|
||||||
world->notifyListeners(&game::WorldListener::OnTowerAdd, tower);
|
world->getWorldNotifier().notifyListeners(&game::WorldListener::OnTowerAdd, tower);
|
||||||
|
|
||||||
protocol::WorldAddTowerPacket addTowerPacket(tower->getID(), packet->getTowerX(), packet->getTowerY(), packet->getTowerType(), m_ID);
|
protocol::WorldAddTowerPacket addTowerPacket(tower->getID(), packet->getTowerX(), packet->getTowerY(), packet->getTowerType(), m_ID);
|
||||||
m_Server->broadcastPacket(&addTowerPacket);
|
m_Server->broadcastPacket(&addTowerPacket);
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ WorldRenderer::WorldRenderer(game::World* world, client::ClientGame* client) : m
|
|||||||
m_Renderer->setCamMovement({});
|
m_Renderer->setCamMovement({});
|
||||||
m_TowerPlacePopup = std::make_unique<gui::TowerPlacePopup>(m_Client->getClient());
|
m_TowerPlacePopup = std::make_unique<gui::TowerPlacePopup>(m_Client->getClient());
|
||||||
m_MobTooltip = std::make_unique<gui::MobTooltip>(m_Client->getClient());
|
m_MobTooltip = std::make_unique<gui::MobTooltip>(m_Client->getClient());
|
||||||
m_Client->getWorld().bindListener(this);
|
m_Client->getWorld().getWorldNotifier().bindListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldRenderer::updateCursorPos() {
|
void WorldRenderer::updateCursorPos() {
|
||||||
|
|||||||
@@ -17,12 +17,14 @@ MobTooltip::MobTooltip(client::Client* client) : GuiWidget(client) {
|
|||||||
void MobTooltip::render() {
|
void MobTooltip::render() {
|
||||||
if (m_Mob == nullptr) return;
|
if (m_Mob == nullptr) return;
|
||||||
|
|
||||||
const game::Player& sender = getClient()->getGame().getPlayerById(m_Mob->getSender());
|
// TODO: add sender null check
|
||||||
|
|
||||||
|
const game::Player* sender = getClient()->getGame().getPlayerById(m_Mob->getSender());
|
||||||
ImGui::BeginTooltip();
|
ImGui::BeginTooltip();
|
||||||
ImGui::Text("Sender :");
|
ImGui::Text("Sender :");
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::PushStyleColor(ImGuiCol_Text, render::WorldRenderer::getImGuiTeamColor(sender.getTeamColor()));
|
ImGui::PushStyleColor(ImGuiCol_Text, render::WorldRenderer::getImGuiTeamColor(sender->getTeamColor()));
|
||||||
ImGui::Text("%s", sender.getName().c_str());
|
ImGui::Text("%s", sender->getName().c_str());
|
||||||
ImGui::PopStyleColor();
|
ImGui::PopStyleColor();
|
||||||
ImGui::Text("Mob HP : %.1f/%i", m_Mob->getHealth(), m_Mob->getStats()->getMaxLife());
|
ImGui::Text("Mob HP : %.1f/%i", m_Mob->getHealth(), m_Mob->getStats()->getMaxLife());
|
||||||
ImGui::Text("Mob Type : %s", game::MobFactory::getMobName(m_Mob->getType()).c_str());
|
ImGui::Text("Mob Type : %s", game::MobFactory::getMobName(m_Mob->getType()).c_str());
|
||||||
|
|||||||
@@ -38,6 +38,9 @@ target("TowerDefense")
|
|||||||
if is_os("linux") then
|
if is_os("linux") then
|
||||||
add_links("dw")
|
add_links("dw")
|
||||||
end
|
end
|
||||||
|
if is_os("windows") then
|
||||||
|
add_links("dbghelp", "psapi", "kernel32", "msvcr90")
|
||||||
|
end
|
||||||
add_cxflags("-pedantic -Wall -Wextra -Wcast-align -Wcast-qual -Wctor-dtor-privacy -Wdisabled-optimization -Wformat=2 -Winit-self -Wlogical-op -Wmissing-declarations -Wmissing-include-dirs -Wnoexcept -Wold-style-cast -Woverloaded-virtual -Wredundant-decls -Wshadow -Wsign-conversion -Wsign-promo -Wstrict-null-sentinel -Wstrict-overflow=5 -Wswitch-default -Wundef -Wno-unused")
|
add_cxflags("-pedantic -Wall -Wextra -Wcast-align -Wcast-qual -Wctor-dtor-privacy -Wdisabled-optimization -Wformat=2 -Winit-self -Wlogical-op -Wmissing-declarations -Wmissing-include-dirs -Wnoexcept -Wold-style-cast -Woverloaded-virtual -Wredundant-decls -Wshadow -Wsign-conversion -Wsign-promo -Wstrict-null-sentinel -Wstrict-overflow=5 -Wswitch-default -Wundef -Wno-unused")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user