39 Commits

Author SHA1 Message Date
7e91b863da bump version to alpha-0.0.4 2021-12-08 15:39:26 +01:00
129bb47286 feat: debug library 2021-12-08 15:38:20 +01:00
e4a9c5f763 feat: remove tower 2021-12-08 15:34:20 +01:00
78cf2d0f18 Merge branch 'master' of 192.168.0.5:repos/Tower-Defense 2021-12-05 12:01:50 +01:00
00d2b5394f refactor: removed unused include 2021-12-05 12:01:17 +01:00
00414abe61 refactor: comment main 2021-12-04 19:09:26 +01:00
cb847d0edd refactor: removed unused declarations 2021-12-04 13:49:50 +01:00
2da0bd9b79 refactor: tower add event processing 2021-12-04 13:44:34 +01:00
cf9633c061 fix: mob spawning repartition 2021-12-03 18:47:55 +01:00
7a6fdc30b6 add fire arrow and fix world events 2021-12-03 18:30:45 +01:00
657fe761ab feat: bump version to alpha-0.0.3 2021-11-30 18:45:42 +01:00
687944bf51 fix: don't call onmobdamage with null damage 2021-11-30 18:45:09 +01:00
93e079ddb3 refactor: archer tower aoe damage 2021-11-30 18:38:40 +01:00
8171a91ed5 feat: add world notifier 2021-11-30 18:36:29 +01:00
0c1824e40b refactor: movd Updater 2021-11-30 18:07:25 +01:00
f91ab4bc83 fix: compilation error 2021-11-30 18:06:33 +01:00
1843fc6f4d feat: add archer tower aoe 2021-11-30 18:01:48 +01:00
6a51638b7e feat: add more shape distances 2021-11-30 18:01:07 +01:00
8351c5d09f refactor: add typo 2021-11-30 18:00:41 +01:00
ee94c811e1 feat: add archer tower damage 2021-11-30 18:00:19 +01:00
50a8269773 feat: add better mob pathing 2021-11-30 11:53:58 +01:00
2996c88d94 feat: add mob coords in tile coords space 2021-11-30 11:23:03 +01:00
55263fa582 fix: changed skel effect immunities 2021-11-29 16:39:29 +01:00
adeddee09d refactor: mob move lock (Castle) 2021-11-29 16:36:27 +01:00
f0115166c0 fix: compiler warning 2021-11-22 19:39:09 +01:00
c1affc36c0 chore: bump version to alpha-0.0.2 2021-11-22 19:36:14 +01:00
6c4ef25abd style: changed tower place popup size 2021-11-22 19:35:50 +01:00
fd0a5e5848 feat: mob stop in front of castle 2021-11-22 19:33:00 +01:00
7fb357e9c8 feat: add working shapes 2021-11-22 19:15:32 +01:00
1d7a8cc66b refactor: removed useless includePath 2021-11-22 18:00:55 +01:00
070749e685 feat: implement shapes for entities 2021-11-21 20:00:35 +01:00
a716e46c64 refactor(Team): moved include to source file 2021-11-21 19:44:20 +01:00
2e2aeb44b9 feat: add shapes 2021-11-21 18:51:54 +01:00
2df76248be chore: use c++17 2021-11-21 18:50:38 +01:00
36f1430ff2 refactor: changed cast type 2021-11-21 17:21:34 +01:00
2e14827f13 refactor: add mob size getter 2021-11-21 17:19:50 +01:00
c7d81de60e feat: add mob size 2021-11-21 17:18:45 +01:00
f48af51dc7 refactor: format project 2021-11-21 17:02:42 +01:00
0f328e6f81 fix: world tile pos calculation 2021-11-20 19:27:06 +01:00
61 changed files with 5361 additions and 413 deletions

View File

@@ -2,10 +2,13 @@
#include "Towers.h" #include "Towers.h"
#include "Types.h" #include "Types.h"
#include "Team.h"
#include <vector> #include <vector>
#include <memory> #include <memory>
#include <glm/glm.hpp>
namespace td { namespace td {
namespace game { namespace game {
@@ -41,27 +44,29 @@ class MobStats {
private: private:
float m_Damage; float m_Damage;
float m_Speed; float m_Speed;
glm::vec2 m_Size;
std::uint16_t m_MoneyCost; std::uint16_t m_MoneyCost;
std::uint16_t m_ExpCost; std::uint16_t m_ExpCost;
std::uint16_t m_MaxLife; std::uint16_t m_MaxLife;
std::uint16_t m_ExpReward; std::uint16_t m_ExpReward;
public: public:
MobStats(float damage, float speed, std::uint16_t moneyCost, MobStats(float damage, float speed, glm::vec2 size, std::uint16_t moneyCost,
std::uint16_t expCost, std::uint16_t expReward, std::uint16_t expCost, std::uint16_t expReward,
std::uint16_t maxLife) : m_Damage(damage), m_Speed(speed), std::uint16_t maxLife) : m_Damage(damage), m_Speed(speed),
m_MoneyCost(moneyCost), m_ExpCost(expCost), m_MaxLife(maxLife), m_Size(size), m_MoneyCost(moneyCost), m_ExpCost(expCost),
m_ExpReward(expReward) { m_MaxLife(maxLife), m_ExpReward(expReward) {
} }
float getDamage() const { return m_Damage; } float getDamage() const { return m_Damage; }
float getMovementSpeed() const { return m_Speed; } 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 getMoneyCost() const { return m_MoneyCost; }
std::uint16_t getExpCost() const { return m_ExpCost; } std::uint16_t getExpCost() const { return m_ExpCost; }
std::uint16_t getExpReward() const { return m_ExpReward; } std::uint16_t getExpReward() const { return m_ExpReward; }
std::uint16_t getMaxLife() const { return m_MaxLife; } std::uint16_t getMaxLife() const { return m_MaxLife; }
}; };
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 const Tower* tower; // the tower that gived the effect
@@ -71,7 +76,7 @@ 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);
class Mob { class Mob : public utils::shape::Rectangle {
protected: protected:
float m_Health; float m_Health;
private: private:
@@ -80,16 +85,17 @@ 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_LastDamage; // the 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;
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) { m_HasReachedCastle(false), m_EffectFireTimer(1000), m_EffectPoisonTimer(1000),
m_EffectHealTimer(1000) {
} }
@@ -97,7 +103,7 @@ public:
virtual void tick(std::uint64_t delta); virtual void tick(std::uint64_t delta);
virtual void OnDeath(World* world){} virtual bool OnDeath(World* world) { return true; }
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); }
@@ -108,15 +114,11 @@ 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; }
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((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
float getX() const { return m_X; }
void setX(float x) { m_X = x; }
float getY() const { return m_Y; }
void setY(float y) { m_Y = y; }
bool isImmuneTo(TowerType type); bool isImmuneTo(TowerType type);
@@ -124,11 +126,16 @@ public:
void addEffect(EffectType type, float durationSec, const Tower* tower); void addEffect(EffectType type, float durationSec, const 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 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; } Direction getDirection() const { return m_Direction; }
void setDirection(Direction dir) { m_Direction = dir; } void setDirection(Direction dir) { m_Direction = dir; }
protected: protected:
void initHealth() { m_Health = (float)getStats()->getMaxLife(); } void initMob() {
m_Health = static_cast<float>(getStats()->getMaxLife());
setSize(getStats()->getSize().x, getStats()->getSize().y);
}
private: private:
void updateEffects(std::uint64_t delta); void updateEffects(std::uint64_t delta);
EffectDuration& getEffect(EffectType type); EffectDuration& getEffect(EffectType type);
@@ -138,70 +145,70 @@ typedef std::shared_ptr<Mob> MobPtr;
class Zombie : public Mob { class Zombie : public Mob {
public: public:
Zombie(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { initHealth(); } Zombie(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { initMob(); }
virtual MobType getType() const { return MobType::Zombie; } virtual MobType getType() const { return MobType::Zombie; }
}; };
class Spider : public Mob { class Spider : public Mob {
public: public:
Spider(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { initHealth(); } Spider(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { initMob(); }
virtual MobType getType() const { return MobType::Spider; } virtual MobType getType() const { return MobType::Spider; }
}; };
class Skeleton : public Mob { class Skeleton : public Mob {
public: public:
Skeleton(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { initHealth(); } Skeleton(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { initMob(); }
virtual MobType getType() const { return MobType::Skeleton; } virtual MobType getType() const { return MobType::Skeleton; }
}; };
class PigMan : public Mob { class PigMan : public Mob {
public: public:
PigMan(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { initHealth(); } PigMan(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { initMob(); }
virtual MobType getType() const { return MobType::Pigman; } virtual MobType getType() const { return MobType::Pigman; }
}; };
class Creeper : public Mob { class Creeper : public Mob {
public: public:
Creeper(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { initHealth(); } Creeper(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { initMob(); }
virtual MobType getType() const { return MobType::Creeper; } virtual MobType getType() const { return MobType::Creeper; }
}; };
class Silverfish : public Mob { class Silverfish : public Mob {
public: public:
Silverfish(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { initHealth(); } Silverfish(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { initMob(); }
virtual MobType getType() const { return MobType::Silverfish; } virtual MobType getType() const { return MobType::Silverfish; }
}; };
class Blaze : public Mob { class Blaze : public Mob {
public: public:
Blaze(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { initHealth(); } Blaze(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { initMob(); }
virtual MobType getType() const { return MobType::Blaze; } virtual MobType getType() const { return MobType::Blaze; }
}; };
class Witch : public Mob { class Witch : public Mob {
public: public:
Witch(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { initHealth(); } Witch(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { initMob(); }
virtual MobType getType() const { return MobType::Witch; } virtual MobType getType() const { return MobType::Witch; }
}; };
class Slime : public Mob { class Slime : public Mob {
public: public:
Slime(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { initHealth(); } Slime(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { initMob(); }
virtual MobType getType() const { return MobType::Slime; } virtual MobType getType() const { return MobType::Slime; }
}; };
class Giant : public Mob { class Giant : public Mob {
public: public:
Giant(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { initHealth(); } Giant(MobID id, std::uint8_t level, PlayerID sender) : Mob(id, level, sender) { initMob(); }
virtual MobType getType() const { return MobType::Giant; } virtual MobType getType() const { return MobType::Giant; }
}; };

View File

@@ -22,7 +22,7 @@ private:
bool m_GoldChanged; bool m_GoldChanged;
bool m_ExpChanged; bool m_ExpChanged;
public: public:
Player(std::uint8_t id = 0) : m_TeamColor(game::TeamColor::None), m_Gold(0), m_Exp(0), m_ID(id), m_GoldPerSecond(5), Player(std::uint8_t id = 0) : m_TeamColor(game::TeamColor::None), m_Gold(0), m_Exp(0), m_ID(id), m_GoldPerSecond(5),
m_GoldChanged(false), m_ExpChanged(false) {} m_GoldChanged(false), m_ExpChanged(false) {}
const std::string& getName() const { return m_Name; } const std::string& getName() const { return m_Name; }
@@ -34,7 +34,7 @@ public:
std::uint8_t getGoldPerSecond() const { return m_GoldPerSecond; } std::uint8_t getGoldPerSecond() const { return m_GoldPerSecond; }
void setGoldPerSecond(std::uint8_t goldPerSecond) { m_GoldPerSecond = goldPerSecond; } void setGoldPerSecond(std::uint8_t goldPerSecond) { m_GoldPerSecond = goldPerSecond; }
std::uint32_t getGold() const { return m_Gold;} std::uint32_t getGold() const { return m_Gold; }
void setGold(std::uint32_t gold) { m_GoldChanged = true; m_Gold = gold; } void setGold(std::uint32_t gold) { m_GoldChanged = true; m_Gold = gold; }
void addGold(std::uint32_t gold) { m_GoldChanged = true; m_Gold += gold; } void addGold(std::uint32_t gold) { m_GoldChanged = true; m_Gold += gold; }
void removeGold(std::uint32_t gold) { m_GoldChanged = true; m_Gold -= gold; } void removeGold(std::uint32_t gold) { m_GoldChanged = true; m_Gold -= gold; }

View File

@@ -2,9 +2,11 @@
#include "Types.h" #include "Types.h"
#include "misc/Shapes.h"
#include <vector> #include <vector>
#include <memory> #include <memory>
#include <algorithm> #include <cmath>
namespace td { namespace td {
namespace game { namespace game {
@@ -17,14 +19,33 @@ enum class TeamColor : std::int8_t {
Blue Blue
}; };
struct Spawn { class Spawn : public utils::shape::Rectangle {
Direction direction; private:
std::int32_t x, y; Direction m_Direction;
public:
Spawn(){
setWidth(5);
setHeight(5);
}
Direction getDirection() const { return m_Direction; }
void setDirection(Direction direction) { m_Direction = direction; }
}; };
struct TeamCastle { struct TeamCastle : public utils::shape::Rectangle{
std::int32_t x, y; private:
std::uint16_t life = 1000; float m_Life;
public:
TeamCastle() : m_Life(1000) {
setWidth(5);
setHeight(5);
}
float getLife() const { return m_Life; }
void setLife(float life) { m_Life = life; }
void damage(float damage) { m_Life = std::max(0.0f, m_Life - damage); }
}; };
class Team { class Team {

View File

@@ -5,6 +5,8 @@
#include <memory> #include <memory>
#include "misc/Time.h" #include "misc/Time.h"
#include "misc/Shapes.h"
#include "game/Types.h" #include "game/Types.h"
namespace td { namespace td {
@@ -85,19 +87,18 @@ const TowerStats* getTowerStats(TowerType type, TowerLevel level);
typedef std::uint16_t TowerID; typedef std::uint16_t TowerID;
class Tower { class Tower : public utils::shape::Circle {
private: private:
TowerID m_ID; TowerID m_ID;
TowerType m_Type; TowerType m_Type;
std::int32_t m_X, m_Y;
TowerLevel m_Level{}; TowerLevel m_Level{};
PlayerID m_Builder; PlayerID m_Builder;
protected: protected:
utils::CooldownTimer m_Timer; utils::CooldownTimer m_Timer;
public: public:
Tower(TowerID id, TowerType type, std::int32_t x, std::int32_t y, PlayerID builder) : m_ID(id), m_Type(type), m_X(x), m_Y(y), m_Builder(builder), Tower(TowerID id, TowerType type, std::int32_t x, std::int32_t y, PlayerID builder) : utils::shape::Circle(x + 0.5f, y + 0.5f, 0), m_ID(id), m_Type(type), m_Builder(builder),
m_Timer(getStats()->getDamageRate() * 1000) { // converting seconds to millis m_Timer(getStats()->getDamageRate() * 1000) { // converting seconds to millis
setRadius(getStats()->getRange());
} }
virtual TowerType getType() const = 0; virtual TowerType getType() const = 0;
@@ -109,11 +110,10 @@ public:
m_Level.setPath(path); m_Level.setPath(path);
m_Timer.setCooldown(getStats()->getDamageRate() * 1000); // converting seconds to millis m_Timer.setCooldown(getStats()->getDamageRate() * 1000); // converting seconds to millis
m_Timer.reset(); m_Timer.reset();
setRadius(getStats()->getRange());
} }
std::uint16_t getID() const { return m_ID; } std::uint16_t getID() const { return m_ID; }
std::int32_t getX() const { return m_X; }
std::int32_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; } PlayerID getBuilder() const { return m_Builder; }
@@ -163,6 +163,9 @@ class ArcherTower : public LittleTower {
public: public:
ArcherTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : LittleTower(id, getType(), x, y, builder) {} ArcherTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : LittleTower(id, getType(), x, y, builder) {}
constexpr static float ExplosionRadius = 1.5f;
constexpr static float FireDurationSec = 10.0f;
virtual TowerType getType() const { return TowerType::Archer; } virtual TowerType getType() const { return TowerType::Archer; }
virtual void tick(std::uint64_t delta, World* world); virtual void tick(std::uint64_t delta, World* world);
}; };

View File

@@ -10,6 +10,8 @@
#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;
@@ -114,7 +116,26 @@ typedef std::array<Color, 2> SpawnColorPalette;
typedef std::vector<TowerPtr> TowerList; typedef std::vector<TowerPtr> TowerList;
class World { class WorldListener {
public:
WorldListener() {}
virtual void OnTowerAdd(TowerPtr tower) {}
virtual void OnTowerRemove(TowerPtr tower) {}
virtual void OnArcherTowerShot(MobPtr target, ArcherTower* shooter) {}
virtual void OnArrowShot(MobPtr target, bool fire, 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;
class World : public WorldNotifier, public WorldListener {
protected: protected:
TowerTileColorPalette m_TowerPlacePalette; TowerTileColorPalette m_TowerPlacePalette;
Color m_WalkablePalette; Color m_WalkablePalette;
@@ -134,6 +155,8 @@ protected:
public: public:
World(Game* game); World(Game* game);
static constexpr std::uint8_t CastleWidth = 5, CastleHeight = 5;
bool loadMap(const protocol::WorldBeginDataPacket* worldHeader); bool loadMap(const protocol::WorldBeginDataPacket* worldHeader);
bool loadMap(const protocol::WorldDataPacket* worldData); bool loadMap(const protocol::WorldDataPacket* worldData);
@@ -145,6 +168,7 @@ public:
void spawnMobAt(MobID id, MobType type, std::uint8_t level, PlayerID sender, float x, float y, Direction dir); void spawnMobAt(MobID id, MobType type, std::uint8_t level, PlayerID sender, float x, float y, Direction dir);
TowerPtr placeTowerAt(TowerID id, TowerType type, std::int32_t x, std::int32_t y, PlayerID builder); TowerPtr placeTowerAt(TowerID id, TowerType type, std::int32_t x, std::int32_t y, PlayerID builder);
TowerPtr removeTower(TowerID id);
TilePtr getTile(std::int32_t x, std::int32_t y) const; TilePtr getTile(std::int32_t x, std::int32_t y) const;
@@ -187,10 +211,20 @@ public:
const TowerList& getTowers() const { return m_Towers; }; const TowerList& getTowers() const { return m_Towers; };
TowerPtr getTowerById(TowerID tower); TowerPtr getTowerById(TowerID tower);
// Archer Tower // WorldListener
virtual void OnArrowShot(MobPtr target, Tower* shooter);
virtual void OnArcherTowerShot(MobPtr target, ArcherTower* shooter);
virtual void OnArrowShot(MobPtr target, bool fire, Tower* shooter);
virtual void OnExplosion(utils::shape::Circle explosion, float centerDamage, Tower* shooter);
virtual void OnMobDamage(MobPtr target, float damage, Tower* source);
private: private:
void moveMobs(std::uint64_t delta); 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();
}; };

View File

@@ -44,6 +44,7 @@ public:
void sendMobs(const std::vector<protocol::MobSend>& mobSends); void sendMobs(const std::vector<protocol::MobSend>& mobSends);
void placeTower(game::TowerType type, const glm::vec2& position); void placeTower(game::TowerType type, const glm::vec2& position);
void upgradeTower(game::TowerID tower, game::TowerLevel level); void upgradeTower(game::TowerID tower, game::TowerLevel level);
void removeTower(game::TowerID tower);
}; };
} // namespace client } // namespace client

View File

@@ -37,6 +37,7 @@ public:
Client* getClient() const { return m_Client; } Client* getClient() const { return m_Client; }
render::Renderer* getRenderer() const { return m_Renderer; } render::Renderer* getRenderer() const { return m_Renderer; }
WorldClient& getWorld() { return m_WorldClient; }
virtual void HandlePacket(const protocol::ConnexionInfoPacket* packet); virtual void HandlePacket(const protocol::ConnexionInfoPacket* packet);
virtual void HandlePacket(const protocol::PlayerJoinPacket* packet); virtual void HandlePacket(const protocol::PlayerJoinPacket* packet);
@@ -48,7 +49,7 @@ public:
virtual void HandlePacket(const protocol::UpdateMoneyPacket* packet); virtual void HandlePacket(const protocol::UpdateMoneyPacket* packet);
virtual void HandlePacket(const protocol::DisconnectPacket* packet); virtual void HandlePacket(const protocol::DisconnectPacket* packet);
virtual void HandlePacket(const protocol::WorldDataPacket* packet); virtual void HandlePacket(const protocol::WorldDataPacket* packet);
virtual void HandlePacket(const protocol::WorldAddTowerPacket* packet);
}; };
} // namespace client } // namespace client

View File

@@ -14,12 +14,13 @@ private:
public: public:
WorldClient(ClientGame* game); WorldClient(ClientGame* game);
virtual void HandlePacket(const protocol::WorldBeginDataPacket* packet) override; virtual void HandlePacket(const protocol::WorldBeginDataPacket* packet);
virtual void HandlePacket(const protocol::WorldDataPacket* packet) override; virtual void HandlePacket(const protocol::WorldDataPacket* packet);
virtual void HandlePacket(const protocol::SpawnMobPacket* packet) override; virtual void HandlePacket(const protocol::SpawnMobPacket* packet);
virtual void HandlePacket(const protocol::UpgradeTowerPacket* packet) override; virtual void HandlePacket(const protocol::UpgradeTowerPacket* packet);
virtual void HandlePacket(const protocol::WorldAddTowerPacket* packet);
virtual void HandlePacket(const protocol::RemoveTowerPacket* packet);
virtual void OnArrowShot(game::MobPtr target, game::Tower* shooter) override;
}; };
} // namespace client } // namespace client

View File

@@ -40,6 +40,7 @@ public:
virtual void HandlePacket(const protocol::PlaceTowerPacket* packet); virtual void HandlePacket(const protocol::PlaceTowerPacket* packet);
virtual void HandlePacket(const protocol::SendMobsPacket* packet); virtual void HandlePacket(const protocol::SendMobsPacket* packet);
virtual void HandlePacket(const protocol::UpgradeTowerPacket* packet); virtual void HandlePacket(const protocol::UpgradeTowerPacket* packet);
virtual void HandlePacket(const protocol::RemoveTowerPacket* packet);
std::uint8_t getID() const { return m_ID; } std::uint8_t getID() const { return m_ID; }
const game::Player* getPlayer() const { return m_Player; } const game::Player* getPlayer() const { return m_Player; }

View File

@@ -19,7 +19,6 @@ public:
void spawnMobs(game::MobType type, std::uint8_t level, game::PlayerID sender, std::uint8_t count); void spawnMobs(game::MobType type, std::uint8_t level, game::PlayerID sender, std::uint8_t count);
game::TowerPtr placeTowerAt(game::TowerType type, std::int32_t x, std::int32_t y, game::PlayerID builder); game::TowerPtr placeTowerAt(game::TowerType type, std::int32_t x, std::int32_t y, game::PlayerID builder);
virtual void OnArrowShot(game::MobPtr target, game::Tower* shooter) override;
}; };
} // namespace server } // namespace server

4465
include/misc/Backward.hpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
#pragma once #pragma once
#include <cstdint> #include <cstdint>
#include "misc/DataBuffer.h" #include "DataBuffer.h"
namespace td { namespace td {
namespace utils { namespace utils {

View File

@@ -0,0 +1,36 @@
#pragma once
#include <algorithm>
#include <functional>
#include <vector>
namespace td {
namespace utils {
template <typename Listener>
class ObjectNotifier {
protected:
std::vector<Listener*> m_Listeners;
public:
void bindListener(Listener* listener) {
m_Listeners.push_back(listener);
}
void unbindListener(Listener* listener) {
auto iter = std::find(m_Listeners.begin(), m_Listeners.end(), listener);
if(iter == m_Listeners.end()) return;
m_Listeners.erase(iter);
}
template <typename Func, typename... Args>
void notifyListeners(Func function, Args... args) {
for (Listener* listener : m_Listeners)
std::bind(function, listener, args...)();
}
};
} // namespace utils
} // namespace td

View File

@@ -18,7 +18,7 @@ enum class Architecture {
Unknown, Unknown,
}; };
inline Os getSystemOs(){ inline Os getSystemOs() {
#if defined(_WIN32) || defined(_WIN64) #if defined(_WIN32) || defined(_WIN64)
return Os::Windows; return Os::Windows;
#elif defined(__ANDROID__) #elif defined(__ANDROID__)
@@ -26,12 +26,12 @@ inline Os getSystemOs(){
#elif defined(__unix__) #elif defined(__unix__)
return Os::Linux; return Os::Linux;
#else #else
#pragma message ("Target OS unknown or unsupported !") #pragma message ("Target OS unknown or unsupported !")
return Os::Unknown; return Os::Unknown;
#endif #endif
} }
inline Architecture getSystemArchitecture(){ inline Architecture getSystemArchitecture() {
#if defined(_WIN64) #if defined(_WIN64)
return Architecture::x86_64; return Architecture::x86_64;
#elif defined(_WIN32) #elif defined(_WIN32)
@@ -45,7 +45,7 @@ inline Architecture getSystemArchitecture(){
#elif defined(__arm__) || defined(_M_ARM) #elif defined(__arm__) || defined(_M_ARM)
return Architecture::Armhf; return Architecture::Armhf;
#else #else
#pragma message ("Target CPU architecture unknown or unsupported !") #pragma message ("Target CPU architecture unknown or unsupported !")
return Architecture::Unknown; return Architecture::Unknown;
#endif #endif
} }

View File

@@ -6,7 +6,7 @@ namespace td {
namespace utils { namespace utils {
template<typename NumberType> template<typename NumberType>
NumberType getRandomInt(NumberType min, NumberType max){ NumberType getRandomInt(NumberType min, NumberType max) {
std::random_device randomDevice; std::random_device randomDevice;
std::mt19937 generator(randomDevice()); std::mt19937 generator(randomDevice());
std::uniform_int_distribution<NumberType> distrib(min, max); std::uniform_int_distribution<NumberType> distrib(min, max);
@@ -14,7 +14,7 @@ NumberType getRandomInt(NumberType min, NumberType max){
} }
template<typename NumberType> template<typename NumberType>
NumberType getRandomReal(NumberType min, NumberType max){ NumberType getRandomReal(NumberType min, NumberType max) {
std::random_device randomDevice; std::random_device randomDevice;
std::mt19937 generator(randomDevice()); std::mt19937 generator(randomDevice());
std::uniform_real_distribution<NumberType> distrib(min, max); std::uniform_real_distribution<NumberType> distrib(min, max);

93
include/misc/Shapes.h Normal file
View File

@@ -0,0 +1,93 @@
#pragma once
#include <cstdint>
namespace td {
namespace utils {
namespace shape {
class Point {
private:
float m_X, m_Y;
public:
Point() : m_X(0), m_Y(0) {}
Point(float x, float y) : m_X(x), m_Y(y) {}
float getX() const { return m_X; }
float getY() const { return m_Y; }
void setX(float x) { m_X = x; }
void setY(float y) { m_Y = y; }
float distance(const Point& point) const;
float distanceSquared(const Point& point) const;
};
class Circle;
class Rectangle {
private:
Point m_Center;
float m_Width, m_Height;
public:
Rectangle() {}
const Point& getCenter() const { return m_Center; }
float getCenterX() const { return m_Center.getX(); }
float getCenterY() const { return m_Center.getY(); }
float getWidth() const { return m_Width; }
float getHeight() const { return m_Height; }
Point getTopLeft() const { return { m_Center.getX() - (m_Width / 2.0f), m_Center.getY() - (m_Height / 2.0f) }; }
Point getBottomRight() const { return { m_Center.getX() + (m_Width / 2.0f), m_Center.getY() + (m_Height / 2.0f) }; }
void setCenter(const Point& center) { m_Center = center; }
void setCenterX(float x) { m_Center.setX(x); }
void setCenterY(float y) { m_Center.setY(y); }
void setSize(float width, float height) { setWidth(width); setHeight(height); }
void setWidth(float width) { m_Width = width; }
void setHeight(float height) { m_Height = height; }
bool collidesWith(const Point& point) const;
bool collidesWith(const Rectangle& rect) const;
bool collidesWith(const Circle& circle) const;
// distance from the closest side of the rectangle
float distance(const Circle& circle) const;
float distanceSquared(const Circle& circle) const;
};
class Circle {
private:
Point m_Center;
float m_Radius;
public:
Circle(float x, float y, float radius) : m_Center(x, y), m_Radius(radius) {}
Circle() : m_Radius(0) {}
const Point& getCenter() const { return m_Center; }
float getCenterX() const { return m_Center.getX(); }
float getCenterY() const { return m_Center.getY(); }
float getRadius() const { return m_Radius; }
void setCenter(const Point& center) { m_Center = center; }
void setCenterX(float x) { m_Center.setX(x); }
void setCenterY(float y) { m_Center.setY(y); }
void setRadius(float radius) { m_Radius = radius; }
bool collidesWith(const Point& point) const;
bool collidesWith(const Rectangle& rect) const;
bool collidesWith(const Circle& circle) const;
// distance from the closest side of the rectangle
float distance(const Rectangle& rect) const;
float distanceSquared(const Rectangle& rect) const;
};
} // namespace shape
} // namespace utils
} // namespace td

View File

@@ -39,7 +39,7 @@ public:
// utililty class to call function at regular period of time // utililty class to call function at regular period of time
class Timer { class Timer {
private: private:
std::uint64_t m_Interval; std::uint64_t m_Interval; // in millis
std::uint64_t m_InternalTime = 0; std::uint64_t m_InternalTime = 0;
public: public:
Timer() : m_Interval(0) {} Timer() : m_Interval(0) {}
@@ -56,7 +56,7 @@ public:
// 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)
class CooldownTimer { class CooldownTimer {
private: private:
std::uint64_t m_Cooldown; std::uint64_t m_Cooldown; // in millis
std::uint64_t m_CooldownTime; std::uint64_t m_CooldownTime;
public: public:
CooldownTimer() : m_Cooldown(0), m_CooldownTime(0) {} CooldownTimer() : m_Cooldown(0), m_CooldownTime(0) {}
@@ -64,7 +64,7 @@ public:
bool update(std::uint64_t delta); bool update(std::uint64_t delta);
void applyCooldown(); void applyCooldown();
void reset(); void reset();

View File

@@ -35,7 +35,7 @@ public:
virtual void HandlePacket(const SpawnMobPacket* packet) {} virtual void HandlePacket(const SpawnMobPacket* packet) {}
virtual void HandlePacket(const PlaceTowerPacket* packet) {} virtual void HandlePacket(const PlaceTowerPacket* packet) {}
virtual void HandlePacket(const WorldAddTowerPacket* packet) {} virtual void HandlePacket(const WorldAddTowerPacket* packet) {}
virtual void HandlePacket(const WorldRemoveTowerPacket* packet) {} virtual void HandlePacket(const RemoveTowerPacket* packet) {}
virtual void HandlePacket(const SendMobsPacket* packet) {} virtual void HandlePacket(const SendMobsPacket* packet) {}
virtual void HandlePacket(const UpgradeTowerPacket* packet) {} virtual void HandlePacket(const UpgradeTowerPacket* packet) {}
}; };

View File

@@ -33,12 +33,12 @@ enum class PacketType : std::uint8_t {
UpdatePlayerTeam, UpdatePlayerTeam,
ServerTps, ServerTps,
WorldAddTower, WorldAddTower,
WorldRemoveTower,
// client <--> server // client <--> server
KeepAlive, KeepAlive,
Disconnect, Disconnect,
UpgradeTower, UpgradeTower,
RemoveTower,
}; };
struct WorldHeader { struct WorldHeader {
@@ -477,13 +477,13 @@ public:
virtual PacketType getType() const { return PacketType::WorldAddTower; } virtual PacketType getType() const { return PacketType::WorldAddTower; }
}; };
class WorldRemoveTowerPacket : public Packet { class RemoveTowerPacket : public Packet {
private: private:
game::TowerID m_TowerID; game::TowerID m_TowerID;
public: public:
WorldRemoveTowerPacket() {} RemoveTowerPacket() {}
WorldRemoveTowerPacket(game::TowerID id) : m_TowerID(id) {} RemoveTowerPacket(game::TowerID id) : m_TowerID(id) {}
virtual ~WorldRemoveTowerPacket() {} virtual ~RemoveTowerPacket() {}
virtual DataBuffer Serialize() const; virtual DataBuffer Serialize() const;
virtual void Deserialize(DataBuffer& data); virtual void Deserialize(DataBuffer& data);
@@ -491,7 +491,7 @@ public:
game::TowerID getTowerID() const { return m_TowerID; } game::TowerID getTowerID() const { return m_TowerID; }
virtual PacketType getType() const { return PacketType::WorldRemoveTower; } virtual PacketType getType() const { return PacketType::RemoveTower; }
}; };
class UpgradeTowerPacket : public Packet { class UpgradeTowerPacket : public Packet {

View File

@@ -12,15 +12,19 @@ namespace render {
class VertexCache { class VertexCache {
typedef std::vector<float> Vector; typedef std::vector<float> Vector;
typedef std::pair<Vector::iterator, Vector::iterator> ElementsIndex;
typedef std::pair<ElementsIndex, ElementsIndex> DataIndex; struct DataIndex {
Vector position;
Vector color;
};
private: private:
Vector m_Positions; std::size_t m_VertexCount;
Vector m_Colors;
std::unordered_map<std::uint64_t, DataIndex> m_Indexes; std::unordered_map<std::uint64_t, DataIndex> m_Indexes;
std::unique_ptr<GL::VertexArray> m_VertexArray; std::unique_ptr<GL::VertexArray> m_VertexArray;
public: public:
VertexCache() : m_VertexCount(0) {}
void addData(std::uint64_t index, std::vector<float> positions, std::vector<float> colors); void addData(std::uint64_t index, std::vector<float> positions, std::vector<float> colors);
void removeData(std::uint64_t index); void removeData(std::uint64_t index);
void clear(); void clear();

View File

@@ -23,7 +23,7 @@ class ClientGame;
namespace render { namespace render {
class WorldRenderer { class WorldRenderer : public game::WorldListener {
private: private:
client::ClientGame* m_Client; client::ClientGame* m_Client;
Renderer* m_Renderer; Renderer* m_Renderer;
@@ -37,7 +37,7 @@ private:
float m_CamSensibility = 1; float m_CamSensibility = 1;
bool m_PopupOpened = false; bool m_PopupOpened = false;
VertexCache m_TowersCache; VertexCache m_TowersCache;
std::unique_ptr<gui::TowerPlacePopup> m_TowerPlacePopup; std::unique_ptr<gui::TowerPlacePopup> m_TowerPlacePopup;
std::unique_ptr<gui::MobTooltip> m_MobTooltip; std::unique_ptr<gui::MobTooltip> m_MobTooltip;
public: public:
@@ -46,9 +46,6 @@ public:
void loadModels(); void loadModels();
void addTower(game::TowerPtr tower);
void removeTower(game::TowerPtr tower);
static ImVec4 getImGuiTeamColor(game::TeamColor color); static ImVec4 getImGuiTeamColor(game::TeamColor color);
void update(); void update();
@@ -58,6 +55,11 @@ public:
void moveCam(float relativeX, float relativeY, float aspectRatio); void moveCam(float relativeX, float relativeY, float aspectRatio);
void changeZoom(float zoom); void changeZoom(float zoom);
// WorldListener
virtual void OnTowerAdd(game::TowerPtr tower);
virtual void OnTowerRemove(game::TowerPtr tower);
private: private:
void click(); void click();
void renderWorld() const; void renderWorld() const;
@@ -69,6 +71,7 @@ private:
void renderMobTooltip() const; void renderMobTooltip() const;
void detectClick(); void detectClick();
void detectMobHovering() const; void detectMobHovering() const;
void removeTower();
glm::vec2 getCursorWorldPos() const; glm::vec2 getCursorWorldPos() const;
glm::vec2 getClickWorldPos() const; glm::vec2 getClickWorldPos() const;

View File

@@ -12,13 +12,13 @@ class GuiManager {
private: private:
std::vector<std::shared_ptr<GuiWidget>> m_Widgets; std::vector<std::shared_ptr<GuiWidget>> m_Widgets;
public: public:
void renderWidgets(){ void renderWidgets() {
for(auto widget : m_Widgets){ for (auto widget : m_Widgets) {
widget->render(); widget->render();
} }
} }
void addWidgets(const std::shared_ptr<GuiWidget>& widget){ void addWidgets(const std::shared_ptr<GuiWidget>& widget) {
m_Widgets.push_back(std::move(widget)); m_Widgets.push_back(std::move(widget));
} }
}; };

View File

@@ -7,7 +7,7 @@ namespace td {
namespace game { namespace game {
class Mob; class Mob;
} // namespace game } // namespace game
namespace gui { namespace gui {

View File

@@ -8,7 +8,7 @@
namespace td { namespace td {
namespace gui { namespace gui {
class SummonMenu : public GuiWidget{ class SummonMenu : public GuiWidget {
private: private:
bool m_MenuOpened; bool m_MenuOpened;
int m_ImageWidth = 100; int m_ImageWidth = 100;

View File

@@ -10,7 +10,7 @@
#include <memory> #include <memory>
struct SDL_Window; struct SDL_Window;
typedef void *SDL_GLContext; typedef void* SDL_GLContext;
namespace td { namespace td {
@@ -26,7 +26,7 @@ class MainMenu;
class GameMenu; class GameMenu;
class FrameMenu; class FrameMenu;
class UpdateMenu; class UpdateMenu;
} // namespace gui } // namespace gui
namespace render { namespace render {

View File

@@ -17,11 +17,11 @@ public:
void setClickPos(const glm::vec2& worldPos); void setClickPos(const glm::vec2& worldPos);
private: private:
static constexpr float m_TowerPopupTileWidth = 250.0f; static constexpr float m_TowerPopupTileWidth = 200.0f;
static constexpr float m_TowerPopupTileHeight = 250.0f; static constexpr float m_TowerPopupTileHeight = 200.0f;
static constexpr float m_PlaceTowerButtonWidth = 200.0f; static constexpr float m_PlaceTowerButtonWidth = 150.0f;
static constexpr float m_PlaceTowerButtonHeight = 45.0f; static constexpr float m_PlaceTowerButtonHeight = 35.0f;
}; };
} // namespace gui } // namespace gui

View File

@@ -2,7 +2,7 @@
#include "GuiWidget.h" #include "GuiWidget.h"
#include "misc/Updater.h" #include "updater/Updater.h"
#include <future> #include <future>

View File

@@ -4,7 +4,7 @@
#include <ctime> #include <ctime>
#define TD_VERSION "alpha-0.0.1" #define TD_VERSION "alpha-0.0.4"
namespace td { namespace td {
namespace utils { namespace utils {
@@ -30,11 +30,11 @@ public:
float getDownloadProgress() { return m_Progress; } float getDownloadProgress() { return m_Progress; }
bool isDownloadComplete() { return m_DownloadComplete; } bool isDownloadComplete() { return m_DownloadComplete; }
bool isFileWrited() { return m_FileWrited; } bool isFileWrited() { return m_FileWrited; }
static std::string getLocalFilePath(); static std::string getLocalFilePath();
static void removeOldFile(); static void removeOldFile();
static std::string getCurrentVersion(){ return TD_VERSION; } static std::string getCurrentVersion() { return TD_VERSION; }
std::string getLastVersion() { return m_LastVersion; } std::string getLastVersion() { return m_LastVersion; }
bool canUpdate(); bool canUpdate();

View File

@@ -6,14 +6,24 @@
// Description : Hello World in C++, Ansi-style // Description : Hello World in C++, Ansi-style
//============================================================================ //============================================================================
#if !defined(NDEBUG) && !defined(_WIN32)
#define BACKWARD_HAS_UNWIND 1
#define BACKWARD_HAS_DW 1
#endif
#include "window/Display.h" #include "window/Display.h"
#include "misc/Updater.h" #include "updater/Updater.h"
#include "misc/Backward.hpp"
#ifdef __ANDROID__ #ifdef __ANDROID__
extern "C" extern "C"
#endif #endif
int main(int argc, const char* args[]) { int main(int argc, const char* args[]) {
// setup signal handling
backward::SignalHandling sh;
// remove the outdated binary
td::utils::Updater::removeOldFile(); td::utils::Updater::removeOldFile();
Display::create(); Display::create();

View File

@@ -14,7 +14,7 @@ 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();
} }
EffectDuration& Mob::getEffect(EffectType effectType){ 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;});
} }
@@ -39,40 +39,40 @@ void Mob::updateEffects(std::uint64_t delta) {
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.duration -= deltaSec; effect.duration -= deltaSec;
if (effect.duration < 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){ switch (effect.type) {
case EffectType::Fire:{ case EffectType::Fire: {
m_EffectFireTimer.reset(); m_EffectFireTimer.reset();
break; break;
} }
case EffectType::Poison:{ case EffectType::Poison: {
m_EffectPoisonTimer.reset(); m_EffectPoisonTimer.reset();
break; break;
} }
case EffectType::Heal:{ case EffectType::Heal: {
m_EffectHealTimer.reset(); m_EffectHealTimer.reset();
} }
default: default:
break; break;
} }
} }
} }
if(hasEffect(EffectType::Fire)){ if (hasEffect(EffectType::Fire)) {
if(m_EffectFireTimer.update(delta)){ if (m_EffectFireTimer.update(delta)) {
damage(3, getEffect(EffectType::Fire).tower); damage(3, 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); damage(1, getEffect(EffectType::Poison).tower);
} }
} }
if(hasEffect(EffectType::Heal)){ if (hasEffect(EffectType::Heal)) {
if(m_EffectFireTimer.update(delta)){ if (m_EffectFireTimer.update(delta)) {
heal(10); heal(10);
} }
} }
@@ -88,66 +88,66 @@ bool Mob::hasEffect(EffectType type) {
typedef std::pair<MobType, std::uint8_t> MobKey; typedef std::pair<MobType, std::uint8_t> MobKey;
const std::map<MobKey, MobStats> MobConstants = { const std::map<MobKey, MobStats> MobConstants = {
// damage speed money_cost exp_cost exp_reward max_health // damage speed size money_cost exp_cost exp_reward max_health
{{MobType::Zombie, 1},{MobStats{1, 1.6, 15, 0, 7, 40}}}, {{MobType::Zombie, 1},{MobStats{1, 1.6, {1, 1}, 15, 0, 7, 40}}},
{{MobType::Zombie, 2},{MobStats{1, 1.6, 18, 88, 9, 56}}}, {{MobType::Zombie, 2},{MobStats{1, 1.6, {1, 1}, 18, 88, 9, 56}}},
{{MobType::Zombie, 3},{MobStats{1, 1.6, 22, 153, 10, 78}}}, {{MobType::Zombie, 3},{MobStats{1, 1.6, {1, 1}, 22, 153, 10, 78}}},
{{MobType::Zombie, 4},{MobStats{1.5, 1.6, 26, 268, 13, 110}}}, {{MobType::Zombie, 4},{MobStats{1.5, 1.6, {1, 1}, 26, 268, 13, 110}}},
{{MobType::Zombie, 5},{MobStats{2, 1.6, 31, 469, 15, 154}}}, {{MobType::Zombie, 5},{MobStats{2, 1.6, {1, 1}, 31, 469, 15, 154}}},
{{MobType::Spider, 1},{MobStats{1, 1.6, 25, 100, 15, 80}}}, {{MobType::Spider, 1},{MobStats{1, 1.6, {1, 1}, 25, 100, 15, 80}}},
{{MobType::Spider, 2},{MobStats{1, 2, 30, 175, 16, 112}}}, {{MobType::Spider, 2},{MobStats{1, 2, {1, 1}, 30, 175, 16, 112}}},
{{MobType::Spider, 3},{MobStats{1.5, 2, 36, 306, 18, 157}}}, {{MobType::Spider, 3},{MobStats{1.5, 2, {1, 1}, 36, 306, 18, 157}}},
{{MobType::Spider, 4},{MobStats{2.5, 2, 43, 536, 19, 222}}}, {{MobType::Spider, 4},{MobStats{2.5, 2, {1, 1}, 43, 536, 19, 222}}},
{{MobType::Spider, 5},{MobStats{1.5, 2.5, 52, 938, 22, 307}}}, {{MobType::Spider, 5},{MobStats{1.5, 2.5, {1, 1}, 52, 938, 22, 307}}},
{{MobType::Skeleton, 1},{MobStats{1, 1.6, 120, 200, 30, 350}}}, {{MobType::Skeleton, 1},{MobStats{1, 1.6, {1, 1}, 120, 200, 30, 350}}},
{{MobType::Skeleton, 2},{MobStats{1, 1.6, 144, 350, 33, 490}}}, {{MobType::Skeleton, 2},{MobStats{1, 1.6, {1, 1}, 144, 350, 33, 490}}},
{{MobType::Skeleton, 3},{MobStats{1, 1.6, 173, 613, 36, 686}}}, {{MobType::Skeleton, 3},{MobStats{1, 1.6, {1, 1}, 173, 613, 36, 686}}},
{{MobType::Skeleton, 4},{MobStats{1.5, 1.6, 225, 1072, 40, 960}}}, {{MobType::Skeleton, 4},{MobStats{1.5, 1.6, {1, 1}, 225, 1072, 40, 960}}},
{{MobType::Skeleton, 5},{MobStats{2, 1.6, 255, 1876, 43, 1345}}}, {{MobType::Skeleton, 5},{MobStats{2, 1.6, {1, 1}, 255, 1876, 43, 1345}}},
{{MobType::Pigman, 1},{MobStats{1, 2, 100, 150, 22, 150}}}, {{MobType::Pigman, 1},{MobStats{1, 2, {1, 1}, 100, 150, 22, 150}}},
{{MobType::Pigman, 2},{MobStats{1, 2, 120, 263, 24, 210}}}, {{MobType::Pigman, 2},{MobStats{1, 2, {1, 1}, 120, 263, 24, 210}}},
{{MobType::Pigman, 3},{MobStats{1, 2, 144, 459, 25, 297}}}, {{MobType::Pigman, 3},{MobStats{1, 2, {1, 1}, 144, 459, 25, 297}}},
{{MobType::Pigman, 4},{MobStats{1, 2, 173, 804, 25, 412}}}, {{MobType::Pigman, 4},{MobStats{1, 2, {1, 1}, 173, 804, 25, 412}}},
{{MobType::Pigman, 5},{MobStats{1.5, 2, 207, 1407, 27, 576}}}, {{MobType::Pigman, 5},{MobStats{1.5, 2, {1, 1}, 207, 1407, 27, 576}}},
{{MobType::Creeper, 1},{MobStats{1, 2, 250, 325, 46, 350}}}, {{MobType::Creeper, 1},{MobStats{1, 2, {1, 1}, 250, 325, 46, 350}}},
{{MobType::Creeper, 2},{MobStats{1, 2, 290, 550, 49, 460}}}, {{MobType::Creeper, 2},{MobStats{1, 2, {1, 1}, 290, 550, 49, 460}}},
{{MobType::Creeper, 3},{MobStats{2, 2, 350, 800, 55, 630}}}, {{MobType::Creeper, 3},{MobStats{2, 2, {1, 1}, 350, 800, 55, 630}}},
{{MobType::Creeper, 4},{MobStats{3, 2, 420, 1300, 61, 900}}}, {{MobType::Creeper, 4},{MobStats{3, 2, {1, 1}, 420, 1300, 61, 900}}},
{{MobType::Creeper, 5},{MobStats{4, 2, 510, 1850, 67, 1250}}}, {{MobType::Creeper, 5},{MobStats{4, 2, {1, 1}, 510, 1850, 67, 1250}}},
{{MobType::Silverfish, 1},{MobStats{1, 1.6, 38, 125, 18, 120}}}, {{MobType::Silverfish, 1},{MobStats{1, 1.6, {1, 1}, 38, 125, 18, 120}}},
{{MobType::Silverfish, 2},{MobStats{1, 1.6, 50, 230, 19, 170}}}, {{MobType::Silverfish, 2},{MobStats{1, 1.6, {1, 1}, 50, 230, 19, 170}}},
{{MobType::Silverfish, 3},{MobStats{1, 1.6, 75, 340, 25, 225}}}, {{MobType::Silverfish, 3},{MobStats{1, 1.6, {1, 1}, 75, 340, 25, 225}}},
{{MobType::Silverfish, 4},{MobStats{1.5, 1.6, 170, 700, 33, 310}}}, {{MobType::Silverfish, 4},{MobStats{1.5, 1.6, {1, 1}, 170, 700, 33, 310}}},
{{MobType::Silverfish, 5},{MobStats{1.5, 1.6, 200, 1800, 36, 390}}}, {{MobType::Silverfish, 5},{MobStats{1.5, 1.6, {1, 1}, 200, 1800, 36, 390}}},
{{MobType::Blaze, 1},{MobStats{1, 1.6, 500, 500, 105, 410}}}, {{MobType::Blaze, 1},{MobStats{1, 1.6, {1, 1}, 500, 500, 105, 410}}},
{{MobType::Blaze, 2},{MobStats{1, 1.6, 600, 875, 111, 574}}}, {{MobType::Blaze, 2},{MobStats{1, 1.6, {1, 1}, 600, 875, 111, 574}}},
{{MobType::Blaze, 3},{MobStats{1, 1.6, 720, 1531, 115, 804}}}, {{MobType::Blaze, 3},{MobStats{1, 1.6, {1, 1}, 720, 1531, 115, 804}}},
{{MobType::Blaze, 4},{MobStats{1.5, 1.6, 864, 2680, 121, 1125}}}, {{MobType::Blaze, 4},{MobStats{1.5, 1.6, {1, 1}, 864, 2680, 121, 1125}}},
{{MobType::Blaze, 5},{MobStats{2, 1.6, 1037, 4689, 127, 1575}}}, {{MobType::Blaze, 5},{MobStats{2, 1.6, {1, 1}, 1037, 4689, 127, 1575}}},
{{MobType::Witch, 1},{MobStats{1, 1.6, 150, 300, 37, 300}}}, {{MobType::Witch, 1},{MobStats{1, 1.6, {1, 1}, 150, 300, 37, 300}}},
{{MobType::Witch, 2},{MobStats{1, 1.6, 165, 525, 39, 405}}}, {{MobType::Witch, 2},{MobStats{1, 1.6, {1, 1}, 165, 525, 39, 405}}},
{{MobType::Witch, 3},{MobStats{1, 1.6, 182, 918, 42, 547}}}, {{MobType::Witch, 3},{MobStats{1, 1.6, {1, 1}, 182, 918, 42, 547}}},
{{MobType::Witch, 4},{MobStats{1.5, 1.6, 200, 1606, 43, 738}}}, {{MobType::Witch, 4},{MobStats{1.5, 1.6, {1, 1}, 200, 1606, 43, 738}}},
{{MobType::Witch, 5},{MobStats{2, 1.6, 220, 2810, 45, 996}}}, {{MobType::Witch, 5},{MobStats{2, 1.6, {1, 1}, 220, 2810, 45, 996}}},
{{MobType::Slime, 1},{MobStats{1, 0.8, 1500, 1000, 300, 800}}}, {{MobType::Slime, 1},{MobStats{1, 0.8, {1, 1}, 1500, 1000, 300, 800}}},
{{MobType::Slime, 2},{MobStats{1.5, 0.8, 1800, 1750, 314, 880}}}, {{MobType::Slime, 2},{MobStats{1.5, 0.8, {1, 1}, 1800, 1750, 314, 880}}},
{{MobType::Slime, 3},{MobStats{2, 0.8, 2160, 3063, 330, 968}}}, {{MobType::Slime, 3},{MobStats{2, 0.8, {1, 1}, 2160, 3063, 330, 968}}},
{{MobType::Slime, 4},{MobStats{2.5, 0.8, 2592, 5359, 348, 1065}}}, {{MobType::Slime, 4},{MobStats{2.5, 0.8, {1, 1}, 2592, 5359, 348, 1065}}},
{{MobType::Slime, 5},{MobStats{3, 0.8, 3110, 9379, 366, 1171}}}, {{MobType::Slime, 5},{MobStats{3, 0.8, {1, 1}, 3110, 9379, 366, 1171}}},
{{MobType::Giant, 1},{MobStats{10, 0.8, 4000, 2250, 600, 6250}}}, {{MobType::Giant, 1},{MobStats{10, 0.8, {1, 1}, 4000, 2250, 600, 6250}}},
{{MobType::Giant, 2},{MobStats{20, 0.8, 4500, 4000, 612, 9375}}}, {{MobType::Giant, 2},{MobStats{20, 0.8, {1, 1}, 4500, 4000, 612, 9375}}},
{{MobType::Giant, 3},{MobStats{30, 0.8, 5062, 7250, 624, 14062}}}, {{MobType::Giant, 3},{MobStats{30, 0.8, {1, 1}, 5062, 7250, 624, 14062}}},
{{MobType::Giant, 4},{MobStats{40, 0.8, 5695, 12500, 636, 21093}}}, {{MobType::Giant, 4},{MobStats{40, 0.8, {1, 1}, 5695, 12500, 636, 21093}}},
{{MobType::Giant, 5},{MobStats{50, 0.8, 6407, 22000, 648, 31640}}}, {{MobType::Giant, 5},{MobStats{50, 0.8, {1, 1}, 6407, 22000, 648, 31640}}},
}; };
const MobStats* getMobStats(MobType type, std::uint8_t level) { const MobStats* getMobStats(MobType type, std::uint8_t level) {
@@ -235,7 +235,7 @@ const std::map<MobKey, EffectImmunities> MobsEffectImmunities = {
{{MobType::Skeleton, 1},{}}, {{MobType::Skeleton, 1},{}},
{{MobType::Skeleton, 2},{}}, {{MobType::Skeleton, 2},{}},
{{MobType::Skeleton, 3},{EffectType::Fire}}, {{MobType::Skeleton, 3},{}},
{{MobType::Skeleton, 4},{EffectType::Fire}}, {{MobType::Skeleton, 4},{EffectType::Fire}},
{{MobType::Skeleton, 5},{EffectType::Fire}}, {{MobType::Skeleton, 5},{EffectType::Fire}},
@@ -305,30 +305,30 @@ MobPtr MobFactory::createMob(MobID id, MobType type, std::uint8_t level, PlayerI
return mobFactory[type](id, level, sender); return mobFactory[type](id, level, sender);
} }
std::string MobFactory::getMobName(MobType type){ std::string MobFactory::getMobName(MobType type) {
switch(type){ switch (type) {
case MobType::Zombie: case MobType::Zombie:
return "Zombie"; return "Zombie";
case MobType::Spider: case MobType::Spider:
return "Spider"; return "Spider";
case MobType::Skeleton: case MobType::Skeleton:
return "Skeleton"; return "Skeleton";
case MobType::Pigman: case MobType::Pigman:
return "Pigman"; return "Pigman";
case MobType::Creeper: case MobType::Creeper:
return "Creeper"; return "Creeper";
case MobType::Silverfish: case MobType::Silverfish:
return "Silverfish"; return "Silverfish";
case MobType::Blaze: case MobType::Blaze:
return "Blaze"; return "Blaze";
case MobType::Witch: case MobType::Witch:
return "Witch"; return "Witch";
case MobType::Slime: case MobType::Slime:
return "Slime"; return "Slime";
case MobType::Giant: case MobType::Giant:
return "Giant"; return "Giant";
default: default:
return "Unknow"; return "Unknow";
} }
} }

View File

@@ -1,5 +1,7 @@
#include "game/Player.h" #include "game/Player.h"
#include <algorithm>
namespace td { namespace td {
namespace game { namespace game {

View File

@@ -9,7 +9,7 @@ namespace game {
bool Tower::isMobInRange(MobPtr mob) { bool Tower::isMobInRange(MobPtr mob) {
if (mob->isDead()) if (mob->isDead())
return false; return false;
return (m_X - mob->getX()) * (m_X - mob->getX()) + (m_Y - mob->getY()) * (m_Y - mob->getY()) < (getStats()->getRange() * getStats()->getRange()); return mob->collidesWith(*this);
} }
const std::map<std::pair<TowerType, TowerLevel>, TowerStats> TowerConstants = { const std::map<std::pair<TowerType, TowerLevel>, TowerStats> TowerConstants = {
@@ -21,8 +21,8 @@ const std::map<std::pair<TowerType, TowerLevel>, TowerStats> TowerConstants = {
{{TowerType::Archer, {4, TowerPath::Top}}, {0.8, 0, 15}}, {{TowerType::Archer, {4, TowerPath::Top}}, {0.8, 0, 15}},
{{TowerType::Archer, {2, TowerPath::Bottom}}, {2, 10, 12}}, {{TowerType::Archer, {2, TowerPath::Bottom}}, {2, 10, 12}},
{{TowerType::Archer, {3, TowerPath::Bottom}}, {2, 0, 13}}, {{TowerType::Archer, {3, TowerPath::Bottom}}, {2, 10, 13}},
{{TowerType::Archer, {4, TowerPath::Bottom}}, {2, 0, 15}}, {{TowerType::Archer, {4, TowerPath::Bottom}}, {2, 10, 15}},
//----------------------------------------------------------------- //-----------------------------------------------------------------
@@ -116,8 +116,8 @@ const std::map<std::pair<TowerType, TowerLevel>, TowerStats> TowerConstants = {
}; };
const TowerStats* getTowerStats(TowerType type, TowerLevel level) { const TowerStats* getTowerStats(TowerType type, TowerLevel level) {
auto it = TowerConstants.find({type, level}); auto it = TowerConstants.find({ type, level });
if(it == TowerConstants.end()) return nullptr; if (it == TowerConstants.end()) return nullptr;
return &it->second; return &it->second;
} }
@@ -213,11 +213,11 @@ 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->OnArrowShot(mob, this); world->notifyListeners(&WorldListener::OnArcherTowerShot, mob, this);
m_Timer.applyCooldown();
arrowsShot++; arrowsShot++;
if (arrowsShot >= arrows) if (arrowsShot >= arrows)
break; break;
m_Timer.applyCooldown();
} }
} }
} }
@@ -229,7 +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
mob->damage(damage, this); if(damage > 0)
world->notifyListeners(&WorldListener::OnMobDamage, mob, damage, this);
m_Timer.applyCooldown(); m_Timer.applyCooldown();
} }
} }
@@ -251,30 +252,30 @@ void PoisonTower::tick(std::uint64_t delta, World* world) {
if (m_Timer.update(delta)) { if (m_Timer.update(delta)) {
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) {
mob->damage(getStats()->getDamage(), this); world->notifyListeners(&WorldListener::OnMobDamage, mob, getStats()->getDamage(), this);
}else{ } else {
float durationSec; float durationSec;
switch(getLevel().getLevel()){ switch (getLevel().getLevel()) {
case 1: case 1:
durationSec = 5; durationSec = 5;
break; break;
case 2: case 2:
durationSec = 15; durationSec = 15;
break; break;
case 3: case 3:
durationSec = 30; durationSec = 30;
break; break;
case 4: case 4:
durationSec = 1e10; // about 3 million hours. It should be enough durationSec = 1e10; // about 3 million hours. It should be enough
break; break;
default: default:
durationSec = 0; // how did we get there ? durationSec = 0; // how did we get there ?
break; break;
} }
mob->addEffect(EffectType::Poison, durationSec, this); mob->addEffect(EffectType::Poison, durationSec, this);
} }

View File

@@ -13,15 +13,15 @@ namespace td {
namespace game { namespace game {
World::World(Game* game) : m_Game(game) { World::World(Game* game) : m_Game(game) {
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 {
std::int16_t chunkX = x / Chunk::ChunkWidth; std::int16_t chunkX = x / Chunk::ChunkWidth;
std::int16_t chunkY = y / Chunk::ChunkHeight; std::int16_t chunkY = y / Chunk::ChunkHeight;
std::uint16_t subChunkX = x % Chunk::ChunkWidth; std::uint16_t subChunkX = std::abs(x % Chunk::ChunkWidth);
std::uint16_t subChunkY = y % Chunk::ChunkHeight; std::uint16_t subChunkY = std::abs(y % Chunk::ChunkHeight);
auto chunkIt = m_Chunks.find({ chunkX, chunkY }); auto chunkIt = m_Chunks.find({ chunkX, chunkY });
if (chunkIt == m_Chunks.end()) if (chunkIt == m_Chunks.end())
@@ -111,8 +111,7 @@ void World::tick(std::uint64_t delta) {
void World::spawnMobAt(MobID id, MobType type, std::uint8_t level, PlayerID sender, float x, float y, Direction dir) { void World::spawnMobAt(MobID id, MobType type, std::uint8_t level, PlayerID sender, float x, float y, Direction dir) {
MobPtr mob = MobFactory::createMob(id, type, level, sender); MobPtr mob = MobFactory::createMob(id, type, level, sender);
mob->setX(x); mob->setCenter({ x, y });
mob->setY(y);
mob->setDirection(dir); mob->setDirection(dir);
m_Mobs.push_back(mob); m_Mobs.push_back(mob);
} }
@@ -123,49 +122,177 @@ TowerPtr World::placeTowerAt(TowerID id, TowerType type, std::int32_t x, std::in
return tower; return tower;
} }
TowerPtr World::removeTower(TowerID towerId) {
auto it = std::find_if(m_Towers.begin(), m_Towers.end(), [towerId](TowerPtr tower) { return tower->getID() == towerId;});
if (it == m_Towers.end()) return nullptr;
TowerPtr tower = *it;
m_Towers.erase(it);
return tower;
}
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);
} }
} }
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) { void World::moveMobs(std::uint64_t delta) {
for (MobPtr mob : m_Mobs) { for (MobPtr mob : m_Mobs) {
TilePtr tile = getTile(mob->getX(), mob->getY()); TilePtr tile = getTile(mob->getCenter().getX(), mob->getCenter().getY());
if (tile != nullptr && tile->getType() == TileType::Walk) { if (tile != nullptr && tile->getType() == TileType::Walk) {
WalkableTile* walkTile = dynamic_cast<WalkableTile*>(tile.get()); WalkableTilePtr walkTile = std::static_pointer_cast<WalkableTile>(tile);
mob->setDirection(walkTile->direction); changeMobDirection(mob, walkTile);
} }
float mobWalkSpeed = mob->getStats()->getMovementSpeed(); if (mob->hasReachedEnemyCastle()) continue;
float walkAmount = mobWalkSpeed * ((float)delta / 1000.0f); moveMob(mob, delta);
if (mob->hasEffect(EffectType::Slowness)) TeamColor mobTeam = m_Game->getPlayerById(mob->getSender()).getTeamColor();
walkAmount *= 0.70;
switch (mob->getDirection()) { const TeamCastle* enemyCastle = nullptr;
case Direction::NegativeX: {
mob->setX(mob->getX() - walkAmount); if (mobTeam == TeamColor::Red) {
break; enemyCastle = &getBlueTeam().getCastle();
} } else if (mobTeam == TeamColor::Blue) {
case Direction::PositiveX: { enemyCastle = &getRedTeam().getCastle();
mob->setX(mob->getX() + walkAmount);
break;
}
case Direction::NegativeY: {
mob->setY(mob->getY() - walkAmount);
break;
}
case Direction::PositiveY: {
mob->setY(mob->getY() + walkAmount);
break;
} }
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;
}
}
}
const Color* World::getTileColor(TilePtr tile) const { const Color* World::getTileColor(TilePtr tile) const {
switch (tile->getType()) { switch (tile->getType()) {
case TileType::Tower: { case TileType::Tower: {
@@ -245,16 +372,16 @@ 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->isDead()) { if (mob->isDead()) {
mob->OnDeath(this); if (mob->OnDeath(this)) {
//reward players
Player& sender = m_Game->getPlayerById(mob->getSender());
sender.addExp(mob->getStats()->getExpReward());
//reward players Player& killer = m_Game->getPlayerById(mob->getLastDamageTower()->getBuilder());
Player& sender = m_Game->getPlayerById(mob->getSender()); killer.addGold(mob->getStats()->getMoneyCost());
sender.addExp(mob->getStats()->getExpReward());
Player& killer = m_Game->getPlayerById(mob->getLastDamageTower()->getBuilder()); m_Mobs.erase(m_Mobs.begin() + i);
killer.addGold(mob->getStats()->getMoneyCost()); }
m_Mobs.erase(m_Mobs.begin() + i);
} }
} }
} }
@@ -262,13 +389,13 @@ void World::cleanDeadMobs() {
TowerPtr World::getTower(const glm::vec2& position) const { TowerPtr World::getTower(const glm::vec2& position) const {
for (TowerPtr tower : m_Towers) { for (TowerPtr tower : m_Towers) {
if (tower->getSize() == TowerSize::Big) { if (tower->getSize() == TowerSize::Big) {
if (tower->getX() - 2 <= static_cast<std::int32_t>(position.x) && tower->getX() + 2 >= static_cast<std::int32_t>(position.x) && if (tower->getCenterX() - 2.5f < position.x && tower->getCenterX() + 2.5f > position.x &&
tower->getY() - 2 <= static_cast<std::int32_t>(position.y) && tower->getY() + 2 >= static_cast<std::int32_t>(position.y)) { tower->getCenterY() - 2.5f < position.y && tower->getCenterY() + 2.5f > position.y) {
return tower; return tower;
} }
} else { } else { // little tower
if (tower->getX() - 1 <= static_cast<std::int32_t>(position.x) && tower->getX() + 1 >= static_cast<std::int32_t>(position.x) && if (tower->getCenterX() - 1.5f < position.x && tower->getCenterX() + 1.5f > position.x &&
tower->getY() - 1 <= static_cast<std::int32_t>(position.y) && tower->getY() + 1 >= static_cast<std::int32_t>(position.y)) { tower->getCenterY() - 1.5f < position.y && tower->getCenterY() + 1.5f > position.y) {
return tower; return tower;
} }
} }
@@ -278,16 +405,41 @@ TowerPtr World::getTower(const glm::vec2& position) const {
TowerPtr World::getTowerById(TowerID towerID) { TowerPtr World::getTowerById(TowerID towerID) {
auto it = std::find_if(m_Towers.begin(), m_Towers.end(), [towerID](TowerPtr tower) { return tower->getID() == towerID;}); auto it = std::find_if(m_Towers.begin(), m_Towers.end(), [towerID](TowerPtr tower) { return tower->getID() == towerID;});
if(it == m_Towers.end()) return nullptr; if (it == m_Towers.end()) return nullptr;
return *it; return *it;
} }
void World::OnArrowShot(MobPtr target, Tower* shooter) { void World::OnArcherTowerShot(MobPtr target, ArcherTower* shooter) {
bool explosiveArrows = shooter->getLevel().getPath() == TowerPath::Bottom; bool fireArrows = shooter->getLevel().getPath() == TowerPath::Bottom;
bool explosiveArrows = shooter->getLevel().getLevel() == 4 && fireArrows;
notifyListeners(&WorldListener::OnArrowShot, target, fireArrows, shooter);
if (explosiveArrows) { if (explosiveArrows) {
// aoe damage notifyListeners(&WorldListener::OnExplosion, utils::shape::Circle{ target->getCenterX(), target->getCenterY(), ArcherTower::ExplosionRadius }, shooter->getStats()->getDamage(), shooter);
} else { }
target->damage(shooter->getStats()->getDamage(), shooter); }
void World::OnArrowShot(MobPtr target, bool fireArrow, Tower* shooter) {
notifyListeners(&WorldListener::OnMobDamage, target, shooter->getStats()->getDamage(), shooter);
if (fireArrow) {
target->addEffect(EffectType::Fire, ArcherTower::FireDurationSec, shooter);
}
}
void World::OnExplosion(utils::shape::Circle explosion, float centerDamage, Tower* shooter) {
for (MobPtr mob : m_Mobs) {
if (mob->isAlive() && mob->collidesWith(explosion)) {
// linear distance damage reduction
float explosionDamage = mob->distance(explosion) / explosion.getRadius() * centerDamage;
notifyListeners(&WorldListener::OnMobDamage, mob, explosionDamage, shooter);
}
}
}
void World::OnMobDamage(MobPtr target, float damage, Tower* source) {
target->damage(damage, source);
if (target->isDead()) {
notifyListeners(&WorldListener::OnMobDead, target);
} }
} }

View File

@@ -49,7 +49,7 @@ void Client::render() {
m_Game.renderWorld(); m_Game.renderWorld();
} }
void Client::sendMobs(const std::vector<protocol::MobSend>& mobSends){ void Client::sendMobs(const std::vector<protocol::MobSend>& mobSends) {
protocol::SendMobsPacket packet(mobSends); protocol::SendMobsPacket packet(mobSends);
m_Connexion.sendPacket(&packet); m_Connexion.sendPacket(&packet);
} }
@@ -59,10 +59,15 @@ void Client::placeTower(game::TowerType type, const glm::vec2& position) {
m_Connexion.sendPacket(&packet); m_Connexion.sendPacket(&packet);
} }
void Client::upgradeTower(game::TowerID tower, game::TowerLevel level){ void Client::upgradeTower(game::TowerID tower, game::TowerLevel level) {
protocol::UpgradeTowerPacket packet(tower, level); protocol::UpgradeTowerPacket packet(tower, level);
m_Connexion.sendPacket(&packet); m_Connexion.sendPacket(&packet);
} }
void Client::removeTower(game::TowerID tower) {
protocol::RemoveTowerPacket packet(tower);
m_Connexion.sendPacket(&packet);
}
} // namespace client } // namespace client
} // namespace td } // namespace td

View File

@@ -1,10 +1,7 @@
#include "game/client/ClientGame.h" #include "game/client/ClientGame.h"
#include "protocol/PacketDispatcher.h" #include "protocol/PacketDispatcher.h"
//#include "game/Team.h"
#include "game/client/Client.h" #include "game/client/Client.h"
#include <iostream>
namespace td { namespace td {
namespace client { namespace client {
@@ -21,7 +18,6 @@ m_WorldRenderer(&m_WorldClient, this) {
GetDispatcher()->RegisterHandler(protocol::PacketType::UpdateMoney, this); GetDispatcher()->RegisterHandler(protocol::PacketType::UpdateMoney, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::Disconnect, this); GetDispatcher()->RegisterHandler(protocol::PacketType::Disconnect, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::WorldData, this); GetDispatcher()->RegisterHandler(protocol::PacketType::WorldData, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::WorldAddTower, this);
} }
ClientGame::~ClientGame() { ClientGame::~ClientGame() {
@@ -103,7 +99,7 @@ void ClientGame::HandlePacket(const protocol::WorldDataPacket* packet) {
m_WorldRenderer.loadModels(); m_WorldRenderer.loadModels();
// set cam pos to player spawn // set cam pos to player spawn
const game::Spawn& spawn = m_World->getTeam(m_Player->getTeamColor()).getSpawn(); const game::Spawn& spawn = m_World->getTeam(m_Player->getTeamColor()).getSpawn();
m_WorldRenderer.setCamPos(spawn.x + 0.5, spawn.y + 0.5); m_WorldRenderer.setCamPos(spawn.getCenterX(), spawn.getCenterY());
} }
void ClientGame::renderWorld() { void ClientGame::renderWorld() {
@@ -112,9 +108,5 @@ void ClientGame::renderWorld() {
} }
} }
void ClientGame::HandlePacket(const protocol::WorldAddTowerPacket* packet) {
m_WorldRenderer.addTower(m_WorldClient.placeTowerAt(packet->getTowerID(), packet->getTowerType(), packet->getTowerX(), packet->getTowerY(), packet->getBuilder()));
}
} // namespace client } // namespace client
} // namespace td } // namespace td

View File

@@ -7,10 +7,12 @@ namespace td {
namespace client { namespace client {
WorldClient::WorldClient(ClientGame* game) : game::World(game), protocol::PacketHandler(game->GetDispatcher()), m_Game(game) { WorldClient::WorldClient(ClientGame* game) : game::World(game), protocol::PacketHandler(game->GetDispatcher()), m_Game(game) {
GetDispatcher()->RegisterHandler(protocol::PacketType::WorldAddTower, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::WorldBeginData, this); GetDispatcher()->RegisterHandler(protocol::PacketType::WorldBeginData, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::WorldData, this); GetDispatcher()->RegisterHandler(protocol::PacketType::WorldData, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::SpawnMob, this); GetDispatcher()->RegisterHandler(protocol::PacketType::SpawnMob, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::UpgradeTower, this); GetDispatcher()->RegisterHandler(protocol::PacketType::UpgradeTower, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::RemoveTower, this);
} }
void WorldClient::HandlePacket(const protocol::WorldBeginDataPacket* packet) { void WorldClient::HandlePacket(const protocol::WorldBeginDataPacket* packet) {
@@ -28,12 +30,22 @@ void WorldClient::HandlePacket(const protocol::SpawnMobPacket* packet) {
void WorldClient::HandlePacket(const protocol::UpgradeTowerPacket* packet) { void WorldClient::HandlePacket(const protocol::UpgradeTowerPacket* packet) {
game::TowerPtr tower = getTowerById(packet->getTowerID()); game::TowerPtr tower = getTowerById(packet->getTowerID());
if(tower == nullptr) return; // this should not happen but who knows ? if (tower == nullptr) return; // this should not happen but who knows ?
tower->upgrade(packet->getTowerLevel().getLevel(), packet->getTowerLevel().getPath()); tower->upgrade(packet->getTowerLevel().getLevel(), packet->getTowerLevel().getPath());
} }
void WorldClient::OnArrowShot(game::MobPtr target, game::Tower* tower) { void WorldClient::HandlePacket(const protocol::WorldAddTowerPacket* packet) {
World::OnArrowShot(target, tower); game::TowerPtr newTower = placeTowerAt(packet->getTowerID(), packet->getTowerType(), packet->getTowerX(), packet->getTowerY(), packet->getBuilder());
notifyListeners(&WorldListener::OnTowerAdd, newTower);
}
void WorldClient::HandlePacket(const protocol::RemoveTowerPacket* packet) {
game::TowerPtr tower = removeTower(packet->getTowerID());
if (tower != nullptr) {
notifyListeners(&WorldListener::OnTowerRemove, tower);
}
} }
} // namespace client } // namespace client

View File

@@ -29,12 +29,12 @@ void Server::startThread() {
} }
} }
}); });
} }
void Server::stopThread(){ void Server::stopThread() {
m_ServerRunning = false; m_ServerRunning = false;
if(m_Thread.joinable()) if (m_Thread.joinable())
m_Thread.join(); m_Thread.join();
} }
@@ -55,7 +55,7 @@ bool Server::start(std::uint16_t port) {
} }
void Server::stop() { void Server::stop() {
if(!m_ServerRunning) if (!m_ServerRunning)
return; return;
stopThread(); stopThread();

View File

@@ -41,6 +41,7 @@ void ServerConnexion::registerHandlers() {
GetDispatcher()->RegisterHandler(protocol::PacketType::PlaceTower, this); GetDispatcher()->RegisterHandler(protocol::PacketType::PlaceTower, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::SendMobs, this); GetDispatcher()->RegisterHandler(protocol::PacketType::SendMobs, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::UpgradeTower, this); GetDispatcher()->RegisterHandler(protocol::PacketType::UpgradeTower, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::RemoveTower, this);
} }
bool ServerConnexion::updateSocket() { bool ServerConnexion::updateSocket() {
@@ -159,6 +160,8 @@ 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);
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);
} }
@@ -168,12 +171,18 @@ void ServerConnexion::HandlePacket(const protocol::SendMobsPacket* packet) {
//TODO: verify the packet //TODO: verify the packet
for(protocol::MobSend mobSend : mobSent){ for (protocol::MobSend mobSend : mobSent) {
m_Server->getGame().getServerWorld()->spawnMobs(mobSend.mobType, mobSend.mobLevel, m_ID, mobSend.mobCount); m_Server->getGame().getServerWorld()->spawnMobs(mobSend.mobType, mobSend.mobLevel, m_ID, mobSend.mobCount);
} }
} }
void ServerConnexion::HandlePacket(const protocol::UpgradeTowerPacket* packet){ void ServerConnexion::HandlePacket(const protocol::UpgradeTowerPacket* packet) {
//TODO: verify the packet
m_Server->broadcastPacket(packet);
}
void ServerConnexion::HandlePacket(const protocol::RemoveTowerPacket* packet) {
//TODO: verify the packet //TODO: verify the packet
m_Server->broadcastPacket(packet); m_Server->broadcastPacket(packet);

View File

@@ -9,7 +9,7 @@ ServerGame::ServerGame(server::Server* server) : game::Game(&m_ServerWorld), m_S
} }
void ServerGame::tick(std::uint64_t delta) { void ServerGame::tick(std::uint64_t delta) {
if(m_GameState == game::GameState::Game){ if (m_GameState == game::GameState::Game) {
Game::tick(delta); Game::tick(delta);
updatePlayerStats(); updatePlayerStats();
} }
@@ -27,16 +27,16 @@ void ServerGame::startGame() {
m_GameState = game::GameState::Game; m_GameState = game::GameState::Game;
} }
void ServerGame::updatePlayerStats(){ void ServerGame::updatePlayerStats() {
m_GoldMineTimer.update(); m_GoldMineTimer.update();
for (auto& pair : m_Server->getPlayers()) { for (auto& pair : m_Server->getPlayers()) {
game::Player& player = pair.second; game::Player& player = pair.second;
if(player.hasGoldChanged()){ if (player.hasGoldChanged()) {
protocol::UpdateMoneyPacket packet(player.getGold()); protocol::UpdateMoneyPacket packet(player.getGold());
m_Server->getConnexions()[player.getID()].sendPacket(&packet); m_Server->getConnexions()[player.getID()].sendPacket(&packet);
player.updateGold(); player.updateGold();
} }
if(player.hasExpChanged()){ if (player.hasExpChanged()) {
protocol::UpdateExpPacket packet(player.getExp()); protocol::UpdateExpPacket packet(player.getExp());
m_Server->getConnexions()[player.getID()].sendPacket(&packet); m_Server->getConnexions()[player.getID()].sendPacket(&packet);
player.updateExp(); player.updateExp();

View File

@@ -22,21 +22,27 @@ void ServerWorld::spawnMobs(game::MobType type, std::uint8_t level, game::Player
enemyMobSpawn = &getTeam(game::TeamColor::Red).getSpawn(); enemyMobSpawn = &getTeam(game::TeamColor::Red).getSpawn();
} }
std::int32_t spawnCenterX = enemyMobSpawn->x; float spawnWidth = enemyMobSpawn->getWidth();
std::int32_t spawnCenterY = enemyMobSpawn->y; float spawnHeight = enemyMobSpawn->getHeight();
std::int32_t minSpawnY = spawnCenterY - 2; float spawnCenterX = enemyMobSpawn->getCenterX();
std::int32_t maxSpawnY = spawnCenterY + 2; float spawnCenterY = enemyMobSpawn->getCenterY();
std::int32_t minSpawnX = spawnCenterX - 2; auto mobStats = getMobStats(type, level);
std::int32_t maxSpawnX = spawnCenterX + 2; auto mobSize = mobStats->getSize();
float minSpawnX = spawnCenterX - spawnWidth / 2.0f + mobSize.x / 2.0f;
float maxSpawnX = spawnCenterX + spawnWidth / 2.0f - mobSize.x / 2.0f;
float minSpawnY = spawnCenterY - spawnHeight / 2.0f + mobSize.y / 2.0f;
float maxSpawnY = spawnCenterY + spawnHeight / 2.0f - mobSize.y / 2.0f;
float mobX = utils::getRandomReal<float>(minSpawnX, maxSpawnX); float mobX = utils::getRandomReal<float>(minSpawnX, maxSpawnX);
float mobY = utils::getRandomReal<float>(minSpawnY, maxSpawnY); float mobY = utils::getRandomReal<float>(minSpawnY, maxSpawnY);
spawnMobAt(m_CurrentMobID, type, level, sender, mobX, mobY, enemyMobSpawn->direction); spawnMobAt(m_CurrentMobID, type, level, sender, mobX, mobY, enemyMobSpawn->getDirection());
protocol::SpawnMobPacket packet(m_CurrentMobID, type, level, sender, mobX, mobY, enemyMobSpawn->direction); protocol::SpawnMobPacket packet(m_CurrentMobID, type, level, sender, mobX, mobY, enemyMobSpawn->getDirection());
m_Server->broadcastPacket(&packet); m_Server->broadcastPacket(&packet);
m_CurrentMobID++; m_CurrentMobID++;
@@ -49,9 +55,5 @@ game::TowerPtr ServerWorld::placeTowerAt(game::TowerType type, std::int32_t x, s
return tower; return tower;
} }
void ServerWorld::OnArrowShot(game::MobPtr target, game::Tower* shooter) {
World::OnArrowShot(target, shooter);
}
} // namespace server } // namespace server
} // namespace td } // namespace td

84
src/misc/Shapes.cpp Normal file
View File

@@ -0,0 +1,84 @@
#include "misc/Shapes.h"
#include <algorithm>
#include <cmath>
namespace td {
namespace utils {
namespace shape {
float Point::distance(const Point& point) const {
return std::sqrt(distanceSquared(point));
}
float Point::distanceSquared(const Point& point) const {
return (m_X - point.getX()) * (m_X - point.getX()) + (m_Y - point.getY()) * (m_Y - point.getY());
}
bool Rectangle::collidesWith(const Point& point) const {
return point.getX() > getTopLeft().getX() && point.getX() < getBottomRight().getX() &&
point.getY() > getTopLeft().getY() && point.getY() < getBottomRight().getY();
}
bool Rectangle::collidesWith(const Rectangle& rect) const {
Point point1{ rect.getTopLeft().getX(), rect.getTopLeft().getY() };
Point point2{ rect.getTopLeft().getX(), rect.getBottomRight().getY() };
Point point3{ rect.getBottomRight().getX(), rect.getTopLeft().getY() };
Point point4{ rect.getBottomRight().getX(), rect.getBottomRight().getY() };
if (collidesWith(point1)) return true;
if (collidesWith(point2)) return true;
if (collidesWith(point3)) return true;
if (collidesWith(point4)) return true;
return false;
}
bool Rectangle::collidesWith(const Circle& circle) const {
return circle.collidesWith(*this);
}
float Rectangle::distance(const Circle& circle) const {
return circle.distance(*this);
}
float Rectangle::distanceSquared(const Circle& circle) const {
return circle.distanceSquared(*this);
}
bool Circle::collidesWith(const Point& point) const {
return m_Radius * m_Radius > m_Center.distanceSquared(point);
}
bool Circle::collidesWith(const Rectangle& rect) const {
float distanceSquared_ = distanceSquared(rect);
return distanceSquared_ < m_Radius* m_Radius;
}
bool Circle::collidesWith(const Circle& circle) const {
return m_Radius + circle.getRadius() > m_Center.distanceSquared(circle.getCenter());
}
float Circle::distance(const Rectangle& rect) const {
return std::sqrt(distanceSquared(rect));
}
float Circle::distanceSquared(const Rectangle& rect) const {
float closestX = std::clamp(m_Center.getX(), rect.getTopLeft().getX(), rect.getBottomRight().getX());
float closestY = std::clamp(m_Center.getY(), rect.getTopLeft().getY(), rect.getBottomRight().getY());
float distanceX = m_Center.getX() - closestX;
float distanceY = m_Center.getY() - closestY;
return (distanceX * distanceX) + (distanceY * distanceY);
}
} // namespace shape
} // namespace utils
} // namespace td

View File

@@ -55,7 +55,7 @@ void CooldownTimer::reset() {
m_Cooldown = 0; // let the timer active once at the beginning m_Cooldown = 0; // let the timer active once at the beginning
} }
void CooldownTimer::applyCooldown(){ void CooldownTimer::applyCooldown() {
m_Cooldown = m_CooldownTime; m_Cooldown = m_CooldownTime;
} }

View File

@@ -6,7 +6,7 @@ namespace td {
namespace protocol { namespace protocol {
namespace PacketFactory { namespace PacketFactory {
using PacketCreator = std::function<PacketPtr ()>; using PacketCreator = std::function<PacketPtr()>;
static std::map<PacketType, PacketCreator> packets = { static std::map<PacketType, PacketCreator> packets = {
{PacketType::PlayerLogin, []() -> PacketPtr {return std::make_unique<PlayerLoginPacket>();} }, {PacketType::PlayerLogin, []() -> PacketPtr {return std::make_unique<PlayerLoginPacket>();} },
@@ -28,7 +28,7 @@ static std::map<PacketType, PacketCreator> packets = {
{PacketType::SpawnMob, []() -> PacketPtr {return std::make_unique<SpawnMobPacket>(); } }, {PacketType::SpawnMob, []() -> PacketPtr {return std::make_unique<SpawnMobPacket>(); } },
{PacketType::PlaceTower, []() -> PacketPtr {return std::make_unique<PlaceTowerPacket>(); } }, {PacketType::PlaceTower, []() -> PacketPtr {return std::make_unique<PlaceTowerPacket>(); } },
{PacketType::WorldAddTower, []() -> PacketPtr {return std::make_unique<WorldAddTowerPacket>(); } }, {PacketType::WorldAddTower, []() -> PacketPtr {return std::make_unique<WorldAddTowerPacket>(); } },
{PacketType::WorldRemoveTower, []() -> PacketPtr {return std::make_unique<WorldRemoveTowerPacket>(); } }, {PacketType::RemoveTower, []() -> PacketPtr {return std::make_unique<RemoveTowerPacket>(); } },
{PacketType::SendMobs, []() -> PacketPtr {return std::make_unique<SendMobsPacket>(); } }, {PacketType::SendMobs, []() -> PacketPtr {return std::make_unique<SendMobsPacket>(); } },
{PacketType::UpgradeTower, []() -> PacketPtr {return std::make_unique<UpgradeTowerPacket>(); } }, {PacketType::UpgradeTower, []() -> PacketPtr {return std::make_unique<UpgradeTowerPacket>(); } },
}; };

View File

@@ -485,20 +485,20 @@ void WorldAddTowerPacket::Deserialize(DataBuffer& data) {
data >> m_TowerID >> m_TowerX >> m_TowerY >> m_TowerType >> m_Builder; data >> m_TowerID >> m_TowerX >> m_TowerY >> m_TowerType >> m_Builder;
} }
DataBuffer WorldRemoveTowerPacket::Serialize() const { DataBuffer RemoveTowerPacket::Serialize() const {
DataBuffer data; DataBuffer data;
data << getID() << m_TowerID; data << getID() << m_TowerID;
return data; return data;
} }
void WorldRemoveTowerPacket::Deserialize(DataBuffer& data) { void RemoveTowerPacket::Deserialize(DataBuffer& data) {
data >> m_TowerID; data >> m_TowerID;
} }
DataBuffer SendMobsPacket::Serialize() const { DataBuffer SendMobsPacket::Serialize() const {
DataBuffer data; DataBuffer data;
data << getID() << static_cast<std::uint8_t>(m_MobSends.size()); data << getID() << static_cast<std::uint8_t>(m_MobSends.size());
for(const MobSend& mobSend : m_MobSends){ for (const MobSend& mobSend : m_MobSends) {
data << mobSend; data << mobSend;
} }
return data; return data;
@@ -508,7 +508,7 @@ void SendMobsPacket::Deserialize(DataBuffer& data) {
std::uint8_t mobSendCount; std::uint8_t mobSendCount;
data >> mobSendCount; data >> mobSendCount;
protocol::MobSend mobSend; protocol::MobSend mobSend;
for(int i = 0; i < mobSendCount; i++){ for (int i = 0; i < mobSendCount; i++) {
data >> mobSend; data >> mobSend;
m_MobSends.push_back(mobSend); m_MobSends.push_back(mobSend);
} }
@@ -543,7 +543,7 @@ REGISTER_DISPATCH_CLASS(ServerTpsPacket);
REGISTER_DISPATCH_CLASS(SpawnMobPacket); REGISTER_DISPATCH_CLASS(SpawnMobPacket);
REGISTER_DISPATCH_CLASS(PlaceTowerPacket); REGISTER_DISPATCH_CLASS(PlaceTowerPacket);
REGISTER_DISPATCH_CLASS(WorldAddTowerPacket); REGISTER_DISPATCH_CLASS(WorldAddTowerPacket);
REGISTER_DISPATCH_CLASS(WorldRemoveTowerPacket); REGISTER_DISPATCH_CLASS(RemoveTowerPacket);
REGISTER_DISPATCH_CLASS(SendMobsPacket); REGISTER_DISPATCH_CLASS(SendMobsPacket);
REGISTER_DISPATCH_CLASS(UpgradeTowerPacket); REGISTER_DISPATCH_CLASS(UpgradeTowerPacket);

View File

@@ -43,9 +43,9 @@ void Renderer::initShader() {
} }
bool Renderer::init() { bool Renderer::init() {
#ifndef ANDROID #ifndef ANDROID
glbinding::Binding::initialize(); glbinding::Binding::initialize();
#endif #endif
glEnable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND); glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

View File

@@ -5,46 +5,43 @@ namespace td {
namespace render { namespace render {
void VertexCache::addData(std::uint64_t index, std::vector<float> positions, std::vector<float> colors) { void VertexCache::addData(std::uint64_t index, std::vector<float> positions, std::vector<float> colors) {
ElementsIndex positionsIndexes; m_Indexes.insert({ index, {positions, colors} });
positionsIndexes.first = m_Positions.end(); m_VertexCount += colors.size(); // one color per vertex
m_Positions.insert(m_Positions.end(), positions.begin(), positions.end());
positionsIndexes.second = m_Positions.end() - 1;
ElementsIndex colorsIndexes;
colorsIndexes.first = m_Colors.end();
m_Colors.insert(m_Colors.end(), colors.begin(), colors.end());
colorsIndexes.second = m_Colors.end() - 1;
m_Indexes.insert({ index, {positionsIndexes, colorsIndexes} });
} }
void VertexCache::removeData(std::uint64_t index) { void VertexCache::removeData(std::uint64_t index) {
auto it = m_Indexes.find(index); auto it = m_Indexes.find(index);
if (it != m_Indexes.end()) { if (it != m_Indexes.end()) {
DataIndex indexes = it->second;
ElementsIndex positionsIndexes = indexes.first;
ElementsIndex colorsIndexes = indexes.second;
m_Positions.erase(positionsIndexes.first, positionsIndexes.second);
m_Colors.erase(colorsIndexes.first, colorsIndexes.second);
m_Indexes.erase(it); m_Indexes.erase(it);
m_VertexCount -= it->second.color.size(); // one color per vertex
} }
} }
void VertexCache::clear() { void VertexCache::clear() {
m_Positions.clear();
m_Colors.clear();
m_Indexes.clear(); m_Indexes.clear();
m_VertexCount = 0;
} }
void VertexCache::updateVertexArray() { void VertexCache::updateVertexArray() {
m_VertexArray = std::make_unique<GL::VertexArray>(m_Colors.size()); // one color per vertex m_VertexArray = std::make_unique<GL::VertexArray>(m_VertexCount); // one color per vertex
GL::VertexBuffer positionsBuffer(m_Positions, 2); Vector positions;
positions.reserve(m_VertexCount * 2);
Vector colors;
colors.reserve(m_VertexCount);
for (auto it = m_Indexes.begin(); it != m_Indexes.end(); it++) {
const DataIndex& data = it->second;
positions.insert(positions.end(), data.position.begin(), data.position.end());
colors.insert(colors.end(), data.color.begin(), data.color.end());
}
GL::VertexBuffer positionsBuffer(positions, 2);
positionsBuffer.addVertexAttribPointer(0, 2, 0); positionsBuffer.addVertexAttribPointer(0, 2, 0);
GL::VertexBuffer colorsBuffer(m_Colors, 1); GL::VertexBuffer colorsBuffer(colors, 1);
colorsBuffer.addVertexAttribPointer(1, 1, 0); colorsBuffer.addVertexAttribPointer(1, 1, 0);
m_VertexArray->bind(); m_VertexArray->bind();

View File

@@ -37,6 +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);
} }
void WorldRenderer::updateCursorPos() { void WorldRenderer::updateCursorPos() {
@@ -64,6 +65,18 @@ void WorldRenderer::update() {
m_PopupOpened = false; m_PopupOpened = false;
} }
} }
if (ImGui::IsMouseDoubleClicked(1)) removeTower();
}
void WorldRenderer::removeTower() {
glm::vec2 cursorPos = getCursorWorldPos();
game::TowerPtr clickedTower = m_World->getTower(cursorPos);
if (clickedTower != nullptr) {
m_Client->getClient()->removeTower(clickedTower->getID());
}
} }
void WorldRenderer::renderWorld() const { void WorldRenderer::renderWorld() const {
@@ -74,7 +87,7 @@ void WorldRenderer::renderMobs() const {
for (game::MobPtr mob : m_World->getMobList()) { for (game::MobPtr mob : m_World->getMobList()) {
Renderer::Model model; Renderer::Model model;
model.vao = m_MobVao.get(); model.vao = m_MobVao.get();
model.positon = { mob->getX(), mob->getY() }; model.positon = { mob->getCenterX(), mob->getCenterY() };
m_Renderer->renderModel(model); m_Renderer->renderModel(model);
} }
} }
@@ -85,7 +98,7 @@ void WorldRenderer::renderTowers() const {
} }
void WorldRenderer::renderTileSelect() const { void WorldRenderer::renderTileSelect() const {
if(ImGui::IsAnyItemHovered()) return; if (ImGui::IsAnyItemHovered()) return;
Renderer::Model tileSelectModel; Renderer::Model tileSelectModel;
tileSelectModel.vao = m_SelectTileVao.get(); tileSelectModel.vao = m_SelectTileVao.get();
@@ -180,8 +193,8 @@ void WorldRenderer::renderTowerUpgradePopup() {
bool alreadyUpgraded = currentLevel <= towerLevel; bool alreadyUpgraded = currentLevel <= towerLevel;
bool canUpgrade = (towerLevel + 1) == currentLevel; bool canUpgrade = (towerLevel + 1) == currentLevel;
if(canUpgrade && towerPath != game::TowerPath::Base){ if (canUpgrade && towerPath != game::TowerPath::Base) {
if(currentPath != towerPath){ if (currentPath != towerPath) {
canUpgrade = false; canUpgrade = false;
} }
} }
@@ -199,7 +212,7 @@ void WorldRenderer::renderTowerUpgradePopup() {
ImGui::EndDisabled(); ImGui::EndDisabled();
} else if (canUpgrade) { } else if (canUpgrade) {
if (ImGui::Button("Upgrade", ImVec2(100, 100))) { if (ImGui::Button("Upgrade", ImVec2(100, 100))) {
m_Client->getClient()->upgradeTower(tower->getID(), {currentLevel, currentPath}); m_Client->getClient()->upgradeTower(tower->getID(), { currentLevel, currentPath });
} }
} else { } else {
ImGui::BeginDisabled(); ImGui::BeginDisabled();
@@ -226,8 +239,8 @@ void WorldRenderer::detectClick() {
} }
void WorldRenderer::renderMobTooltip() const { void WorldRenderer::renderMobTooltip() const {
if(ImGui::IsAnyItemHovered()) return; if (ImGui::IsAnyItemHovered()) return;
detectMobHovering(); detectMobHovering();
m_MobTooltip->render(); m_MobTooltip->render();
} }
@@ -235,25 +248,21 @@ void WorldRenderer::renderMobTooltip() const {
void WorldRenderer::detectMobHovering() const { void WorldRenderer::detectMobHovering() const {
glm::vec2 cursorWorldPos = getCursorWorldPos(); glm::vec2 cursorWorldPos = getCursorWorldPos();
for (game::MobPtr mob : m_World->getMobList()) { for (game::MobPtr mob : m_World->getMobList()) {
// mob size is currently 1x1 for all mobs if (mob->collidesWith({ cursorWorldPos.x, cursorWorldPos.y })) {
float mobCenterX = mob->getX(); m_MobTooltip->setMob(mob.get());
float mobCenterY = mob->getY();
if (cursorWorldPos.x > mobCenterX - 0.5f && cursorWorldPos.x < mobCenterX + 0.5f
&& cursorWorldPos.y > mobCenterY - 0.5f && cursorWorldPos.y < mobCenterY + 0.5f) {
m_MobTooltip->setMob(mob.get());
return; return;
} }
} }
m_MobTooltip->setMob(nullptr); m_MobTooltip->setMob(nullptr);
} }
void WorldRenderer::addTower(game::TowerPtr tower) { void WorldRenderer::OnTowerAdd(game::TowerPtr tower) {
const WorldLoader::RenderData& renderData = WorldLoader::loadTowerModel(tower); WorldLoader::RenderData renderData = WorldLoader::loadTowerModel(tower);
m_TowersCache.addData(tower->getID(), renderData.positions, renderData.colors); m_TowersCache.addData(tower->getID(), renderData.positions, renderData.colors);
m_TowersCache.updateVertexArray(); m_TowersCache.updateVertexArray();
} }
void WorldRenderer::removeTower(game::TowerPtr tower) { void WorldRenderer::OnTowerRemove(game::TowerPtr tower) {
m_TowersCache.removeData(tower->getID()); m_TowersCache.removeData(tower->getID());
m_TowersCache.updateVertexArray(); m_TowersCache.updateVertexArray();
} }

View File

@@ -8,7 +8,7 @@
namespace td { namespace td {
namespace gui { namespace gui {
FrameMenu::FrameMenu(client::Client* client) : GuiWidget(client), m_VSync(true), m_IsometricView(true), m_ShowDemoWindow(false){ FrameMenu::FrameMenu(client::Client* client) : GuiWidget(client), m_VSync(true), m_IsometricView(true), m_ShowDemoWindow(false) {
} }
@@ -24,7 +24,7 @@ void FrameMenu::render() {
ImGui::Checkbox("Demo Window", &m_ShowDemoWindow); ImGui::Checkbox("Demo Window", &m_ShowDemoWindow);
ImGui::End(); ImGui::End();
if(m_ShowDemoWindow) if (m_ShowDemoWindow)
ImGui::ShowDemoWindow(&m_ShowDemoWindow); ImGui::ShowDemoWindow(&m_ShowDemoWindow);
} }

View File

@@ -13,7 +13,7 @@ GameMenu::GameMenu(client::Client* client) : GuiWidget(client), m_SummonMenu(std
} }
void GameMenu::render(){ void GameMenu::render() {
if (getClient()->getGame().getGameState() == td::game::GameState::Lobby) { if (getClient()->getGame().getGameState() == td::game::GameState::Lobby) {
ImGui::Begin("Lobby"); ImGui::Begin("Lobby");

View File

@@ -12,8 +12,8 @@ MainMenu::MainMenu(client::Client* client) : GuiWidget(client), m_ConnectPort(25
m_ConnectAddress.reserve(256); m_ConnectAddress.reserve(256);
} }
MainMenu::~MainMenu(){ MainMenu::~MainMenu() {
if(m_Server != nullptr) if (m_Server != nullptr)
m_Server->stop(); m_Server->stop();
} }
@@ -28,7 +28,7 @@ void MainMenu::render() {
if (ImGui::Button("Options")) { if (ImGui::Button("Options")) {
// TODO: add settings // TODO: add settings
} }
if (ImGui::BeginPopup("Rejoindre une partie##join_popup")) { if (ImGui::BeginPopup("Rejoindre une partie##join_popup")) {
ImGui::InputText("Server Adress", &m_ConnectAddress.front(), m_ConnectAddress.capacity()); ImGui::InputText("Server Adress", &m_ConnectAddress.front(), m_ConnectAddress.capacity());
ImGui::InputInt("Port", &m_ConnectPort, -1); ImGui::InputInt("Port", &m_ConnectPort, -1);
@@ -71,7 +71,7 @@ void MainMenu::render() {
ImGui::End(); ImGui::End();
} }
bool MainMenu::startServer(){ bool MainMenu::startServer() {
if (m_WorldFilePath.empty()) if (m_WorldFilePath.empty())
return false; return false;
m_Server = std::make_unique<td::server::Server>(m_WorldFilePath); m_Server = std::make_unique<td::server::Server>(m_WorldFilePath);

View File

@@ -19,22 +19,22 @@ void MobTooltip::render() {
const game::Player& sender = getClient()->getGame().getPlayerById(m_Mob->getSender()); 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());
ImGui::Text("Mob Level : %i", m_Mob->getLevel()); ImGui::Text("Mob Level : %i", m_Mob->getLevel());
ImGui::NewLine(); ImGui::NewLine();
ImGui::Text("Mob Stats :"); ImGui::Text("Mob Stats :");
ImGui::Text("\tMax health : %i", m_Mob->getStats()->getMaxLife()); ImGui::Text("\tMax health : %i", m_Mob->getStats()->getMaxLife());
ImGui::Text("\tSpeed : %.1f", m_Mob->getStats()->getMovementSpeed()); ImGui::Text("\tSpeed : %.1f", m_Mob->getStats()->getMovementSpeed());
ImGui::Text("\tDamage : %.1f", m_Mob->getStats()->getDamage()); ImGui::Text("\tDamage : %.1f", m_Mob->getStats()->getDamage());
ImGui::Text("\tMoney cost : %i", m_Mob->getStats()->getMoneyCost()); ImGui::Text("\tMoney cost : %i", m_Mob->getStats()->getMoneyCost());
ImGui::Text("\tEXP cost : %i", m_Mob->getStats()->getExpCost()); ImGui::Text("\tEXP cost : %i", m_Mob->getStats()->getExpCost());
ImGui::Text("\tEXP reward : %i", m_Mob->getStats()->getExpReward()); ImGui::Text("\tEXP reward : %i", m_Mob->getStats()->getExpReward());
ImGui::EndTooltip(); ImGui::EndTooltip();
} }

View File

@@ -5,11 +5,11 @@
namespace td { namespace td {
namespace gui { namespace gui {
SummonMenu::SummonMenu(client::Client* client) : GuiWidget(client), m_MenuOpened(true){ SummonMenu::SummonMenu(client::Client* client) : GuiWidget(client), m_MenuOpened(true) {
m_Values.fill(0); m_Values.fill(0);
} }
void SummonMenu::render(){ void SummonMenu::render() {
if (m_MenuOpened) { if (m_MenuOpened) {
ImGui::Begin("Summon", &m_MenuOpened); ImGui::Begin("Summon", &m_MenuOpened);
ImTextureID my_tex_id = ImGui::GetIO().Fonts->TexID; ImTextureID my_tex_id = ImGui::GetIO().Fonts->TexID;
@@ -51,8 +51,8 @@ void SummonMenu::render(){
if (ImGui::Button("Send")) { if (ImGui::Button("Send")) {
std::vector<protocol::MobSend> mobSent; std::vector<protocol::MobSend> mobSent;
protocol::MobSend mobSend; protocol::MobSend mobSend;
for(int i = 0; i < m_MobTypeCount; i++){ for (int i = 0; i < m_MobTypeCount; i++) {
if(m_Values[i] != 0){ if (m_Values[i] != 0) {
mobSend.mobCount = m_Values[i]; mobSend.mobCount = m_Values[i];
mobSend.mobLevel = 1; // TODO: add mob levels mobSend.mobLevel = 1; // TODO: add mob levels
mobSend.mobType = td::game::MobType(i); mobSend.mobType = td::game::MobType(i);
@@ -66,7 +66,7 @@ void SummonMenu::render(){
} }
} }
void SummonMenu::setSummonMax(int valueIndex){ void SummonMenu::setSummonMax(int valueIndex) {
int& value = m_Values[valueIndex]; int& value = m_Values[valueIndex];
value = std::max(0, value); value = std::max(0, value);
value = std::min(12, value); value = std::min(12, value);

View File

@@ -28,8 +28,8 @@ void TowerGui::initWidgets() {
m_UpdateMenu = std::make_unique<td::gui::UpdateMenu>(m_Client.get()); m_UpdateMenu = std::make_unique<td::gui::UpdateMenu>(m_Client.get());
} }
TowerGui::TowerGui(SDL_Window* sdl_window, SDL_GLContext glContext, td::render::Renderer* renderer) : m_Window(sdl_window), TowerGui::TowerGui(SDL_Window* sdl_window, SDL_GLContext glContext, td::render::Renderer* renderer) : m_Window(sdl_window),
m_GlContext(glContext), m_Renderer(renderer), m_Client(std::make_unique<client::Client>(m_Renderer)) { m_GlContext(glContext), m_Renderer(renderer), m_Client(std::make_unique<client::Client>(m_Renderer)) {
IMGUI_CHECKVERSION(); IMGUI_CHECKVERSION();
ImGui::CreateContext(); ImGui::CreateContext();
ImGui::StyleColorsDark(); ImGui::StyleColorsDark();

View File

@@ -44,7 +44,7 @@ void TowerPlacePopup::render() {
ImGui::SetCursorPosY(m_TowerPopupTileHeight - m_PlaceTowerButtonHeight - 10); ImGui::SetCursorPosY(m_TowerPopupTileHeight - m_PlaceTowerButtonHeight - 10);
ImGui::SetCursorPosX(m_TowerPopupTileWidth / 2.0f - m_PlaceTowerButtonWidth / 2.0f); ImGui::SetCursorPosX(m_TowerPopupTileWidth / 2.0f - m_PlaceTowerButtonWidth / 2.0f);
if(ImGui::Button(buyText.c_str(), ImVec2(m_PlaceTowerButtonWidth, m_PlaceTowerButtonHeight))){ if (ImGui::Button(buyText.c_str(), ImVec2(m_PlaceTowerButtonWidth, m_PlaceTowerButtonHeight))) {
getClient()->placeTower(towerType, m_ClickWorldPos); getClient()->placeTower(towerType, m_ClickWorldPos);
ImGui::CloseCurrentPopup(); ImGui::CloseCurrentPopup();
} }

View File

@@ -20,18 +20,18 @@ void UpdateMenu::render() {
bool updateAvailable = m_UpdateAvailable.get(); bool updateAvailable = m_UpdateAvailable.get();
if (updateAvailable) { if (updateAvailable) {
if(m_Updater.isFileWrited()){ if (m_Updater.isFileWrited()) {
ImGui::Text("The update is now installed"); ImGui::Text("The update is now installed");
ImGui::Text("The game needs to be restarted"); ImGui::Text("The game needs to be restarted");
}else if (m_Updater.isDownloadComplete()) { } else if (m_Updater.isDownloadComplete()) {
ImGui::Text("Download done!"); ImGui::Text("Download done!");
if(ImGui::Button("Install")){ if (ImGui::Button("Install")) {
if(!m_Updater.writeFile()){ if (!m_Updater.writeFile()) {
m_Error = "Failed to write file !\n"; m_Error = "Failed to write file !\n";
ImGui::OpenPopup("UpdateError"); ImGui::OpenPopup("UpdateError");
} }
} }
if(ImGui::Button("Cancel")){ if (ImGui::Button("Cancel")) {
m_Updater.cancelDownload(); m_Updater.cancelDownload();
m_Updater.clearCache(); m_Updater.clearCache();
} }
@@ -50,13 +50,13 @@ void UpdateMenu::render() {
bool canDownloadFile = m_Updater.canUpdate(); bool canDownloadFile = m_Updater.canUpdate();
if(!canDownloadFile) ImGui::BeginDisabled(); if (!canDownloadFile) ImGui::BeginDisabled();
if (ImGui::Button("Download")) { if (ImGui::Button("Download")) {
m_Updater.downloadUpdate(); m_Updater.downloadUpdate();
} }
if(!canDownloadFile) ImGui::EndDisabled(); if (!canDownloadFile) ImGui::EndDisabled();
ImGui::SameLine(); ImGui::SameLine();
if (ImGui::Button("Cancel")) { if (ImGui::Button("Cancel")) {
@@ -77,8 +77,8 @@ void UpdateMenu::render() {
} }
} }
void UpdateMenu::renderErrorPopup(){ void UpdateMenu::renderErrorPopup() {
if(ImGui::BeginPopup("UpdateError")){ if (ImGui::BeginPopup("UpdateError")) {
ImGui::Text("Error : %s", m_Error.c_str()); ImGui::Text("Error : %s", m_Error.c_str());
ImGui::EndPopup(); ImGui::EndPopup();
} }

View File

@@ -97,8 +97,8 @@ GL::VertexArray loadWorldModel(const td::game::World* world) {
for (int spawnColor = 0; spawnColor < 2; spawnColor++) { for (int spawnColor = 0; spawnColor < 2; spawnColor++) {
const game::Spawn& spawn = world->getTeam(game::TeamColor(spawnColor)).getSpawn(); const game::Spawn& spawn = world->getTeam(game::TeamColor(spawnColor)).getSpawn();
float fromX = spawn.x - 2, toX = spawn.x + 3; float fromX = spawn.getTopLeft().getX() , toX = spawn.getBottomRight().getX();
float fromY = spawn.y - 2, toY = spawn.y + 3; float fromY = spawn.getTopLeft().getY() , toY = spawn.getBottomRight().getY();
positions.insert(positions.end(), { positions.insert(positions.end(), {
fromX, fromY, fromX, fromY,
@@ -125,8 +125,8 @@ GL::VertexArray loadWorldModel(const td::game::World* world) {
for (int castleColor = 0; castleColor < 2; castleColor++) { for (int castleColor = 0; castleColor < 2; castleColor++) {
const game::TeamCastle& castle = world->getTeam(game::TeamColor(castleColor)).getCastle(); const game::TeamCastle& castle = world->getTeam(game::TeamColor(castleColor)).getCastle();
float fromX = castle.x - 2, toX = castle.x + 3; float fromX = castle.getTopLeft().getX(), toX = castle.getBottomRight().getX();
float fromY = castle.y - 2, toY = castle.y + 3; float fromY = castle.getTopLeft().getY(), toY = castle.getBottomRight().getY();
positions.insert(positions.end(), { positions.insert(positions.end(), {
fromX, fromY, fromX, fromY,
@@ -203,17 +203,17 @@ RenderData loadTowerModel(game::TowerPtr tower) {
float towerY, towerDY; float towerY, towerDY;
if (tower->getSize() == game::TowerSize::Little) { if (tower->getSize() == game::TowerSize::Little) {
towerX = tower->getX() - 1; towerX = tower->getCenterX() - 1.5f;
towerDX = tower->getX() + 2; towerDX = tower->getCenterX() + 1.5f;
towerY = tower->getY() - 1; towerY = tower->getCenterY() - 1.5f;
towerDY = tower->getY() + 2; towerDY = tower->getCenterY() + 1.5f;
} else { } else {
towerX = tower->getX() - 2; towerX = tower->getCenterX() - 2.5f;
towerDX = tower->getX() + 3; towerDX = tower->getCenterX() + 2.5f;
towerY = tower->getY() - 2; towerY = tower->getCenterY() - 2.5f;
towerDY = tower->getY() + 3; towerDY = tower->getCenterY() + 2.5f;
} }
std::vector<float> positions = { std::vector<float> positions = {
towerX, towerY, towerX, towerY,

View File

@@ -8,7 +8,7 @@
#include "render/shaders/EntityShader.h" #include "render/shaders/EntityShader.h"
#ifdef __ANDROID__ #ifdef __ANDROID__
static const char vertexSource[] = static const char vertexSource[] =
R"(#version 300 es R"(#version 300 es
precision mediump float; precision mediump float;
@@ -34,7 +34,7 @@ void main(void){
} }
)"; )";
static const char fragmentSource[] = static const char fragmentSource[] =
R"(#version 300 es R"(#version 300 es
precision mediump float; precision mediump float;

View File

@@ -116,9 +116,9 @@ int ShaderProgram::loadShader(const std::string& source, GLenum type) {
char error[size]; char error[size];
glGetShaderInfoLog(shaderID, size, &size, error); glGetShaderInfoLog(shaderID, size, &size, error);
std::cout << error << std::endl; std::cout << error << std::endl;
#ifdef __ANDROID__ #ifdef __ANDROID__
__android_log_print(ANDROID_LOG_ERROR, "TRACKERS", "Could not compile shader !\n %s", error); __android_log_print(ANDROID_LOG_ERROR, "TRACKERS", "Could not compile shader !\n %s", error);
#endif #endif
} }
return shaderID; return shaderID;
} }

View File

@@ -8,7 +8,7 @@
#include "render/shaders/WorldShader.h" #include "render/shaders/WorldShader.h"
#ifdef __ANDROID__ #ifdef __ANDROID__
static const char vertexSource[] = static const char vertexSource[] =
R"(#version 300 es R"(#version 300 es
precision mediump float; precision mediump float;
@@ -31,7 +31,7 @@ void main(void){
} }
)"; )";
static const char fragmentSource[] = static const char fragmentSource[] =
R"(#version 300 es R"(#version 300 es
precision mediump float; precision mediump float;

View File

@@ -1,4 +1,5 @@
#include "misc/Updater.h" #include "updater/Updater.h"
#include "misc/Platform.h" #include "misc/Platform.h"
#include "misc/DataBuffer.h" #include "misc/DataBuffer.h"
@@ -24,7 +25,7 @@ bool Updater::checkUpdate() {
m_LastVersion = m_LastVersion.substr(0, m_LastVersion.find('\n')); m_LastVersion = m_LastVersion.substr(0, m_LastVersion.find('\n'));
std::cout << "Current version : [" << getCurrentVersion() << "]\n"; std::cout << "Current version : [" << getCurrentVersion() << "]\n";
std::cout << "Last version : [" << m_LastVersion << "]\n"; std::cout << "Last version : [" << m_LastVersion << "]\n";
if (currentVersion != m_LastVersion) { if (currentVersion != m_LastVersion) {
return true; return true;

View File

@@ -8,7 +8,7 @@ target("TowerDefense")
add_files("src/*.cpp", "src/*/*.cpp", "src/*/*/*.cpp", "src/*/*/*/*.cpp") add_files("src/*.cpp", "src/*/*.cpp", "src/*/*/*.cpp", "src/*/*/*/*.cpp")
add_cxflags("-pthread") add_cxflags("-pthread")
set_languages("c++14") set_languages("c++17")
add_links("glbinding", "z", "SDL2") add_links("glbinding", "z", "SDL2")
@@ -35,6 +35,9 @@ target("TowerDefense")
end end
else else
if is_os("linux") then
add_links("dw")
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