110 Commits

Author SHA1 Message Date
36f37b6548 Revert "Merge branch 'discord'"
This reverts commit e7b9a57723, reversing
changes made to 02b4aa3c91.

Revert "moved rapidjson files"

This reverts commit f5012f770c.
2023-06-21 23:36:20 +02:00
1dde1dbf1e fix vertex cache 2023-06-20 16:27:41 +02:00
f5012f770c moved rapidjson files 2023-06-08 12:30:05 +02:00
e7b9a57723 Merge branch 'discord' 2023-06-08 12:21:54 +02:00
02b4aa3c91 xmake add_files 2023-06-08 12:16:50 +02:00
f184982bc1 change release optimization 2023-06-07 12:39:58 +02:00
1cdc738839 refactor: rename zoom function 2023-06-07 12:36:31 +02:00
368bc450ce better cam controls 2023-06-07 12:33:10 +02:00
148b5f397a more vect operators 2023-06-07 12:32:24 +02:00
f62322752d use of td pi 2023-06-06 17:59:48 +02:00
fb9e125f16 refactor: format 2023-06-06 17:58:27 +02:00
b70e8f7790 approximative cam movement 2023-06-06 17:56:19 +02:00
39bdd0a11e remove useless pi digits 2023-06-06 17:17:00 +02:00
c95c8b7fde clamp camera + pi 2023-06-06 17:15:44 +02:00
e984ed9085 fixed cam distance 2023-06-06 17:04:17 +02:00
92035d7b9e remove useless variable 2023-06-06 13:09:02 +02:00
48841fa4e9 camera fixing 2023-06-06 13:07:42 +02:00
83ab8c70f0 cache transpose 2023-06-06 12:45:34 +02:00
ccdcdac7c6 working mouse picking 2023-06-06 12:36:05 +02:00
a2b5424888 fix inverse assert 2023-06-05 18:06:02 +02:00
a4fb56b549 camera yaw and pitch 2023-06-05 13:50:45 +02:00
22e62df04d remove unused variables 2023-06-05 13:17:04 +02:00
faf544f997 basic camera movement 2023-06-05 13:15:27 +02:00
b72f4a7673 fix inverted zoom 2023-06-05 13:12:43 +02:00
19c03010cb remove useless computation 2023-06-05 13:07:56 +02:00
41f8c152eb really bad controls 2023-06-04 13:02:41 +02:00
051c9d8744 fix format error 2023-06-04 12:42:58 +02:00
193e4db651 fix mouse picking 2023-06-03 20:43:40 +02:00
cb5f5a4cf8 fixing transpose 2023-06-03 19:46:37 +02:00
bc7e5914ce invert assert 2023-06-03 19:44:05 +02:00
0365902971 moved Mat4 definition 2023-06-03 19:40:50 +02:00
f2fcc348d7 more maths 2023-06-03 18:22:01 +02:00
95c92ec6c9 rename lookat function 2023-06-03 17:54:59 +02:00
721f15b601 fix tower rendering 2023-06-03 17:49:00 +02:00
3970103b01 kinda 3d 2023-06-03 17:41:46 +02:00
4e866c1032 shaders to 3d 2023-06-03 16:35:17 +02:00
ca268781fd shader better logging 2023-06-03 16:30:32 +02:00
a2d8984199 shader matrix support 2023-06-03 16:30:23 +02:00
e7f9ca2b6c fix maths warning 2023-06-03 16:23:56 +02:00
deb0075aac add maths utils 2023-06-02 17:54:58 +02:00
28b8659e16 fix linux compiling 2023-06-02 16:26:17 +02:00
0b9fc0520e fix compiling mingw 2023-06-02 16:19:42 +02:00
c54017c7be update presence 2023-06-02 13:34:01 +02:00
bbfe341d23 base discord rpc 2023-06-02 13:18:09 +02:00
14efe2cc39 simplified health bar display 2023-01-02 16:58:31 +01:00
fcda12e321 add hit "animation" 2023-01-02 16:37:18 +01:00
1200a6e087 moved TowerUpgradePopop into its own file 2023-01-02 15:56:20 +01:00
512fb23d0e add server mspt (+procotol format) 2023-01-02 15:07:34 +01:00
5a547b6514 move towers implementations 2023-01-02 14:47:02 +01:00
ed45995645 add mob send cooldown 2023-01-02 14:32:37 +01:00
0b6d826eba remove unused glm package 2023-01-02 13:55:54 +01:00
6d0c6be166 server side safe checks 2023-01-02 13:18:49 +01:00
222b79b40a indent with tabs 2023-01-02 13:05:43 +01:00
8f95b1a750 remove format warning 2023-01-02 12:27:08 +01:00
7d30017742 moved Color to Defines.h 2023-01-02 12:21:27 +01:00
386ea5b6ad forward declare Updater 2023-01-02 12:05:20 +01:00
8949c37891 chore: bump version to alpha-0.3.0 2023-01-01 19:42:49 +01:00
019174128c fix: COMPRESSION 2023-01-01 19:40:23 +01:00
4e8b095e31 xmake.lua show wine console output 2022-12-11 13:04:00 +01:00
0e0368cada add wine xmake.lua 2022-12-11 12:59:57 +01:00
Simon Pribylski
6e0923ac75 remove glm dependency 2022-10-13 12:24:15 +02:00
Simon Pribylski
bba9ef8219 Add glm dependency 2022-09-07 18:54:10 +02:00
fd2288ac3c refactor xmake.lua 2022-09-03 16:55:36 +02:00
660952aed3 add example map 2022-07-18 12:12:53 +02:00
243b153309 remove unsed variable 2022-07-18 11:51:52 +02:00
73fa10d8d6 fixing log 2022-07-18 11:50:30 +02:00
0b8a7d8db7 hmmm 2022-07-14 18:42:46 +02:00
e2ec9d6a3b add player getter 2022-07-14 18:40:52 +02:00
eb5b3c8ce2 explicit cast zlib functions 2022-07-14 18:39:28 +02:00
ddbba7399d use of loge 2022-07-14 18:39:06 +02:00
9ce1f4a1a8 add loge 2022-07-14 18:35:11 +02:00
ea4349af4c fix log android 2022-07-14 18:34:26 +02:00
d6fbb58da8 using log calls 2022-07-14 18:32:32 +02:00
66376eaeda allow custom opengl loader 2022-07-14 18:04:13 +02:00
85eb9bbc32 add exp sync 2022-07-14 13:09:38 +02:00
bbb84c0061 add log 2022-07-14 13:08:20 +02:00
2f1161959b remove unused includes 2022-07-14 13:07:41 +02:00
f506307653 refactor databuffer write 2022-07-04 11:17:30 +02:00
40f0d50991 util format function 2022-07-04 11:13:26 +02:00
663ad60ee3 util player methods 2022-07-04 11:13:11 +02:00
3fbb6acac7 fix initial stats 2022-07-04 10:42:31 +02:00
377e98f583 fix warnings 2022-07-04 10:24:18 +02:00
ef9712629f remove use of loops in protocol 2022-06-29 12:42:21 +02:00
ed481de03e add databuffer helper functions 2022-06-29 12:35:36 +02:00
7d667d9c5e add buy packets 2022-06-29 12:13:58 +02:00
16006adc6e fix more warnings 2022-06-27 13:33:24 +02:00
19062b5c77 fix warnings 2022-06-27 13:12:39 +02:00
d3c6ff3988 fix MobSend size 2022-06-27 13:12:20 +02:00
31a0027bfc add namespace comments 2022-06-27 12:29:22 +02:00
d4b1805998 refactor: forgot this one 2022-04-27 19:46:41 +02:00
b84f1fd302 fix: remove useless warning flag 2022-04-27 19:46:09 +02:00
98f73f467d fix: change ChunkCoords hashing 2022-04-27 19:44:16 +02:00
dc8a4ce947 refactor: alpha sort methods 2022-04-27 19:41:03 +02:00
113a831f39 refactor: removed unused semicolon 2022-04-27 19:35:45 +02:00
f906aa1bf0 refactor: more casts 2022-04-27 19:34:45 +02:00
1bbf607b22 refactor: show override 2022-04-27 19:34:12 +02:00
d5b42caf39 refactor: cpp style casts 2022-04-27 19:25:36 +02:00
d3edc0cb6c refactor: spaces instead of tabs 2022-04-27 18:44:22 +02:00
87e4e65843 refactor: remove useless namespace 2022-04-27 18:38:10 +02:00
7509cc1bf2 feat: add player upgrades 2022-04-27 18:37:07 +02:00
6df59b1487 GIGA REFACTOR 2022-03-02 18:51:42 +01:00
553b2f6aad feat: show demo window on debug only 2022-02-17 19:39:07 +01:00
916fa0e7c0 format 2022-02-17 19:35:09 +01:00
bc271bc01e protocol rework + map packet ids removal 2022-02-17 19:35:02 +01:00
97a33e5517 BIG REFACTOR Part 2 2022-02-16 18:34:49 +01:00
bdebabb79e BIG REFACTOR 2022-02-16 17:54:33 +01:00
387cff36ad style: more space 2022-02-16 16:32:05 +01:00
790237a1b5 refactor: changed to PlayerID type 2022-02-16 16:31:18 +01:00
840d5edbe4 refactor: changed exp and money update 2022-02-16 16:18:25 +01:00
36a9e1921c refactor: use of const reference 2022-01-07 18:30:37 +01:00
134 changed files with 6416 additions and 5498 deletions

148
include/Defines.h Normal file
View File

@@ -0,0 +1,148 @@
#pragma once
#include <cstdint>
namespace td {
static constexpr float PI = 3.141592653f;
template<typename T>
struct Vec2 {
union {
T x;
T r;
};
union {
T y;
T g;
};
constexpr Vec2(T X = 0, T Y = 0) : x(X), y(Y) {}
};
template<typename T>
inline bool operator==(const Vec2<T>& vec2, const Vec2<T>& other) {
return vec2.x == other.x && vec2.y == other.y;
}
template<typename T>
struct Vec3 {
union {
T x;
T r;
};
union {
T y;
T g;
};
union {
T z;
T b;
};
constexpr Vec3(T X = 0, T Y = 0, T Z = 0) : x(X), y(Y), z(Z) {}
};
template<typename T>
inline bool operator==(const Vec3<T>& vec3, const Vec3<T>& other) {
return vec3.x == other.x && vec3.y == other.y && vec3.z == other.z;
}
template<typename T>
struct Vec4 {
union {
T x;
T r;
};
union {
T y;
T g;
};
union {
T z;
T b;
};
union {
T w;
T a;
};
constexpr Vec4(Vec3<T> vec, T W = 1) : x(vec.x), y(vec.y), z(vec.z), w(W) {}
constexpr Vec4(T X = 0, T Y = 0, T Z = 0, T W = 0) : x(X), y(Y), z(Z), w(W) {}
};
template<typename T>
inline bool operator==(const Vec4<T>& vec4, const Vec4<T>& other) {
return vec4.x == other.x && vec4.y == other.y && vec4.z == other.z && vec4.w = other.w;
}
using Vec2i = Vec2<int>;
using Vec2u = Vec2<unsigned int>;
using Vec2f = Vec2<float>;
using Vec2d = Vec2<double>;
using Vec3i = Vec3<int>;
using Vec3u = Vec3<unsigned int>;
using Vec3f = Vec3<float>;
using Vec3d = Vec3<double>;
using Vec4i = Vec4<int>;
using Vec4u = Vec4<unsigned int>;
using Vec4f = Vec4<float>;
using Vec4d = Vec4<double>;
using Color = Vec3<unsigned char>;
template<typename T>
struct Mat4 {
static const std::size_t MATRIX_SIZE = 4;
T x0, x1, x2, x3;
T y0, y1, y2, y3;
T z0, z1, z2, z3;
T w0, w1, w2, w3;
T operator[] (std::size_t offset) const {
return reinterpret_cast<const T*>(this)[offset];
}
T& operator[] (std::size_t offset) {
return reinterpret_cast<T*>(this)[offset];
}
T* data() {
return reinterpret_cast<T*>(this);
}
const T* data() const{
return reinterpret_cast<const T*>(this);
}
T at(std::size_t row, std::size_t column) const {
return operator[](row * MATRIX_SIZE + column);
}
T& at(std::size_t row, std::size_t column) {
return operator[](row * MATRIX_SIZE + column);
}
};
typedef Mat4<float> Mat4f;
typedef Mat4<int> Mat4i;
typedef Mat4<double> Mat4d;
template<typename T>
inline bool operator==(const Mat4<T>& mat, const Mat4<T>& other) {
return mat.x0 == other.x0 && mat.y0 == other.y0 && mat.z0 == other.z0 && mat.w0 == other.w0 &&
mat.x1 == other.x1 && mat.y1 == other.y1 && mat.z1 == other.z1 && mat.w1 == other.w1 &&
mat.x2 == other.x2 && mat.y2 == other.y2 && mat.z2 == other.z2 && mat.w2 == other.w2 &&
mat.x3 == other.x3 && mat.y3 == other.y3 && mat.z3 == other.z3 && mat.w3 == other.w3;
}
} // namespace td

View File

@@ -8,62 +8,62 @@ namespace td {
namespace game { namespace game {
enum class GameState : std::uint8_t { enum class GameState : std::uint8_t {
Lobby, Lobby,
Game, Game,
EndGame, EndGame,
Disconnected, Disconnected,
Closed Closed
}; };
typedef std::map<std::uint8_t, Player> PlayerList; typedef std::map<std::uint8_t, Player> PlayerList;
class GameListener { class GameListener {
public: public:
virtual void OnPlayerJoin(PlayerID player) {} virtual void OnPlayerJoin(PlayerID player) {}
virtual void OnPlayerLeave(PlayerID player) {} virtual void OnPlayerLeave(PlayerID player) {}
virtual void OnGameStateUpdate(GameState newState) {} virtual void OnGameStateUpdate(GameState newState) {}
virtual void OnGameBegin() {} virtual void OnGameBegin() {}
virtual void OnGameEnd() {} virtual void OnGameEnd() {}
virtual void OnGameClose() {} virtual void OnGameClose() {}
}; };
typedef utils::ObjectNotifier<GameListener> GameNotifier; typedef utils::ObjectNotifier<GameListener> GameNotifier;
class Game : public GameNotifier { class Game : public GameNotifier {
protected: protected:
World* m_World; World* m_World;
TeamList m_Teams = { Team{TeamColor::Red}, Team{TeamColor::Blue} }; TeamList m_Teams = { Team{TeamColor::Red}, Team{TeamColor::Blue} };
GameState m_GameState = GameState::Lobby; GameState m_GameState = GameState::Lobby;
PlayerList m_Players; PlayerList m_Players;
public: public:
Game(World* world); Game(World* world);
virtual ~Game(); virtual ~Game();
virtual void tick(std::uint64_t delta); virtual void Tick(std::uint64_t delta);
Team& getRedTeam() { return m_Teams[(std::uint8_t)TeamColor::Red]; } Team& GetRedTeam() { return m_Teams[static_cast<std::uint8_t>(TeamColor::Red)]; }
const Team& getRedTeam() const { return m_Teams[(std::uint8_t)TeamColor::Red]; } const Team& GetRedTeam() const { return m_Teams[static_cast<std::uint8_t>(TeamColor::Red)]; }
Team& getBlueTeam() { return m_Teams[(std::uint8_t)TeamColor::Blue]; } Team& GetBlueTeam() { return m_Teams[static_cast<std::uint8_t>(TeamColor::Blue)]; }
const Team& getBlueTeam() const { return m_Teams[(std::uint8_t)TeamColor::Blue]; } const Team& GetBlueTeam() const { return m_Teams[static_cast<std::uint8_t>(TeamColor::Red)]; }
Team& getTeam(TeamColor team) { return m_Teams[(std::uint8_t)team]; } Team& GetTeam(TeamColor team) { return m_Teams[static_cast<std::uint8_t>(team)]; }
const Team& getTeam(TeamColor team) const { return m_Teams[(std::uint8_t)team]; } const Team& GetTeam(TeamColor team) const { return m_Teams[static_cast<std::uint8_t>(team)]; }
GameState getGameState() const { return m_GameState; } GameState GetGameState() const { return m_GameState; }
void setGameState(GameState gameState) { m_GameState = gameState; }; void SetGameState(GameState gameState) { m_GameState = gameState; };
const World* getWorld() const { return m_World; } const World* GetWorld() const { return m_World; }
World* getWorld() { return m_World; } World* GetWorld() { return m_World; }
const PlayerList& getPlayers() const { return m_Players; } const PlayerList& GetPlayers() const { return m_Players; }
PlayerList& getPlayers() { return m_Players; } PlayerList& GetPlayers() { return m_Players; }
const Player* getPlayerById(PlayerID id) const; const Player* GetPlayerById(PlayerID id) const;
Player* getPlayerById(PlayerID id); Player* GetPlayerById(PlayerID id);
const TeamList& getTeams() const { return m_Teams; } const TeamList& GetTeams() const { return m_Teams; }
}; };

View File

@@ -10,26 +10,26 @@ namespace protocol {
class Connexion : public protocol::PacketHandler { class Connexion : public protocol::PacketHandler {
protected: protected:
protocol::PacketDispatcher m_Dispatcher; protocol::PacketDispatcher m_Dispatcher;
private: private:
network::TCPSocket m_Socket; network::TCPSocket m_Socket;
public: public:
Connexion(); Connexion();
Connexion(Connexion&& move); Connexion(Connexion&& move);
Connexion(protocol::PacketDispatcher* dispatcher); Connexion(protocol::PacketDispatcher* dispatcher);
Connexion(protocol::PacketDispatcher* dispatcher, network::TCPSocket& socket); Connexion(protocol::PacketDispatcher* dispatcher, network::TCPSocket& socket);
virtual ~Connexion(); virtual ~Connexion();
virtual bool updateSocket(); virtual bool UpdateSocket();
void closeConnection(); void CloseConnection();
bool connect(const std::string& address, std::uint16_t port); bool Connect(const std::string& address, std::uint16_t port);
network::Socket::Status getSocketStatus() const { return m_Socket.GetStatus(); } network::Socket::Status GetSocketStatus() const { return m_Socket.GetStatus(); }
void sendPacket(const protocol::Packet* packet); void SendPacket(const protocol::Packet* packet);
REMOVE_COPY(Connexion); REMOVE_COPY(Connexion);
}; };
} // namespace server } // namespace server

View File

@@ -10,12 +10,12 @@
namespace GameManager { namespace GameManager {
void render(); void Render();
void init(); void Init();
void destroy(); void Destroy();
void tick(); void Tick();
void startServer(); void StartServer();
} }

View File

@@ -1,5 +1,6 @@
#pragma once #pragma once
#include "Defines.h"
#include "Towers.h" #include "Towers.h"
#include "Types.h" #include "Types.h"
#include "Team.h" #include "Team.h"
@@ -9,34 +10,32 @@
#include <vector> #include <vector>
#include <memory> #include <memory>
#include <glm/glm.hpp>
namespace td { namespace td {
namespace game { namespace game {
struct WalkableTile; struct WalkableTile;
enum class EffectType : std::uint8_t { enum class EffectType : std::uint8_t {
Slowness = 0, Slowness = 0,
Stun, Stun,
Fire, Fire,
Poison, Poison,
Heal, Heal,
}; };
enum class MobType : std::uint8_t { enum class MobType : std::uint8_t {
Zombie = 0, Zombie = 0,
Spider, Spider,
Skeleton, Skeleton,
Pigman, Pigman,
Creeper, Creeper,
Silverfish, Silverfish,
Blaze, Blaze,
Witch, Witch,
Slime, Slime,
Giant, Giant,
MOB_COUNT MOB_COUNT
}; };
typedef std::uint32_t MobID; typedef std::uint32_t MobID;
@@ -46,201 +45,214 @@ typedef std::vector<EffectType> EffectImmunities;
class MobStats { class MobStats {
private: private:
float m_Damage; float m_Damage;
float m_Speed; float m_Speed;
glm::vec2 m_Size; Vec2f 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, glm::vec2 size, std::uint16_t moneyCost, MobStats(float damage, float speed, Vec2f 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_Size(size), m_MoneyCost(moneyCost), m_ExpCost(expCost), m_Size(size), m_MoneyCost(moneyCost), m_ExpCost(expCost),
m_MaxLife(maxLife), 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; } const Vec2f& 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
Tower* tower; // the tower that gived the effect Tower* tower; // the tower that gived the effect
}; };
const MobStats* getMobStats(MobType type, std::uint8_t level); const MobStats* GetMobStats(MobType type, std::uint8_t level);
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 : public utils::shape::Rectangle { class Mob : public utils::shape::Rectangle {
protected: protected:
float m_Health; float m_Health;
private: private:
MobID m_ID; MobID m_ID;
PlayerID m_Sender; PlayerID m_Sender;
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 last tower that damaged the mob const Tower* m_LastDamage; // the last tower that damaged the mob
float m_HitCooldown;
utils::Timer m_EffectFireTimer; utils::Timer m_EffectFireTimer;
utils::Timer m_EffectPoisonTimer; utils::Timer m_EffectPoisonTimer;
utils::Timer m_EffectHealTimer; utils::Timer m_EffectHealTimer;
TeamCastle* m_CastleTarget; TeamCastle* m_CastleTarget;
utils::CooldownTimer m_AttackTimer; utils::CooldownTimer m_AttackTimer;
public: public:
Mob(MobID id, MobLevel level, PlayerID sender) : m_Sender(sender), m_Level(level), Mob(MobID id, MobLevel level, PlayerID sender) : m_Sender(sender), m_Level(level),
m_EffectFireTimer(1000), m_EffectPoisonTimer(1000), m_HitCooldown(0), m_EffectFireTimer(1000), m_EffectPoisonTimer(1000),
m_EffectHealTimer(1000), m_CastleTarget(nullptr), m_AttackTimer(1000) { m_EffectHealTimer(1000), m_CastleTarget(nullptr), m_AttackTimer(1000) {
} }
virtual MobType getType() const = 0; virtual MobType GetType() const = 0;
virtual void tick(std::uint64_t delta, World* world); virtual void Tick(std::uint64_t delta, World* world);
virtual bool OnDeath(World* world) { return true; } virtual bool OnDeath(World* world) { return true; }
MobID getMobID() const { return m_ID; } MobID GetMobID() const { return m_ID; }
const TowerImmunities& getTowerImmunities() const { return getMobTowerImmunities(getType(), m_Level); } const TowerImmunities& GetTowerImmunities() const { return GetMobTowerImmunities(GetType(), m_Level); }
const EffectImmunities& getEffectImmunities() const { return getMobEffectImmunities(getType(), m_Level); } const EffectImmunities& GetEffectImmunities() const { return GetMobEffectImmunities(GetType(), m_Level); }
PlayerID getSender() const { return m_Sender; } PlayerID GetSender() const { return m_Sender; }
MobLevel getLevel() const { return m_Level; } MobLevel GetLevel() const { return m_Level; }
const MobStats* getStats() const { return getMobStats(getType(), m_Level); } const MobStats* GetStats() const { return GetMobStats(GetType(), m_Level); }
void setHealth(float newHealth) { m_Health = newHealth; } void SetHealth(float newHealth) { m_Health = newHealth; }
float getHealth() const { return m_Health; } float GetHealth() const { return m_Health; }
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_CastleTarget != nullptr; } bool HasReachedEnemyCastle() { return m_CastleTarget != nullptr; }
void damage(float dmg, const Tower* damager) { m_Health = std::max(0.0f, m_Health - dmg); m_LastDamage = damager; } void Damage(float dmg, const Tower* damager) {
void heal(float heal) { m_Health = std::min(static_cast<float>(getStats()->getMaxLife()), m_Health + heal); } m_Health = std::max(0.0f, m_Health - dmg);
void setMobReachedCastle(TeamCastle* castle) { m_CastleTarget = castle; } // used when mob is in front of the castle m_LastDamage = damager;
m_HitCooldown = 0.1;
}
bool isImmuneTo(TowerType type); void Heal(float heal) {
m_Health = std::min(static_cast<float>(GetStats()->GetMaxLife()), m_Health + heal);
}
bool isImmuneTo(EffectType type); void SetMobReachedCastle(TeamCastle* castle) { m_CastleTarget = castle; } // used when mob is in front of the castle
void addEffect(EffectType type, float durationSec, Tower* tower);
bool hasEffect(EffectType type);
float getTileX() { return getCenterX() - static_cast<float>(static_cast<std::int32_t>(getCenterX())); } // returns a float between 0 and 1 excluded bool IsImmuneTo(TowerType type);
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; } bool IsImmuneTo(EffectType type);
void setDirection(Direction dir) { m_Direction = dir; } void AddEffect(EffectType type, float durationSec, Tower* tower);
bool HasEffect(EffectType type);
bool HasTakenDamage() { return m_HitCooldown > 0; }
float GetTileX() { return GetCenterX() - static_cast<float>(static_cast<std::int32_t>(GetCenterX())); } // returns a float between 0 and 1 excluded
float GetTileY() { return GetCenterY() - static_cast<float>(static_cast<std::int32_t>(GetCenterY())); } // returns a float between 0 and 1 excluded
Direction GetDirection() const { return m_Direction; }
void SetDirection(Direction dir) { m_Direction = dir; }
protected: protected:
void initMob() { void InitMob() {
m_Health = static_cast<float>(getStats()->getMaxLife()); m_Health = static_cast<float>(GetStats()->GetMaxLife());
setSize(getStats()->getSize().x, getStats()->getSize().y); SetSize(GetStats()->GetSize().x, GetStats()->GetSize().y);
} }
private: private:
void updateEffects(std::uint64_t delta, World* world); void UpdateEffects(std::uint64_t delta, World* world);
void attackCastle(std::uint64_t delta, World* world); void AttackCastle(std::uint64_t delta, World* world);
void move(std::uint64_t delta, World* world); void Move(std::uint64_t delta, World* world);
void walk(std::uint64_t delta, World* world); void Walk(std::uint64_t delta, World* world);
void moveBack(const TeamCastle& castle, World* world); void MoveBack(const TeamCastle& castle, World* world);
void changeDirection(const WalkableTile& tile, World* world); void ChangeDirection(const WalkableTile& tile, World* world);
bool isTouchingCastle(const TeamCastle& castle) const; bool IsTouchingCastle(const TeamCastle& castle) const;
EffectDuration& getEffect(EffectType type); EffectDuration& GetEffect(EffectType type);
}; };
typedef std::shared_ptr<Mob> MobPtr; 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) { initMob(); } 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) { initMob(); } 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) { initMob(); } 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) { initMob(); } 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) { initMob(); } 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) { initMob(); } 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) { initMob(); } 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) { initMob(); } 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) { initMob(); } 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) { initMob(); } 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; }
}; };
namespace MobFactory { namespace MobFactory {
MobPtr createMob(MobID id, MobType type, std::uint8_t level, PlayerID sender);
std::string getMobName(MobType type); MobPtr CreateMob(MobID id, MobType type, std::uint8_t level, PlayerID sender);
std::string GetMobName(MobType type);
} }
class MobListener { class MobListener {
public: public:
virtual void OnMobSpawn(Mob* mob) {} virtual void OnMobSpawn(Mob* mob) {}
virtual void OnMobDie(Mob* mob) {} virtual void OnMobDie(Mob* mob) {}
virtual void OnMobDamage(Mob* target, float damage, Tower* damager) {} virtual void OnMobDamage(Mob* target, float damage, Tower* damager) {}
virtual void OnMobTouchCastle(Mob* damager, TeamCastle* enemyCastle) {} virtual void OnMobTouchCastle(Mob* damager, TeamCastle* enemyCastle) {}
virtual void OnMobCastleDamage(Mob* damager, TeamCastle* enemyCastle, float damage) {} virtual void OnMobCastleDamage(Mob* damager, TeamCastle* enemyCastle, float damage) {}
}; };
typedef utils::ObjectNotifier<MobListener> MobNotifier; typedef utils::ObjectNotifier<MobListener> MobNotifier;

View File

@@ -1,56 +1,50 @@
#pragma once #pragma once
#include <cstdint>
#include <string> #include <string>
#include "game/Team.h" #include "game/Team.h"
#include "game/PlayerUpgrades.h"
namespace td { namespace td {
namespace game { namespace game {
class Player { class Player {
private: private:
game::TeamColor m_TeamColor; TeamColor m_TeamColor;
PlayerUpgrades m_Upgrades;
std::uint32_t m_Gold; std::uint32_t m_Gold;
std::uint32_t m_Exp; std::uint32_t m_Exp;
std::string m_Name; std::string m_Name;
std::uint8_t m_ID; PlayerID m_ID;
std::uint8_t m_GoldPerSecond;
bool m_GoldChanged;
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),
m_GoldChanged(false), m_ExpChanged(false) {}
const std::string& getName() const { return m_Name; } Player(std::uint8_t id = 0) : m_TeamColor(TeamColor::None), m_Gold(0), m_Exp(0), m_ID(id) {}
void setName(const std::string& name) { m_Name = name; }
game::TeamColor getTeamColor() const { return m_TeamColor; } const std::string& GetName() const { return m_Name; }
void setTeamColor(game::TeamColor teamColor) { m_TeamColor = teamColor; } void SetName(const std::string& name) { m_Name = name; }
std::uint8_t getGoldPerSecond() const { return m_GoldPerSecond; } TeamColor GetTeamColor() const { return m_TeamColor; }
void setGoldPerSecond(std::uint8_t goldPerSecond) { m_GoldPerSecond = goldPerSecond; } void SetTeamColor(TeamColor teamColor) { m_TeamColor = teamColor; }
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_Gold = gold; }
void addGold(std::uint32_t gold) { m_GoldChanged = true; m_Gold += gold; } void AddGold(std::uint32_t gold) { m_Gold += gold; }
void removeGold(std::uint32_t gold) { m_GoldChanged = true; m_Gold -= gold; } void RemoveGold(std::uint32_t gold) { m_Gold -= gold; }
std::uint32_t getExp() const { return m_Exp; } std::uint32_t GetExp() const { return m_Exp; }
void setExp(std::uint32_t exp) { m_ExpChanged = true; m_Exp = exp; } void SetExp(std::uint32_t exp) { m_Exp = exp; }
void addExp(std::uint32_t exp) { m_ExpChanged = true; m_Exp += exp; } void AddExp(std::uint32_t exp) { m_Exp += exp; }
void removeExp(std::uint32_t exp) { m_ExpChanged = true; m_Exp -= exp; } void RemoveExp(std::uint32_t exp) { m_Exp -= exp; }
bool hasGoldChanged() const { return m_GoldChanged; } const PlayerUpgrades& getUpgrades() const { return m_Upgrades; }
bool hasExpChanged() const { return m_ExpChanged; } PlayerUpgrades& getUpgrades() { return m_Upgrades; }
void updateGold() { m_GoldChanged = false; } bool HasEnoughGold(std::uint32_t gold) const { return m_Gold >= gold; }
void updateExp() { m_ExpChanged = false; } bool HasEnoughExp(std::uint32_t exp) const { return m_Exp >= exp; }
std::uint8_t getID() const { return m_ID; } PlayerID GetID() const { return m_ID; }
}; };
} // namespace game } // namespace game

View File

@@ -0,0 +1,34 @@
#pragma once
#include "Mobs.h"
namespace td {
namespace game {
class PlayerUpgrades {
private:
std::uint8_t m_ClickerLevel;
std::uint8_t m_GoldPerSecond;
std::array<std::uint8_t, static_cast<std::size_t>(MobType::MOB_COUNT)> m_MobsUpgradeLevel;
public:
static const int MAX_MOB_LEVEL = 5;
static const int MAX_CLICKER_LEVEL = 3;
PlayerUpgrades() : m_ClickerLevel(1), m_GoldPerSecond(5) {}
std::uint8_t GetClickerLevel() const { return m_ClickerLevel; }
std::uint8_t GetMobUpgradeLevel(MobType mob) const { return m_MobsUpgradeLevel.at(static_cast<std::size_t>(mob)); }
std::uint8_t GetGoldPerSecond() const { return m_GoldPerSecond; }
void UpgradeMob(MobType mob) {
std::uint8_t& mobLevel = m_MobsUpgradeLevel.at(static_cast<std::size_t>(mob));
mobLevel = std::min(mobLevel + 1, MAX_MOB_LEVEL);
}
void UpgradeClicker() { m_ClickerLevel = std::min(m_ClickerLevel + 1, MAX_CLICKER_LEVEL); }
void SetGoldPerSecond(std::uint8_t goldPerSecond) { m_GoldPerSecond = goldPerSecond; }
};
} // namespace game
} // namespace td

View File

@@ -14,76 +14,76 @@ namespace game {
class Player; class Player;
enum class TeamColor : std::int8_t { enum class TeamColor : std::int8_t {
None = -1, None = -1,
Red, Red,
Blue Blue
}; };
class Spawn : public utils::shape::Rectangle { class Spawn : public utils::shape::Rectangle {
private: private:
Direction m_Direction; Direction m_Direction;
public: public:
Spawn() { Spawn() {
setWidth(5); SetWidth(5);
setHeight(5); SetHeight(5);
} }
Direction getDirection() const { return m_Direction; } Direction GetDirection() const { return m_Direction; }
void setDirection(Direction direction) { m_Direction = direction; } void SetDirection(Direction direction) { m_Direction = direction; }
}; };
class Team; class Team;
class TeamCastle : public utils::shape::Rectangle { class TeamCastle : public utils::shape::Rectangle {
private: private:
const Team* m_Team; const Team* m_Team;
float m_Life; float m_Life;
public: public:
static constexpr int CastleMaxLife = 1000; static constexpr int CastleMaxLife = 1000;
TeamCastle(const Team* team) : m_Team(team), m_Life(CastleMaxLife) { TeamCastle(const Team* team) : m_Team(team), m_Life(CastleMaxLife) {
setWidth(5); SetWidth(5);
setHeight(5); SetHeight(5);
} }
TeamCastle() : TeamCastle(nullptr) {} TeamCastle() : TeamCastle(nullptr) {}
float getLife() const { return m_Life; } float GetLife() const { return m_Life; }
const Team* getTeam() const { return m_Team; } const Team* GetTeam() const { return m_Team; }
void setTeam(const Team* team) { m_Team = team; } void SetTeam(const Team* team) { m_Team = team; }
void setLife(float life) { m_Life = life; } void SetLife(float life) { m_Life = life; }
void damage(float damage) { m_Life = std::max(0.0f, m_Life - damage); } void Damage(float damage) { m_Life = std::max(0.0f, m_Life - damage); }
void setShape(utils::shape::Rectangle rect) { void SetShape(utils::shape::Rectangle rect) {
setCenter(rect.getCenter()); SetCenter(rect.GetCenter());
setSize(rect.getSize()); SetSize(rect.GetSize());
} }
}; };
class Team { class Team {
private: private:
std::vector<Player*> m_Players; std::vector<Player*> m_Players;
TeamColor m_Color; TeamColor m_Color;
Spawn m_Spawn; Spawn m_Spawn;
TeamCastle m_TeamCastle; TeamCastle m_TeamCastle;
public: public:
Team(TeamColor color); Team(TeamColor color);
void addPlayer(Player* newPlayer); void AddPlayer(Player* newPlayer);
void removePlayer(const Player* player); void RemovePlayer(const Player* player);
TeamColor getColor() const; TeamColor GetColor() const;
const Spawn& getSpawn() const { return m_Spawn; } const Spawn& GetSpawn() const { return m_Spawn; }
Spawn& getSpawn() { return m_Spawn; } Spawn& GetSpawn() { return m_Spawn; }
const TeamCastle& getCastle() const { return m_TeamCastle; } const TeamCastle& GetCastle() const { return m_TeamCastle; }
TeamCastle& getCastle() { return m_TeamCastle; } TeamCastle& GetCastle() { return m_TeamCastle; }
std::uint8_t getPlayerCount() const; std::uint8_t GetPlayerCount() const;
}; };
typedef std::array<Team, 2> TeamList; typedef std::array<Team, 2> TeamList;

View File

@@ -1,6 +1,5 @@
#pragma once #pragma once
#include <cstdint>
#include <string> #include <string>
#include <memory> #include <memory>
@@ -18,248 +17,249 @@ class Mob;
typedef std::shared_ptr<Mob> MobPtr; typedef std::shared_ptr<Mob> MobPtr;
enum class TowerType : std::uint8_t { enum class TowerType : std::uint8_t {
Archer = 0, Archer = 0,
Ice, Ice,
Sorcerer, Sorcerer,
Zeus, Zeus,
Mage, Mage,
Artillery, Artillery,
Quake, Quake,
Poison, Poison,
Leach, Leach,
Turret, Turret,
Necromancer, Necromancer,
TowerCount TowerCount
}; };
enum class TowerSize : std::uint8_t { enum class TowerSize : std::uint8_t {
Little = 3, // 3x3 Little = 3, // 3x3
Big = 5, // 5x5 Big = 5, // 5x5
}; };
enum class TowerPath : std::uint8_t { enum class TowerPath : std::uint8_t {
Top = 0, Top = 0,
Base, // Base Path Base, // Base Path
Bottom Bottom
}; };
class TowerStats { class TowerStats {
private: private:
float m_Rate; float m_Rate;
float m_Damage; float m_Damage;
std::uint8_t m_Range; std::uint8_t m_Range;
public: public:
TowerStats(float rate, float damage, std::uint8_t range) : m_Rate(rate), m_Damage(damage), TowerStats(float rate, float damage, std::uint8_t range) : m_Rate(rate), m_Damage(damage),
m_Range(range) { m_Range(range) {
} }
float getDamageRate() const { return m_Rate; } float GetDamageRate() const { return m_Rate; }
float getDamage() const { return m_Damage; } float GetDamage() const { return m_Damage; }
std::uint8_t getRange() const { return m_Range; } std::uint8_t GetRange() const { return m_Range; }
}; };
class TowerLevel { class TowerLevel {
private: private:
// 1, 2, 3, 4 // 1, 2, 3, 4
std::uint8_t m_Level : 3; std::uint8_t m_Level : 3;
// 0 : base path 1 : top path (if there is bottom path) 2 : bottom path (if there is top path) // 0 : base path 1 : top path (if there is bottom path) 2 : bottom path (if there is top path)
TowerPath m_Path : 2; TowerPath m_Path : 2;
public: public:
TowerLevel() : m_Level(1), m_Path(TowerPath::Base) {} TowerLevel() : m_Level(1), m_Path(TowerPath::Base) {}
TowerLevel(std::uint8_t level, TowerPath path) : m_Level(level), m_Path(path) {} TowerLevel(std::uint8_t level, TowerPath path) : m_Level(level), m_Path(path) {}
std::uint8_t getLevel() const { return m_Level; } std::uint8_t GetLevel() const { return m_Level; }
TowerPath getPath() const { return m_Path; } TowerPath GetPath() const { return m_Path; }
void setLevel(std::uint8_t level) { m_Level = level; } void SetLevel(std::uint8_t level) { m_Level = level; }
void setPath(TowerPath path) { m_Path = path; } void SetPath(TowerPath path) { m_Path = path; }
// operator to sort maps // operator to sort maps
friend bool operator<(const TowerLevel& level, const TowerLevel& other) { friend bool operator<(const TowerLevel& level, const TowerLevel& other) {
return level.getLevel() + static_cast<std::uint8_t>(level.getPath()) * 4 < return level.GetLevel() + static_cast<std::uint8_t>(level.GetPath()) * 4 <
other.getLevel() + static_cast<std::uint8_t>(other.getPath()) * 4; other.GetLevel() + static_cast<std::uint8_t>(other.GetPath()) * 4;
} }
}; };
const TowerStats* getTowerStats(TowerType type, TowerLevel level); const TowerStats* GetTowerStats(TowerType type, TowerLevel level);
typedef std::uint16_t TowerID; typedef std::uint16_t TowerID;
class Tower : public utils::shape::Circle { class Tower : public utils::shape::Circle {
private: private:
TowerID m_ID; TowerID m_ID;
TowerType m_Type; TowerType m_Type;
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) : utils::shape::Circle(x + 0.5f, y + 0.5f, 0), m_ID(id), m_Type(type), 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()); SetRadius(GetStats()->GetRange());
} }
virtual TowerType getType() const = 0; virtual TowerType GetType() const = 0;
virtual TowerSize getSize() const = 0; virtual TowerSize GetSize() const = 0;
virtual void tick(std::uint64_t delta, World* world) = 0; virtual void Tick(std::uint64_t delta, World* world) = 0;
void upgrade(std::uint8_t level, TowerPath path) { void Upgrade(std::uint8_t level, TowerPath path) {
m_Level.setLevel(level); m_Level.SetLevel(level);
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()); SetRadius(GetStats()->GetRange());
} }
std::uint16_t getID() const { return m_ID; } std::uint16_t GetID() const { return m_ID; }
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; }
bool isMobInRange(MobPtr mob); bool IsMobInRange(MobPtr mob);
}; };
typedef std::shared_ptr<Tower> TowerPtr; typedef std::shared_ptr<Tower> TowerPtr;
namespace TowerFactory { namespace TowerFactory {
TowerPtr createTower(TowerType type, TowerID id, std::int32_t x, std::int32_t y, PlayerID builder); TowerPtr CreateTower(TowerType type, TowerID id, std::int32_t x, std::int32_t y, PlayerID builder);
std::string getTowerName(TowerType type); std::string GetTowerName(TowerType type);
} // namespace TowerFactory } // namespace TowerFactory
class TowerInfo { class TowerInfo {
private: private:
std::string m_Name, m_Description; std::string m_Name, m_Description;
bool m_IsBigTower; bool m_IsBigTower;
public: public:
TowerInfo(std::string&& name, std::string&& description, bool big) : m_Name(std::move(name)), TowerInfo(std::string&& name, std::string&& description, bool big) : m_Name(std::move(name)),
m_Description(std::move(description)), m_IsBigTower(big) {} m_Description(std::move(description)), m_IsBigTower(big) {
}
const std::string& getName() const { return m_Name; } const std::string& GetName() const { return m_Name; }
const std::string& getDescription() const { return m_Description; } const std::string& GetDescription() const { return m_Description; }
bool isBigTower() const { return m_IsBigTower; } bool IsBigTower() const { return m_IsBigTower; }
}; };
const TowerInfo& getTowerInfo(TowerType type); const TowerInfo& GetTowerInfo(TowerType type);
// ---------- Little Towers ---------- // ---------- Little Towers ----------
class LittleTower : public Tower { class LittleTower : public Tower {
public: public:
LittleTower(TowerID id, TowerType type, std::uint16_t x, std::uint16_t y, PlayerID builder) : Tower(id, type, x, y, builder) {} LittleTower(TowerID id, TowerType type, std::uint16_t x, std::uint16_t y, PlayerID builder) : Tower(id, type, x, y, builder) {}
virtual TowerSize getSize() const { return TowerSize::Little; } virtual TowerSize GetSize() const { return TowerSize::Little; }
virtual TowerType getType() const = 0; virtual TowerType GetType() const = 0;
virtual void tick(std::uint64_t delta, World* world) = 0; virtual void Tick(std::uint64_t delta, World* world) = 0;
}; };
class ArcherTower : public LittleTower { 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 ExplosionRadius = 1.5f;
constexpr static float FireDurationSec = 10.0f; 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);
}; };
class IceTower : public LittleTower { class IceTower : public LittleTower {
public: public:
IceTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : LittleTower(id, getType(), x, y, builder) {} IceTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : LittleTower(id, GetType(), x, y, builder) {}
virtual TowerType getType() const { return TowerType::Ice; } virtual TowerType GetType() const { return TowerType::Ice; }
virtual void tick(std::uint64_t delta, World* world); virtual void Tick(std::uint64_t delta, World* world);
}; };
class MageTower : public LittleTower { class MageTower : public LittleTower {
public: public:
MageTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : LittleTower(id, getType(), x, y, builder) {} MageTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : LittleTower(id, GetType(), x, y, builder) {}
virtual TowerType getType() const { return TowerType::Mage; } virtual TowerType GetType() const { return TowerType::Mage; }
virtual void tick(std::uint64_t delta, World* world); virtual void Tick(std::uint64_t delta, World* world);
}; };
class PoisonTower : public LittleTower { class PoisonTower : public LittleTower {
public: public:
PoisonTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : LittleTower(id, getType(), x, y, builder) {} PoisonTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : LittleTower(id, GetType(), x, y, builder) {}
virtual TowerType getType() const { return TowerType::Poison; } virtual TowerType GetType() const { return TowerType::Poison; }
virtual void tick(std::uint64_t delta, World* world); virtual void Tick(std::uint64_t delta, World* world);
}; };
class QuakeTower : public LittleTower { class QuakeTower : public LittleTower {
public: public:
QuakeTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : LittleTower(id, getType(), x, y, builder) {} QuakeTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : LittleTower(id, GetType(), x, y, builder) {}
virtual TowerType getType() const { return TowerType::Quake; } virtual TowerType GetType() const { return TowerType::Quake; }
virtual void tick(std::uint64_t delta, World* world); virtual void Tick(std::uint64_t delta, World* world);
}; };
class ArtilleryTower : public LittleTower { class ArtilleryTower : public LittleTower {
public: public:
ArtilleryTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : LittleTower(id, getType(), x, y, builder) {} ArtilleryTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : LittleTower(id, GetType(), x, y, builder) {}
virtual TowerType getType() const { return TowerType::Artillery; } virtual TowerType GetType() const { return TowerType::Artillery; }
virtual void tick(std::uint64_t delta, World* world); virtual void Tick(std::uint64_t delta, World* world);
}; };
class SorcererTower : public LittleTower { class SorcererTower : public LittleTower {
public: public:
SorcererTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : LittleTower(id, getType(), x, y, builder) {} SorcererTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : LittleTower(id, GetType(), x, y, builder) {}
virtual TowerType getType() const { return TowerType::Sorcerer; } virtual TowerType GetType() const { return TowerType::Sorcerer; }
virtual void tick(std::uint64_t delta, World* world); virtual void Tick(std::uint64_t delta, World* world);
}; };
class ZeusTower : public LittleTower { class ZeusTower : public LittleTower {
public: public:
ZeusTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : LittleTower(id, getType(), x, y, builder) {} ZeusTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : LittleTower(id, GetType(), x, y, builder) {}
virtual TowerType getType() const { return TowerType::Zeus; } virtual TowerType GetType() const { return TowerType::Zeus; }
virtual void tick(std::uint64_t delta, World* world); virtual void Tick(std::uint64_t delta, World* world);
}; };
// ---------- Big Towers ---------- // ---------- Big Towers ----------
class BigTower : public Tower { class BigTower : public Tower {
public: public:
BigTower(TowerID id, TowerType type, std::uint16_t x, std::uint16_t y, PlayerID builder) : Tower(id, type, x, y, builder) {} BigTower(TowerID id, TowerType type, std::uint16_t x, std::uint16_t y, PlayerID builder) : Tower(id, type, x, y, builder) {}
virtual TowerSize getSize() const { return TowerSize::Big; } virtual TowerSize GetSize() const { return TowerSize::Big; }
virtual TowerType getType() const = 0; virtual TowerType GetType() const = 0;
virtual void tick(std::uint64_t delta, World* world) = 0; virtual void Tick(std::uint64_t delta, World* world) = 0;
}; };
class TurretTower : public BigTower { class TurretTower : public BigTower {
public: public:
TurretTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : BigTower(id, getType(), x, y, builder) {} TurretTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : BigTower(id, GetType(), x, y, builder) {}
virtual TowerType getType() const { return TowerType::Turret; } virtual TowerType GetType() const { return TowerType::Turret; }
virtual void tick(std::uint64_t delta, World* world); virtual void Tick(std::uint64_t delta, World* world);
}; };
class NecromancerTower : public BigTower { class NecromancerTower : public BigTower {
public: public:
NecromancerTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : BigTower(id, getType(), x, y, builder) {} NecromancerTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : BigTower(id, GetType(), x, y, builder) {}
virtual TowerType getType() const { return TowerType::Necromancer; } virtual TowerType GetType() const { return TowerType::Necromancer; }
virtual void tick(std::uint64_t delta, World* world); virtual void Tick(std::uint64_t delta, World* world);
}; };
class LeachTower : public BigTower { class LeachTower : public BigTower {
public: public:
LeachTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : BigTower(id, getType(), x, y, builder) {} LeachTower(TowerID id, std::uint16_t x, std::uint16_t y, PlayerID builder) : BigTower(id, GetType(), x, y, builder) {}
virtual TowerType getType() const { return TowerType::Leach; } virtual TowerType GetType() const { return TowerType::Leach; }
virtual void tick(std::uint64_t delta, World* world); virtual void Tick(std::uint64_t delta, World* world);
}; };
} // namespace game } // namespace game

View File

@@ -2,14 +2,17 @@
#include <cstdint> #include <cstdint>
// include Log for every files
#include "misc/Log.h"
namespace td { namespace td {
namespace game { namespace game {
enum class Direction : std::uint8_t { enum class Direction : std::uint8_t {
PositiveX = 1 << 0, PositiveX = 1 << 0,
NegativeX = 1 << 1, NegativeX = 1 << 1,
PositiveY = 1 << 2, PositiveY = 1 << 2,
NegativeY = 1 << 3, NegativeY = 1 << 3,
}; };
typedef std::uint8_t PlayerID; typedef std::uint8_t PlayerID;

View File

@@ -4,7 +4,6 @@
#include <vector> #include <vector>
#include <map> #include <map>
#include <unordered_map> #include <unordered_map>
#include <glm/glm.hpp>
#include <array> #include <array>
#include "Mobs.h" #include "Mobs.h"
@@ -12,23 +11,30 @@
namespace td { namespace td {
namespace game { namespace game {
typedef std::pair<std::int16_t, std::int16_t> ChunkCoord;
struct ChunkCoord {
std::int16_t x, y;
friend bool operator==(const td::game::ChunkCoord& first, const td::game::ChunkCoord& other) {
return first.x == other.x && first.y == other.y;
}
};
} }
} }
namespace std { namespace std {
template <> template <>
struct hash<td::game::ChunkCoord> { struct hash<td::game::ChunkCoord> {
std::size_t operator()(const td::game::ChunkCoord& key) const { std::size_t operator()(const td::game::ChunkCoord& key) const noexcept {
// Compute individual hash values for first, return std::hash<std::int16_t>()(key.x << 16 | key.y);
// second and third and combine them using XOR }
// and bit shifting:
return ((std::hash<std::int16_t>()(key.first) ^ (std::hash<std::int16_t>()(key.second) << 1)) >> 1);
}
}; };
} }
namespace td { namespace td {
namespace protocol { namespace protocol {
class WorldBeginDataPacket; class WorldBeginDataPacket;
@@ -41,19 +47,15 @@ namespace game {
class Game; class Game;
enum class TileType : std::uint8_t { enum class TileType : std::uint8_t {
None = 0, None = 0,
Tower, Tower,
Walk, Walk,
Decoration, Decoration,
/*Heal, /*Heal,
Lava, Lava,
Bedrock, Bedrock,
Freeze, Freeze,
Ice,*/ Ice,*/
};
struct Color {
std::uint8_t r, g, b;
}; };
static constexpr Color BLACK{ 0, 0, 0 }; static constexpr Color BLACK{ 0, 0, 0 };
@@ -64,26 +66,26 @@ static constexpr Color GREEN{ 0, 255, 0 };
static constexpr Color BLUE{ 0, 0, 255 }; static constexpr Color BLUE{ 0, 0, 255 };
struct Tile { struct Tile {
virtual TileType getType() const = 0; virtual TileType GetType() const = 0;
}; };
struct TowerTile : Tile { struct TowerTile : Tile {
std::uint8_t color_palette_ref; std::uint8_t color_palette_ref;
TeamColor team_owner; TeamColor team_owner;
virtual TileType getType() const { return TileType::Tower; } virtual TileType GetType() const { return TileType::Tower; }
}; };
struct WalkableTile : Tile { struct WalkableTile : Tile {
Direction direction; Direction direction;
virtual TileType getType() const { return TileType::Walk; } virtual TileType GetType() const { return TileType::Walk; }
}; };
struct DecorationTile : Tile { struct DecorationTile : Tile {
std::uint16_t color_palette_ref; std::uint16_t color_palette_ref;
virtual TileType getType() const { return TileType::Decoration; } virtual TileType GetType() const { return TileType::Decoration; }
}; };
typedef std::shared_ptr<Tile> TilePtr; typedef std::shared_ptr<Tile> TilePtr;
@@ -91,22 +93,23 @@ typedef std::vector<std::uint16_t> ChunkPalette;
typedef std::shared_ptr<WalkableTile> WalkableTilePtr; typedef std::shared_ptr<WalkableTile> WalkableTilePtr;
typedef std::array<std::uint16_t, 32 * 32> ChunkData;
typedef std::uint32_t TileIndex; typedef std::uint32_t TileIndex;
//32 x 32 area //32 x 32 area
struct Chunk { struct Chunk {
enum { ChunkWidth = 32, ChunkHeight = 32, ChunkSize = ChunkWidth * ChunkHeight }; enum { ChunkWidth = 32, ChunkHeight = 32, ChunkSize = ChunkWidth * ChunkHeight };
// stores index of tile palette typedef std::array<std::uint16_t, ChunkSize> ChunkData;
ChunkData tiles{ 0 };
ChunkPalette palette;
TileIndex getTileIndex(std::uint16_t tileNumber) const { // stores index of tile palette
TileIndex chunkPaletteIndex = tiles.at(tileNumber); ChunkData tiles{ 0 };
if (chunkPaletteIndex == 0) // index 0 means empty tile index 1 = first tile ChunkPalette palette;
return 0;
return palette.at(chunkPaletteIndex); TileIndex GetTileIndex(std::uint16_t tileNumber) const {
} TileIndex chunkPaletteIndex = tiles.at(tileNumber);
if (chunkPaletteIndex == 0) // index 0 means empty tile index 1 = first tile
return 0;
return palette.at(chunkPaletteIndex);
}
}; };
typedef std::shared_ptr<Chunk> ChunkPtr; typedef std::shared_ptr<Chunk> ChunkPtr;
@@ -123,120 +126,119 @@ typedef std::vector<TowerPtr> TowerList;
class WorldListener { class WorldListener {
public: public:
WorldListener() {} WorldListener() {}
virtual void OnTowerAdd(TowerPtr tower) {} virtual void OnTowerAdd(TowerPtr tower) {}
virtual void OnTowerRemove(TowerPtr tower) {} virtual void OnTowerRemove(TowerPtr tower) {}
virtual void OnArcherTowerShot(MobPtr target, ArcherTower* shooter) {} virtual void OnArcherTowerShot(MobPtr target, ArcherTower* shooter) {}
virtual void OnArrowShot(MobPtr target, bool fire, Tower* shooter) {} virtual void OnArrowShot(MobPtr target, bool fire, Tower* shooter) {}
virtual void OnExplosion(utils::shape::Circle explosion, float centerDamage, Tower* shooter) {} virtual void OnExplosion(utils::shape::Circle explosion, float centerDamage, Tower* shooter) {}
}; };
typedef utils::ObjectNotifier<WorldListener> WorldNotifier; typedef utils::ObjectNotifier<WorldListener> WorldNotifier;
class World : public WorldListener, public MobListener { class World : public WorldListener, public MobListener {
protected: protected:
TowerTileColorPalette m_TowerPlacePalette; TowerTileColorPalette m_TowerPlacePalette;
Color m_WalkablePalette; Color m_WalkablePalette;
std::vector<Color> m_DecorationPalette; std::vector<Color> m_DecorationPalette;
Color m_Background; Color m_Background;
std::unordered_map<ChunkCoord, ChunkPtr> m_Chunks; std::unordered_map<ChunkCoord, ChunkPtr> m_Chunks;
SpawnColorPalette m_SpawnColorPalette; SpawnColorPalette m_SpawnColorPalette;
TilePalette m_TilePalette; TilePalette m_TilePalette;
MobList m_Mobs; MobList m_Mobs;
TowerList m_Towers; TowerList m_Towers;
Game* m_Game; Game* m_Game;
WorldNotifier m_WorldNotifier; WorldNotifier m_WorldNotifier;
MobNotifier m_MobNotifier; MobNotifier m_MobNotifier;
public: public:
World(Game* game); World(Game* game);
bool loadMap(const protocol::WorldBeginDataPacket* worldHeader); bool LoadMap(const protocol::WorldBeginDataPacket* worldHeader);
bool loadMap(const protocol::WorldDataPacket* worldData); bool LoadMap(const protocol::WorldDataPacket* worldData);
bool loadMapFromFile(const std::string& fileName); bool LoadMapFromFile(const std::string& fileName);
bool saveMap(const std::string& fileName) const; bool SaveMap(const std::string& fileName) const;
void tick(std::uint64_t delta); void Tick(std::uint64_t delta);
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); 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;
const TowerTileColorPalette& getTowerTileColorPalette() const { return m_TowerPlacePalette; } const TowerTileColorPalette& GetTowerTileColorPalette() const { return m_TowerPlacePalette; }
const Color& getWalkableTileColor() const { return m_WalkablePalette; } const Color& GetWalkableTileColor() const { return m_WalkablePalette; }
const std::vector<Color>& getDecorationPalette() const { return m_DecorationPalette; } const std::vector<Color>& GetDecorationPalette() const { return m_DecorationPalette; }
const Color& getBackgroundColor() const { return m_Background; } const Color& GetBackgroundColor() const { return m_Background; }
const TilePalette& getTilePalette() const { return m_TilePalette; } const TilePalette& GetTilePalette() const { return m_TilePalette; }
TilePtr getTilePtr(TileIndex index) const { TilePtr GetTilePtr(TileIndex index) const {
if (index == 0) if (index == 0)
return nullptr; return nullptr;
return m_TilePalette.at(index - 1); return m_TilePalette.at(index - 1);
} }
bool CanPlaceLittleTower(const glm::vec2& worldPos, PlayerID player) const; bool CanPlaceLittleTower(const Vec2f& worldPos, PlayerID player) const;
bool CanPlaceBigTower(const glm::vec2& worldPos, PlayerID player) const; bool CanPlaceBigTower(const Vec2f& worldPos, PlayerID player) const;
TowerPtr getTower(const glm::vec2& position) const; // returns null if no tower is here TowerPtr GetTower(const Vec2f& position) const; // returns null if no tower is here
const std::unordered_map<ChunkCoord, ChunkPtr>& getChunks() const { return m_Chunks; } const std::unordered_map<ChunkCoord, ChunkPtr>& GetChunks() const { return m_Chunks; }
const Color& getSpawnColor(TeamColor color) const { return m_SpawnColorPalette[(std::size_t)color]; } const Color& GetSpawnColor(TeamColor color) const { return m_SpawnColorPalette[static_cast<std::size_t>(color)]; }
const SpawnColorPalette& getSpawnColors() const { return m_SpawnColorPalette; } const SpawnColorPalette& GetSpawnColors() const { return m_SpawnColorPalette; }
const MobList& getMobList() const { return m_Mobs; } const MobList& GetMobList() const { return m_Mobs; }
MobList& getMobList() { return m_Mobs; } MobList& GetMobList() { return m_Mobs; }
const Color* getTileColor(TilePtr tile) const; const Color* GetTileColor(TilePtr tile) const;
Team& getRedTeam(); Team& GetRedTeam();
const Team& getRedTeam() const; const Team& GetRedTeam() const;
Team& getBlueTeam(); Team& GetBlueTeam();
const Team& getBlueTeam() const; const Team& GetBlueTeam() const;
Team& getTeam(TeamColor team); Team& GetTeam(TeamColor team);
const Team& getTeam(TeamColor team) const; const Team& GetTeam(TeamColor team) const;
const TeamList& getTeams() const; const TeamList& GetTeams() const;
const TowerList& getTowers() const { return m_Towers; }; const TowerList& GetTowers() const { return m_Towers; }
TowerPtr getTowerById(TowerID tower); TowerPtr GetTowerById(TowerID tower);
const Player* getPlayerById(PlayerID id) const; const Player* GetPlayerById(PlayerID id) const;
WorldNotifier& getWorldNotifier() { return m_WorldNotifier; } WorldNotifier& GetWorldNotifier() { return m_WorldNotifier; }
MobNotifier& getMobNotifier() { return m_MobNotifier; } MobNotifier& GetMobNotifier() { return m_MobNotifier; }
// WorldListener // WorldListener
virtual void OnArcherTowerShot(MobPtr target, ArcherTower* shooter); virtual void OnArcherTowerShot(MobPtr target, ArcherTower* shooter) override;
virtual void OnArrowShot(MobPtr target, bool fire, Tower* shooter) override;
virtual void OnExplosion(utils::shape::Circle explosion, float centerDamage, Tower* shooter) override;
virtual void OnArrowShot(MobPtr target, bool fire, Tower* shooter); // MobListener
virtual void OnExplosion(utils::shape::Circle explosion, float centerDamage, Tower* shooter);
// MobListener virtual void OnMobDamage(Mob* target, float damage, Tower* source) override;
virtual void OnMobCastleDamage(Mob* damager, TeamCastle* enemyCastle, float damage) override;
virtual void OnMobDamage(Mob* target, float damage, Tower* source);
virtual void OnMobCastleDamage(Mob* damager, TeamCastle* enemyCastle, float damage);
private: private:
void tickMobs(std::uint64_t delta); void TickMobs(std::uint64_t delta);
void cleanDeadMobs(); void CleanDeadMobs();
}; };
} // namespace game } // namespace game

View File

@@ -17,36 +17,38 @@ namespace client {
class Client { class Client {
private: private:
render::Renderer* m_Renderer; render::Renderer* m_Renderer;
ClientConnexion m_Connexion; ClientConnexion m_Connexion;
std::unique_ptr<ClientGame> m_Game; std::unique_ptr<ClientGame> m_Game;
bool m_Connected; bool m_Connected;
public: public:
Client(render::Renderer* renderer) : m_Renderer(renderer), m_Game(std::make_unique<ClientGame>(this)), m_Connected(false) {} Client(render::Renderer* renderer) : m_Renderer(renderer), m_Game(std::make_unique<ClientGame>(this)), m_Connected(false) {}
const ClientGame& getGame() const { return *m_Game; } const ClientGame& GetGame() const { return *m_Game; }
const ClientConnexion& getConnexion() const { return m_Connexion; } const ClientConnexion& GetConnexion() const { return m_Connexion; }
render::Renderer* getRenderer() const { return m_Renderer; } render::Renderer* GetRenderer() const { return m_Renderer; }
ClientGame& getGame() { return *m_Game; } ClientGame& GetGame() { return *m_Game; }
ClientConnexion& getConnexion() { return m_Connexion; } ClientConnexion& GetConnexion() { return m_Connexion; }
void tick(std::uint64_t delta); const game::Player* GetPlayer() { return m_Game->GetPlayer(); }
void render(); void Tick(std::uint64_t delta);
bool connect(const network::IPAddresses& addresses, std::uint16_t port); void Render();
void closeConnection();
bool isConnected() const { return m_Connexion.getSocketStatus() == network::Socket::Connected; } bool Connect(const network::IPAddresses& addresses, std::uint16_t port);
void CloseConnection();
void selectTeam(game::TeamColor team); bool IsConnected() const { return m_Connexion.GetSocketStatus() == network::Socket::Connected; }
void sendMobs(const std::vector<protocol::MobSend>& mobSends);
void placeTower(game::TowerType type, const glm::vec2& position); void SelectTeam(game::TeamColor team);
void upgradeTower(game::TowerID tower, game::TowerLevel level); void SendMobs(const std::vector<protocol::MobSend>& mobSends);
void removeTower(game::TowerID tower); void PlaceTower(game::TowerType type, const Vec2f& position);
void UpgradeTower(game::TowerID tower, game::TowerLevel level);
void RemoveTower(game::TowerID tower);
private: private:
void reset(); void Reset();
}; };
} // namespace client } // namespace client

View File

@@ -9,28 +9,30 @@ namespace client {
class ClientConnexion : public protocol::Connexion { class ClientConnexion : public protocol::Connexion {
private: private:
std::uint8_t m_ConnectionID; std::uint8_t m_ConnectionID;
std::string m_DisconnectReason; std::string m_DisconnectReason;
float m_ServerTPS; float m_ServerTPS;
int m_Ping = 0; float m_ServerMSPT;
int m_Ping = 0;
public: public:
ClientConnexion(); ClientConnexion();
virtual bool updateSocket(); virtual bool UpdateSocket();
virtual void HandlePacket(const protocol::KeepAlivePacket* packet); virtual void HandlePacket(const protocol::KeepAlivePacket* packet) override;
virtual void HandlePacket(const protocol::ConnexionInfoPacket* packet); virtual void HandlePacket(const protocol::ConnexionInfoPacket* packet) override;
virtual void HandlePacket(const protocol::DisconnectPacket* packet); virtual void HandlePacket(const protocol::DisconnectPacket* packet) override;
virtual void HandlePacket(const protocol::ServerTpsPacket* packet); virtual void HandlePacket(const protocol::ServerTpsPacket* packet) override;
const std::string& getDisconnectReason() const { return m_DisconnectReason; } const std::string& GetDisconnectReason() const { return m_DisconnectReason; }
float getServerTPS() const { return m_ServerTPS; } float GetServerTPS() const { return m_ServerTPS; }
int getServerPing() const { return m_Ping; } float GetServerMSPT() const { return m_ServerMSPT; }
int GetServerPing() const { return m_Ping; }
REMOVE_COPY(ClientConnexion); REMOVE_COPY(ClientConnexion);
private: private:
void registerHandlers(); void RegisterHandlers();
void login(); void Login();
}; };
} // namespace client } // namespace client

View File

@@ -16,39 +16,40 @@ class Client;
class ClientGame : public protocol::PacketHandler, public game::Game { class ClientGame : public protocol::PacketHandler, public game::Game {
private: private:
Client* m_Client; Client* m_Client;
std::uint8_t m_ConnexionID; std::uint8_t m_ConnexionID;
std::uint32_t m_LobbyTime = 0; std::uint32_t m_LobbyTime = 0;
game::Player* m_Player = nullptr; game::Player* m_Player = nullptr;
render::Renderer* m_Renderer; render::Renderer* m_Renderer;
client::WorldClient m_WorldClient; client::WorldClient m_WorldClient;
render::WorldRenderer m_WorldRenderer; render::WorldRenderer m_WorldRenderer;
public: public:
ClientGame(Client* client); ClientGame(Client* client);
virtual ~ClientGame(); virtual ~ClientGame();
virtual void tick(std::uint64_t delta); virtual void Tick(std::uint64_t delta);
void renderWorld(); void RenderWorld();
std::uint32_t getLobbyTime() const { return m_LobbyTime; } std::uint32_t GetLobbyTime() const { return m_LobbyTime; }
const game::Player* getPlayer() const { return m_Player; } const game::Player* GetPlayer() const { return m_Player; }
const WorldClient& getWorld() const { return m_WorldClient; } const WorldClient& GetWorld() const { return m_WorldClient; }
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& getWorldClient() { return m_WorldClient; } WorldClient& GetWorldClient() { return m_WorldClient; }
virtual void HandlePacket(const protocol::ConnexionInfoPacket* packet); virtual void HandlePacket(const protocol::ConnexionInfoPacket* packet) override;
virtual void HandlePacket(const protocol::PlayerJoinPacket* packet); virtual void HandlePacket(const protocol::PlayerJoinPacket* packet) override;
virtual void HandlePacket(const protocol::PlayerLeavePacket* packet); virtual void HandlePacket(const protocol::PlayerLeavePacket* packet) override;
virtual void HandlePacket(const protocol::PlayerListPacket* packet); virtual void HandlePacket(const protocol::PlayerListPacket* packet) override;
virtual void HandlePacket(const protocol::UpdatePlayerTeamPacket* packet); virtual void HandlePacket(const protocol::UpdatePlayerTeamPacket* packet) override;
virtual void HandlePacket(const protocol::UpdateGameStatePacket* packet); virtual void HandlePacket(const protocol::UpdateGameStatePacket* packet) override;
virtual void HandlePacket(const protocol::UpdateLobbyTimePacket* packet); virtual void HandlePacket(const protocol::UpdateLobbyTimePacket* packet) override;
virtual void HandlePacket(const protocol::UpdateMoneyPacket* packet); virtual void HandlePacket(const protocol::UpdateMoneyPacket* packet) override;
virtual void HandlePacket(const protocol::DisconnectPacket* packet); virtual void HandlePacket(const protocol::UpdateExpPacket* packet) override;
virtual void HandlePacket(const protocol::WorldDataPacket* packet); virtual void HandlePacket(const protocol::DisconnectPacket* packet) override;
virtual void HandlePacket(const protocol::WorldDataPacket* packet) override;
}; };

View File

@@ -10,18 +10,18 @@ class ClientGame;
class WorldClient : public game::World, public protocol::PacketHandler { class WorldClient : public game::World, public protocol::PacketHandler {
private: private:
ClientGame* m_Game; ClientGame* m_Game;
public: public:
WorldClient(ClientGame* game); WorldClient(ClientGame* game);
virtual void HandlePacket(const protocol::WorldBeginDataPacket* packet); virtual void HandlePacket(const protocol::WorldBeginDataPacket* packet) override;
virtual void HandlePacket(const protocol::WorldDataPacket* packet); virtual void HandlePacket(const protocol::WorldDataPacket* packet) override;
virtual void HandlePacket(const protocol::SpawnMobPacket* packet); virtual void HandlePacket(const protocol::SpawnMobPacket* packet) override;
virtual void HandlePacket(const protocol::UpgradeTowerPacket* packet); virtual void HandlePacket(const protocol::UpgradeTowerPacket* packet) override;
virtual void HandlePacket(const protocol::WorldAddTowerPacket* packet); virtual void HandlePacket(const protocol::WorldAddTowerPacket* packet) override;
virtual void HandlePacket(const protocol::RemoveTowerPacket* packet); virtual void HandlePacket(const protocol::RemoveTowerPacket* packet) override;
virtual void HandlePacket(const protocol::UpdateMobStatesPacket* packet); virtual void HandlePacket(const protocol::UpdateMobStatesPacket* packet) override;
virtual void HandlePacket(const protocol::UpdateCastleLifePacket* packet); virtual void HandlePacket(const protocol::UpdateCastleLifePacket* packet) override;
}; };

View File

@@ -11,23 +11,23 @@ class Server;
class Lobby { class Lobby {
private: private:
Server* m_Server; Server* m_Server;
bool m_GameStarted = false; bool m_GameStarted = false;
std::uint64_t m_StartTimerTime = 0; std::uint64_t m_StartTimerTime = 0;
std::vector<std::uint8_t> m_Players; std::vector<std::uint8_t> m_Players;
utils::AutoTimer m_Timer; utils::AutoTimer m_Timer;
public: public:
Lobby(Server* server); Lobby(Server* server);
void OnPlayerJoin(std::uint8_t playerID); void OnPlayerJoin(std::uint8_t playerID);
void OnPlayerLeave(std::uint8_t playerID); void OnPlayerLeave(std::uint8_t playerID);
void sendTimeRemaining(); void SendTimeRemaining();
void tick(); void Tick();
//static constexpr int LobbyWaitingTime = 2 * 60 * 1000; // in millis //static constexpr int LobbyWaitingTime = 2 * 60 * 1000; // in millis
static constexpr int LobbyWaitingTime = 5 * 1000; // in millis static constexpr int LobbyWaitingTime = 5 * 1000; // in millis
}; };
} // namespace server } // namespace server

View File

@@ -1,6 +1,5 @@
#pragma once #pragma once
#include <cstdint>
#include <map> #include <map>
#include <thread> #include <thread>
@@ -22,80 +21,84 @@ typedef std::map<std::uint8_t, ServerConnexion> ConnexionMap;
class TickCounter { class TickCounter {
private: private:
float m_TPS; float m_TPS;
std::uint64_t m_LastTPSTime; float m_MSPT;
std::uint8_t m_TickCount; std::uint64_t m_LastTPSTime;
std::uint8_t m_TickCount;
public: public:
TickCounter() {} TickCounter() {}
void reset() { void Reset() {
m_TPS = SERVER_TPS; m_TPS = SERVER_TPS;
m_LastTPSTime = utils::getTime(); m_LastTPSTime = utils::GetTime();
m_TickCount = 0; m_TickCount = 0;
} }
bool update() { // return true when tps is updated bool Update() { // return true when tps is updated
m_TickCount++; m_TickCount++;
if (m_TickCount >= SERVER_TPS) { if (m_TickCount >= SERVER_TPS) {
std::uint64_t timeElapsedSinceLast20Ticks = td::utils::getTime() - m_LastTPSTime; std::uint64_t timeElapsedSinceLast20Ticks = td::utils::GetTime() - m_LastTPSTime;
m_TPS = (float)SERVER_TPS / (float)(timeElapsedSinceLast20Ticks / 1000.0f); m_TPS = static_cast<float>(SERVER_TPS) / static_cast<float>(timeElapsedSinceLast20Ticks / 1000.0f);
m_TickCount = 0; m_TickCount = 0;
m_LastTPSTime = td::utils::getTime(); m_LastTPSTime = td::utils::GetTime();
return true; return true;
} }
return false; return false;
} }
float getTPS() const { return m_TPS; } float GetTPS() const { return m_TPS; }
float GetMSPT() const { return m_MSPT; }
void SetMSPT(float mspt) { m_MSPT = mspt; }
}; };
class Server { class Server {
private: private:
network::TCPListener m_Listener; network::TCPListener m_Listener;
ConnexionMap m_Connections; ConnexionMap m_Connections;
ServerGame m_Game{ this }; ServerGame m_Game{ this };
Lobby m_Lobby{ this }; Lobby m_Lobby{ this };
TickCounter m_TickCounter; TickCounter m_TickCounter;
std::thread m_Thread; std::thread m_Thread;
bool m_ServerRunning; bool m_ServerRunning;
public: public:
Server(const std::string& worldFilePath); Server(const std::string& worldFilePath);
virtual ~Server(); virtual ~Server();
bool start(std::uint16_t port); bool Start(std::uint16_t port);
void stop(); // force the server to stop void Stop(); // force the server to stop
void close(); // at the end of a game void Close(); // at the end of a game
void removeConnexion(std::uint8_t connexionID); void RemoveConnexion(std::uint8_t connexionID);
void broadcastPacket(const protocol::Packet* packet); void BroadcastPacket(const protocol::Packet* packet);
float getTPS() const { return m_TickCounter.getTPS(); } float GetTPS() const { return m_TickCounter.GetTPS(); }
bool isRunning() { return m_ServerRunning; } bool IsRunning() { return m_ServerRunning; }
const ServerGame& getGame() const { return m_Game; } const ServerGame& GetGame() const { return m_Game; }
ServerGame& getGame() { return m_Game; } ServerGame& GetGame() { return m_Game; }
const Lobby& getLobby() const { return m_Lobby; } const Lobby& GetLobby() const { return m_Lobby; }
const ConnexionMap& getConnexions() const { return m_Connections; } const ConnexionMap& GetConnexions() const { return m_Connections; }
ConnexionMap& getConnexions() { return m_Connections; } ConnexionMap& GetConnexions() { return m_Connections; }
const game::PlayerList& getPlayers() const { return m_Game.getPlayers(); } const game::PlayerList& GetPlayers() const { return m_Game.GetPlayers(); }
game::PlayerList& getPlayers() { return m_Game.getPlayers(); } game::PlayerList& GetPlayers() { return m_Game.GetPlayers(); }
private: private:
void accept(); void Accept();
void updateSockets(); void UpdateSockets();
void clean(); void Clean();
void startThread(); void StartThread();
void stopThread(); void StopThread();
void tick(std::uint64_t delta); void Tick(std::uint64_t delta);
void OnPlayerJoin(std::uint8_t id); void OnPlayerJoin(std::uint8_t id);
void OnPlayerLeave(std::uint8_t id); void OnPlayerLeave(std::uint8_t id);
}; };
} // namespace server } // namespace server

View File

@@ -11,49 +11,48 @@ namespace server {
class Server; class Server;
struct KeepAlive struct KeepAlive {
{ std::uint64_t keepAliveID = 0;
std::uint64_t keepAliveID = 0; std::uint64_t sendTime;
std::uint64_t sendTime; bool recievedResponse = false;
bool recievedResponse = false;
}; };
class ServerConnexion : public protocol::Connexion { class ServerConnexion : public protocol::Connexion {
private: private:
Server* m_Server = nullptr; Server* m_Server = nullptr;
std::uint8_t m_ID; std::uint8_t m_ID;
KeepAlive m_KeepAlive; KeepAlive m_KeepAlive;
game::Player* m_Player; game::Player* m_Player;
public: public:
ServerConnexion(); ServerConnexion();
ServerConnexion(network::TCPSocket& socket, std::uint8_t id); ServerConnexion(network::TCPSocket& socket, std::uint8_t id);
ServerConnexion(ServerConnexion&& move); ServerConnexion(ServerConnexion&& move);
virtual ~ServerConnexion(); virtual ~ServerConnexion();
void setServer(Server* server); void SetServer(Server* server);
virtual void HandlePacket(const protocol::PlayerLoginPacket* packet); virtual void HandlePacket(const protocol::PlayerLoginPacket* packet) override;
virtual void HandlePacket(const protocol::KeepAlivePacket* packet); virtual void HandlePacket(const protocol::KeepAlivePacket* packet) override;
virtual void HandlePacket(const protocol::SelectTeamPacket* packet); virtual void HandlePacket(const protocol::SelectTeamPacket* packet) override;
virtual void HandlePacket(const protocol::DisconnectPacket* packet); virtual void HandlePacket(const protocol::DisconnectPacket* packet) override;
virtual void HandlePacket(const protocol::PlaceTowerPacket* packet); virtual void HandlePacket(const protocol::PlaceTowerPacket* packet) override;
virtual void HandlePacket(const protocol::SendMobsPacket* packet); virtual void HandlePacket(const protocol::SendMobsPacket* packet) override;
virtual void HandlePacket(const protocol::UpgradeTowerPacket* packet); virtual void HandlePacket(const protocol::UpgradeTowerPacket* packet) override;
virtual void HandlePacket(const protocol::RemoveTowerPacket* packet); virtual void HandlePacket(const protocol::RemoveTowerPacket* packet) override;
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; }
game::Player* getPlayer() { return m_Player; } game::Player* GetPlayer() { return m_Player; }
virtual bool updateSocket(); virtual bool UpdateSocket();
REMOVE_COPY(ServerConnexion); REMOVE_COPY(ServerConnexion);
private: private:
void registerHandlers(); void RegisterHandlers();
void checkKeepAlive(); void CheckKeepAlive();
void sendKeepAlive(); void SendKeepAlive();
void initConnection(); void InitConnection();
}; };
} // namespace server } // namespace server

View File

@@ -11,31 +11,32 @@ class Server;
class ServerGame : public game::Game, public game::GameListener { class ServerGame : public game::Game, public game::GameListener {
private: private:
Server* m_Server; Server* m_Server;
ServerWorld m_ServerWorld; ServerWorld m_ServerWorld;
utils::AutoTimer m_GoldMineTimer; utils::AutoTimer m_GoldMineTimer;
utils::AutoTimer m_MobStatesTimer; utils::AutoTimer m_MobStatesTimer;
utils::CooldownTimer m_EndGameCooldown; utils::CooldownTimer m_EndGameCooldown;
public: public:
ServerGame(Server* server); ServerGame(Server* server);
~ServerGame() {} ~ServerGame() {}
ServerWorld* getServerWorld() { return &m_ServerWorld; } ServerWorld* GetServerWorld() { return &m_ServerWorld; }
virtual void tick(std::uint64_t delta); virtual void Tick(std::uint64_t delta);
void startGame(); void StartGame();
// GameListener // GameListener
virtual void OnGameStateUpdate(game::GameState newState); virtual void OnGameStateUpdate(game::GameState newState) override;
virtual void OnGameBegin(); virtual void OnGameBegin() override;
virtual void OnGameEnd(); virtual void OnGameEnd() override;
virtual void OnGameClose(); virtual void OnGameClose() override;
private: private:
void balanceTeams(); void BalanceTeams();
void updateMobStates(); void InitPlayerStats();
void updateGoldMines(); void UpdateMobStates();
void updatePlayerStats(); void UpdateGoldMines();
void UpdatePlayerStats();
}; };
} // namespace game } // namespace game

View File

@@ -10,20 +10,19 @@ class ServerGame;
class ServerWorld : public game::World { class ServerWorld : public game::World {
private: private:
game::MobID m_CurrentMobID; game::MobID m_CurrentMobID;
game::TowerID m_CurrentTowerID; game::TowerID m_CurrentTowerID;
Server* m_Server; Server* m_Server;
public: public:
static constexpr float MobSpawnBorder = 0.01f; static constexpr float MobSpawnBorder = 0.01f;
ServerWorld(Server* server, ServerGame* game); ServerWorld(Server* server, ServerGame* game);
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 OnMobDie(game::Mob* mob); virtual void OnMobDie(game::Mob* mob) override;
virtual void OnMobCastleDamage(game::Mob* damager, game::TeamCastle* enemyCastle, float damage) override;
virtual void OnMobCastleDamage(game::Mob* damager, game::TeamCastle* enemyCastle, float damage);
}; };

View File

@@ -6,6 +6,9 @@
namespace td { namespace td {
namespace utils { namespace utils {
std::uint64_t Inflate(const std::string& source, std::string& dest);
std::uint64_t Deflate(const std::string& source, std::string& dest);
DataBuffer Compress(const DataBuffer& buffer); DataBuffer Compress(const DataBuffer& buffer);
DataBuffer Decompress(DataBuffer& buffer); DataBuffer Decompress(DataBuffer& buffer);
DataBuffer Decompress(DataBuffer& buffer, std::uint64_t packetLength); DataBuffer Decompress(DataBuffer& buffer, std::uint64_t packetLength);

View File

@@ -1,5 +1,4 @@
#ifndef MCLIB_COMMON_DATA_BUFFER_H_ #pragma once
#define MCLIB_COMMON_DATA_BUFFER_H_
#include <vector> #include <vector>
#include <algorithm> #include <algorithm>
@@ -11,157 +10,168 @@ namespace td {
class DataBuffer { class DataBuffer {
private: private:
typedef std::vector<std::uint8_t> Data; typedef std::vector<std::uint8_t> Data;
Data m_Buffer; Data m_Buffer;
std::size_t m_ReadOffset = 0; std::size_t m_ReadOffset;
public: public:
typedef Data::iterator iterator; typedef Data::iterator iterator;
typedef Data::const_iterator const_iterator; typedef Data::const_iterator const_iterator;
typedef Data::reference reference; typedef Data::reference reference;
typedef Data::const_reference const_reference; typedef Data::const_reference const_reference;
DataBuffer(); DataBuffer();
DataBuffer(const DataBuffer& other); DataBuffer(const DataBuffer& other);
DataBuffer(const DataBuffer& other, std::size_t offset); DataBuffer(const DataBuffer& other, Data::difference_type offset);
DataBuffer(DataBuffer&& other); DataBuffer(DataBuffer&& other);
DataBuffer(const std::string& str); DataBuffer(const std::string& str);
DataBuffer& operator=(const DataBuffer& other); DataBuffer& operator=(const DataBuffer& other);
DataBuffer& operator=(DataBuffer&& other); DataBuffer& operator=(DataBuffer&& other);
template <typename T> template <typename T>
void Append(T data) { void Append(T data) {
std::size_t size = sizeof(data); std::size_t size = sizeof(data);
std::size_t end_pos = m_Buffer.size(); std::size_t end_pos = m_Buffer.size();
m_Buffer.resize(m_Buffer.size() + size); m_Buffer.resize(m_Buffer.size() + size);
memcpy(&m_Buffer[end_pos], &data, size); memcpy(&m_Buffer[end_pos], &data, size);
} }
template <typename T> template <typename T>
DataBuffer& operator<<(T data) { DataBuffer& operator<<(T data) {
// Switch to big endian // Switch to big endian
//std::reverse((std::uint8_t*)&data, (std::uint8_t*)&data + sizeof(T)); //std::reverse((std::uint8_t*)&data, (std::uint8_t*)&data + sizeof(T));
Append(data); Append(data);
return *this; return *this;
} }
DataBuffer& operator<<(std::string str) { DataBuffer& operator<<(std::string str) {
m_Buffer.insert(m_Buffer.end(), str.begin(), str.end()); m_Buffer.insert(m_Buffer.end(), str.begin(), str.end());
return *this; return *this;
} }
DataBuffer& operator<<(DataBuffer& data) { DataBuffer& operator<<(DataBuffer& data) {
m_Buffer.insert(m_Buffer.end(), data.begin(), data.end()); m_Buffer.insert(m_Buffer.end(), data.begin(), data.end());
return *this; return *this;
} }
DataBuffer& operator<<(const DataBuffer& data) { DataBuffer& operator<<(const DataBuffer& data) {
m_Buffer.insert(m_Buffer.end(), data.begin(), data.end()); m_Buffer.insert(m_Buffer.end(), data.begin(), data.end());
return *this; return *this;
} }
template <typename T> template <typename T>
DataBuffer& operator>>(T& data) { DataBuffer& operator>>(T& data) {
assert(m_ReadOffset + sizeof(T) <= GetSize()); assert(m_ReadOffset + sizeof(T) <= GetSize());
data = *(T*)&m_Buffer[m_ReadOffset]; data = *(reinterpret_cast<T*>(&m_Buffer[m_ReadOffset]));
//std::reverse((std::uint8_t*)&data, (std::uint8_t*)&data + sizeof(T)); //std::reverse((std::uint8_t*)&data, (std::uint8_t*)&data + sizeof(T));
m_ReadOffset += sizeof(T); m_ReadOffset += sizeof(T);
return *this; return *this;
} }
DataBuffer& operator>>(DataBuffer& data) { DataBuffer& operator>>(DataBuffer& data) {
data.Resize(GetSize() - m_ReadOffset); data.Resize(GetSize() - m_ReadOffset);
std::copy(m_Buffer.begin() + m_ReadOffset, m_Buffer.end(), data.begin()); std::copy(m_Buffer.begin() + static_cast<Data::difference_type>(m_ReadOffset), m_Buffer.end(), data.begin());
m_ReadOffset = m_Buffer.size(); m_ReadOffset = m_Buffer.size();
return *this; return *this;
} }
DataBuffer& operator>>(std::string& str) { DataBuffer& operator>>(std::string& str) {
std::size_t stringSize = strlen((const char*)m_Buffer.data() + m_ReadOffset) + 1; // including null character std::size_t stringSize = strlen(reinterpret_cast<const char*>(m_Buffer.data()) + m_ReadOffset) + 1; // including null character
str.resize(stringSize); str.resize(stringSize);
std::copy(m_Buffer.begin() + m_ReadOffset, m_Buffer.begin() + m_ReadOffset + stringSize, str.begin()); std::copy(m_Buffer.begin() + static_cast<Data::difference_type>(m_ReadOffset),
m_ReadOffset += stringSize; m_Buffer.begin() + static_cast<Data::difference_type>(m_ReadOffset + stringSize), str.begin());
return *this; m_ReadOffset += stringSize;
} return *this;
}
void ReadSome(char* buffer, std::size_t amount) { void WriteSome(const char* buffer, std::size_t amount) {
assert(m_ReadOffset + amount <= GetSize()); std::size_t end_pos = m_Buffer.size();
std::copy_n(m_Buffer.begin() + m_ReadOffset, amount, buffer); m_Buffer.resize(m_Buffer.size() + amount);
m_ReadOffset += amount; memcpy(m_Buffer.data() + end_pos, buffer, amount);
} }
void ReadSome(std::uint8_t* buffer, std::size_t amount) { void WriteSome(const std::uint8_t* buffer, std::size_t amount) {
assert(m_ReadOffset + amount <= GetSize()); std::size_t end_pos = m_Buffer.size();
std::copy_n(m_Buffer.begin() + m_ReadOffset, amount, buffer); m_Buffer.resize(m_Buffer.size() + amount);
m_ReadOffset += amount; memcpy(m_Buffer.data() + end_pos, buffer, amount);
} }
void ReadSome(DataBuffer& buffer, std::size_t amount) { void ReadSome(char* buffer, std::size_t amount) {
assert(m_ReadOffset + amount <= GetSize()); assert(m_ReadOffset + amount <= GetSize());
buffer.Resize(amount); std::copy_n(m_Buffer.begin() + static_cast<Data::difference_type>(m_ReadOffset), amount, buffer);
std::copy_n(m_Buffer.begin() + m_ReadOffset, amount, buffer.begin()); m_ReadOffset += amount;
m_ReadOffset += amount; }
}
void ReadSome(std::string& buffer, std::size_t amount) { void ReadSome(std::uint8_t* buffer, std::size_t amount) {
assert(m_ReadOffset + amount <= GetSize()); assert(m_ReadOffset + amount <= GetSize());
buffer.resize(amount); std::copy_n(m_Buffer.begin() + static_cast<Data::difference_type>(m_ReadOffset), amount, buffer);
std::copy_n(m_Buffer.begin() + m_ReadOffset, amount, buffer.begin()); m_ReadOffset += amount;
m_ReadOffset += amount; }
}
void Resize(std::size_t size) { void ReadSome(DataBuffer& buffer, std::size_t amount) {
m_Buffer.resize(size); assert(m_ReadOffset + amount <= GetSize());
} buffer.Resize(amount);
std::copy_n(m_Buffer.begin() + static_cast<Data::difference_type>(m_ReadOffset), amount, buffer.begin());
m_ReadOffset += amount;
}
void Reserve(std::size_t amount) { void ReadSome(std::string& buffer, std::size_t amount) {
m_Buffer.reserve(amount); assert(m_ReadOffset + amount <= GetSize());
} buffer.resize(amount);
std::copy_n(m_Buffer.begin() + static_cast<Data::difference_type>(m_ReadOffset), amount, buffer.begin());
m_ReadOffset += amount;
}
void erase(iterator it) { void Resize(std::size_t size) {
m_Buffer.erase(it); m_Buffer.resize(size);
} }
void Clear() { void Reserve(std::size_t amount) {
m_Buffer.clear(); m_Buffer.reserve(amount);
m_ReadOffset = 0; }
}
bool IsFinished() const { void erase(iterator it) {
return m_ReadOffset >= m_Buffer.size(); m_Buffer.erase(it);
} }
std::uint8_t* data() { void Clear() {
return m_Buffer.data(); m_Buffer.clear();
} m_ReadOffset = 0;
}
const std::uint8_t* data() const { bool IsFinished() const {
return m_Buffer.data(); return m_ReadOffset >= m_Buffer.size();
} }
std::size_t GetReadOffset() const { return m_ReadOffset; } std::uint8_t* data() {
void SetReadOffset(std::size_t pos); return m_Buffer.data();
}
std::string ToString() const; const std::uint8_t* data() const {
std::size_t GetSize() const; return m_Buffer.data();
bool IsEmpty() const; }
std::size_t GetRemaining() const;
iterator begin(); std::size_t GetReadOffset() const { return m_ReadOffset; }
iterator end(); void SetReadOffset(std::size_t pos);
const_iterator begin() const;
const_iterator end() const;
reference operator[](Data::size_type i) { return m_Buffer[i]; } std::string ToString() const;
const_reference operator[](Data::size_type i) const { return m_Buffer[i]; } std::size_t GetSize() const;
bool IsEmpty() const;
std::size_t GetRemaining() const;
bool ReadFile(const std::string& fileName); iterator begin();
bool WriteFile(const std::string& fileName); iterator end();
const_iterator begin() const;
const_iterator end() const;
reference operator[](Data::size_type i) { return m_Buffer[i]; }
const_reference operator[](Data::size_type i) const { return m_Buffer[i]; }
bool ReadFile(const std::string& fileName);
bool WriteFile(const std::string& fileName);
}; };
std::ostream& operator<<(std::ostream& os, const DataBuffer& buffer); std::ostream& operator<<(std::ostream& os, const DataBuffer& buffer);
} // ns td } // ns td
#endif

View File

@@ -7,63 +7,63 @@ constexpr float PI = 3.14159274101257324219;
/* Sine functions */ /* Sine functions */
float easeInSine(float x); float EaseInSine(float x);
float easeOutSine(float x); float EaseOutSine(float x);
float easeInOutSine(float x); float EaseInOutSine(float x);
/* Cubic functions */ /* Cubic functions */
float easeInCubic(float x); float EaseInCubic(float x);
float easeOutCubic(float x); float EaseOutCubic(float x);
float easeInOutCubic(float x); float EaseInOutCubic(float x);
/* Quint functions */ /* Quint functions */
float easeInQuint(float x); float EaseInQuint(float x);
float easeOutQuint(float x); float EaseOutQuint(float x);
float easeInOutQuint(float x); float EaseInOutQuint(float x);
/* Circ functions */ /* Circ functions */
float easeInCirc(float x); float EaseInCirc(float x);
float easeOutCirc(float x); float EaseOutCirc(float x);
float easeInOutCirc(float x); float EaseInOutCirc(float x);
/* Elastic functions */ /* Elastic functions */
float easeInElastic(float x); float EaseInElastic(float x);
float easeOutElastic(float x); float EaseOutElastic(float x);
float easeInOutElastic(float x); float EaseInOutElastic(float x);
/* Quad functions */ /* Quad functions */
float easeInQuad(float x); float EaseInQuad(float x);
float easeOutQuad(float x); float EaseOutQuad(float x);
float easeInOutQuad(float x); float EaseInOutQuad(float x);
/* Quart functions */ /* Quart functions */
float easeInQuart(float x); float EaseInQuart(float x);
float easeOutQuart(float x); float EaseOutQuart(float x);
float easeInOutQuart(float x); float EaseInOutQuart(float x);
/* Expo functions */ /* Expo functions */
float easeInExpo(float x); float EaseInExpo(float x);
float easeOutExpo(float x); float EaseOutExpo(float x);
float easeInOutExpo(float x); float EaseInOutExpo(float x);
/* Back functions */ /* Back functions */
float easeInBack(float x); float EaseInBack(float x);
float easeOutBack(float x); float EaseOutBack(float x);
float easeInOutBack(float x); float EaseInOutBack(float x);
/* Bounce functions */ /* Bounce functions */
float easeInBounce(float x); float EaseInBounce(float x);
float easeOutBounce(float x); float EaseOutBounce(float x);
float easeInOutBounce(float x); float EaseInOutBounce(float x);
} // namespace utils } // namespace utils
} // namespace td } // namespace td

23
include/misc/Format.h Normal file
View File

@@ -0,0 +1,23 @@
#pragma once
#include <string>
#include <memory>
#include <stdexcept>
namespace td {
namespace utils {
template <typename... Args>
std::string format(const std::string& format, Args... args) {
int size = snprintf(nullptr, 0, format.c_str(), args...) + 1; // Extra space for '\0'
if (size <= 0) {
throw std::runtime_error("Error during formatting.");
}
std::unique_ptr<char[]> buf(new char[size]);
snprintf(buf.get(), static_cast<std::size_t>(size), format.c_str(), args...);
return std::string(buf.get(), buf.get() + size - 1); // We don't want the '\0' inside
}
} // namespace utils
} // namespace td

13
include/misc/Log.h Normal file
View File

@@ -0,0 +1,13 @@
#pragma once
#include <string>
namespace td {
namespace utils {
void LOG(const std::string& msg);
void LOGD(const std::string& msg);
void LOGE(const std::string& err);
} // namespace utils
} // namespace td

177
include/misc/Maths.h Normal file
View File

@@ -0,0 +1,177 @@
#pragma once
#include "Defines.h"
#include <cmath>
namespace td {
//////////////////////////////////////////////////////////////////
// Operators //
//////////////////////////////////////////////////////////////////
template<typename T>
Vec2<T> operator+(const Vec2<T>& vect, const Vec2<T>& other) {
return {vect.x + other.x, vect.y + other.y};
}
template<typename T>
Vec2<T> operator- (const Vec2<T>& vect) {
return { -vect.x, -vect.y };
}
template<typename T>
Vec2<T> operator- (const Vec2<T>& vect, const Vec2<T>& other) {
return vect + (-other);
}
template<typename T>
Vec3<T> operator- (const Vec3<T>& vect) {
return { -vect.x, -vect.y, -vect.z };
}
template<typename T>
Vec3<T> operator+ (const Vec3<T>& vect, const Vec3<T>& other) {
return { vect.x + other.x, vect.y + other.y, vect.z + other.y };
}
template<typename T>
Vec3<T> operator- (const Vec3<T>& vect, const Vec3<T>& other) {
return vect + (-other);
}
template<typename T>
Vec4<T> operator- (const Vec4<T>& vect) {
return { -vect.x, -vect.y, -vect.z, -vect.w };
}
template<typename T>
Vec4<T> operator+ (const Vec4<T>& vect, const Vec4<T>& other) {
return { vect.x + other.x, vect.y + other.y, vect.z + other.y, vect.w + other.w };
}
template<typename T>
Vec4<T> operator- (const Vec4<T>& vect, const Vec4<T>& other) {
return vect + (-other);
}
//////////////////////////////////////////////////////////////////
// Vectors //
//////////////////////////////////////////////////////////////////
namespace maths {
template<typename T>
T Length(const Vec3<T>& vect) {
return std::sqrt(vect.x * vect.x + vect.y * vect.y + vect.z * vect.z);
}
template<typename T>
Vec3<T> Normalize(const Vec3<T>& vect) {
T length = Length(vect);
return { vect.x / length, vect.y / length, vect.z / length };
}
template<typename T>
Vec4<T> Normalize(const Vec4<T>& vect) {
T length = std::sqrt(vect.x * vect.x + vect.y * vect.y + vect.z * vect.z + vect.w * vect.w);
return { vect.x / length, vect.y / length, vect.z / length, vect.w / length };
}
template<typename T>
T Dot(const Vec3<T>& vect, const Vec3<T>& other) {
return vect.x * other.x + vect.y * other.y + vect.z * other.z;
}
template<typename T>
Vec3<T> Cross(const Vec3<T>& vect, const Vec3<T>& other) {
return {
vect.y * other.z - vect.z * other.y,
vect.z * other.x - vect.x * other.z,
vect.x * other.y - vect.y * other.x,
};
}
template<typename T>
T Dot(const Vec4<T>& vect, const Vec4<T>& other) {
return vect.x * other.x + vect.y * other.y + vect.z * other.z + vect.w * other.w;
}
template<typename T>
T Distance(const Vec3<T>& vect, const Vec3<T>& other) {
return Length(vect - other);
}
//////////////////////////////////////////////////////////////////
// Matricies //
//////////////////////////////////////////////////////////////////
template<typename T>
Vec4<T> Dot(const Mat4<T>& mat, const Vec4<T>& vect) {
return {
mat.x0 * vect.x + mat.x1 * vect.y + mat.x2 * vect.z + mat.x3 * vect.w,
mat.y0 * vect.x + mat.y1 * vect.y + mat.y2 * vect.z + mat.y3 * vect.w,
mat.z0 * vect.x + mat.z1 * vect.y + mat.z2 * vect.z + mat.z3 * vect.w,
mat.w0 * vect.x + mat.w1 * vect.y + mat.w2 * vect.z + mat.w3 * vect.w
};
}
template<typename T>
Mat4<T> Dot(const Mat4<T>& mat, const Mat4<T>& other) {
Mat4<T> result {};
for (std::size_t i = 0; i < Mat4<T>::MATRIX_SIZE; i++) {
for (std::size_t j = 0; j < Mat4<T>::MATRIX_SIZE; j++) {
for (std::size_t k = 0; k < Mat4<T>::MATRIX_SIZE; k++) {
result.at(i, j) += mat.at(i, k) * other.at(k, j);
}
}
}
return result;
}
template<typename T>
Mat4<T> Identity() {
Mat4<T> result{};
result.x0 = static_cast<T>(1);
result.y1 = static_cast<T>(1);
result.z2 = static_cast<T>(1);
result.w3 = static_cast<T>(1);
return result;
}
template<typename T>
Mat4<T> Transpose(const Mat4<T>& mat) {
Mat4<T> result;
result.x1 = mat.y0;
result.x2 = mat.z0;
result.x3 = mat.w0;
result.y0 = mat.x1;
result.y2 = mat.z1;
result.y3 = mat.w1;
result.z0 = mat.x2;
result.z1 = mat.y2;
result.z3 = mat.w2;
result.w0 = mat.x3;
result.w1 = mat.y3;
result.w2 = mat.z3;
result.x0 = mat.x0;
result.y1 = mat.y1;
result.z2 = mat.z2;
result.w3 = mat.w3;
return result;
}
Mat4f Perspective(float fovY, float aspectRatio, float zNear, float zFar);
Mat4f Look(const Vec3f& eye, const Vec3f& center, const Vec3f& up);
Mat4f Inverse(const Mat4f& mat);
} // namespace maths
} // namespace td

View File

@@ -10,26 +10,26 @@ namespace utils {
template <typename Listener> template <typename Listener>
class ObjectNotifier { class ObjectNotifier {
protected: protected:
std::vector<Listener*> m_Listeners; std::vector<Listener*> m_Listeners;
public: public:
void bindListener(Listener* listener) { void BindListener(Listener* listener) {
m_Listeners.push_back(listener); m_Listeners.push_back(listener);
} }
void unbindListener(Listener* listener) { void UnbindListener(Listener* listener) {
auto iter = std::find(m_Listeners.begin(), m_Listeners.end(), listener); auto iter = std::find(m_Listeners.begin(), m_Listeners.end(), listener);
if(iter == m_Listeners.end()) return; if (iter == m_Listeners.end()) return;
m_Listeners.erase(iter); m_Listeners.erase(iter);
} }
template <typename Func, typename... Args> template <typename Func, typename... Args>
void notifyListeners(Func function, Args... args) { void NotifyListeners(Func function, Args... args) {
for (Listener* listener : m_Listeners) for (Listener* listener : m_Listeners)
std::bind(function, listener, args...)(); std::bind(function, listener, args...)();
} }
}; };
} // namespace utils } // namespace utils

View File

@@ -4,49 +4,49 @@ namespace td {
namespace utils { namespace utils {
enum class Os { enum class Os {
Windows = 0, Windows = 0,
Linux, Linux,
Android, Android,
Unknown, Unknown,
}; };
enum class Architecture { enum class Architecture {
x86_64 = 0, x86_64 = 0,
x86, x86,
Arm64, Arm64,
Armhf, Armhf,
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__)
return Os::Android; return Os::Android;
#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)
return Architecture::x86; return Architecture::x86;
#elif defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) #elif defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64)
return Architecture::x86_64; return Architecture::x86_64;
#elif defined(_M_IX86) || defined(_X86_) || defined(i386) || defined(__i386) || defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) #elif defined(_M_IX86) || defined(_X86_) || defined(i386) || defined(__i386) || defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__)
return Architecture::x86; return Architecture::x86;
#elif defined(__aarch64__) #elif defined(__aarch64__)
return Architecture::Arm64; return Architecture::Arm64;
#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,19 +6,19 @@ 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);
return distrib(generator); return distrib(generator);
} }
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);
return distrib(generator); return distrib(generator);
} }
} // namespace utils } // namespace utils

View File

@@ -8,87 +8,87 @@ namespace shape {
class Point { class Point {
private: private:
float m_X, m_Y; float m_X, m_Y;
public: public:
Point() : m_X(0), m_Y(0) {} Point() : m_X(0), m_Y(0) {}
Point(float x, float y) : m_X(x), m_Y(y) {} Point(float x, float y) : m_X(x), m_Y(y) {}
float getX() const { return m_X; } float GetX() const { return m_X; }
float getY() const { return m_Y; } float GetY() const { return m_Y; }
void setX(float x) { m_X = x; } void SetX(float x) { m_X = x; }
void setY(float y) { m_Y = y; } void SetY(float y) { m_Y = y; }
float distance(const Point& point) const; float Distance(const Point& point) const;
float distanceSquared(const Point& point) const; float DistanceSquared(const Point& point) const;
}; };
class Circle; class Circle;
class Rectangle { class Rectangle {
private: private:
Point m_Center; Point m_Center;
float m_Width, m_Height; float m_Width, m_Height;
public: public:
Rectangle() {} Rectangle() {}
const Point& getCenter() const { return m_Center; } const Point& GetCenter() const { return m_Center; }
float getCenterX() const { return m_Center.getX(); } float GetCenterX() const { return m_Center.GetX(); }
float getCenterY() const { return m_Center.getY(); } float GetCenterY() const { return m_Center.GetY(); }
float getWidth() const { return m_Width; } float GetWidth() const { return m_Width; }
float getHeight() const { return m_Height; } 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 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) }; } 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 SetCenter(const Point& center) { m_Center = center; }
void setCenterX(float x) { m_Center.setX(x); } void SetCenterX(float x) { m_Center.SetX(x); }
void setCenterY(float y) { m_Center.setY(y); } void SetCenterY(float y) { m_Center.SetY(y); }
void setSize(float width, float height) { setWidth(width); setHeight(height); } void SetSize(float width, float height) { SetWidth(width); SetHeight(height); }
void setSize(Point size) { setSize(size.getX(), size.getY()); } void SetSize(Point size) { SetSize(size.GetX(), size.GetY()); }
Point getSize() { return { m_Width, m_Height }; } Point GetSize() { return { m_Width, m_Height }; }
void setWidth(float width) { m_Width = width; } void SetWidth(float width) { m_Width = width; }
void setHeight(float height) { m_Height = height; } void SetHeight(float height) { m_Height = height; }
bool collidesWith(const Point& point) const; bool CollidesWith(const Point& point) const;
bool collidesWith(const Rectangle& rect) const; bool CollidesWith(const Rectangle& rect) const;
bool collidesWith(const Circle& circle) const; bool CollidesWith(const Circle& circle) const;
// distance from the closest side of the rectangle // distance from the closest side of the rectangle
float distance(const Circle& circle) const; float Distance(const Circle& circle) const;
float distanceSquared(const Circle& circle) const; float DistanceSquared(const Circle& circle) const;
}; };
class Circle { class Circle {
private: private:
Point m_Center; Point m_Center;
float m_Radius; float m_Radius;
public: public:
Circle(float x, float y, float radius) : m_Center(x, y), m_Radius(radius) {} Circle(float x, float y, float radius) : m_Center(x, y), m_Radius(radius) {}
Circle() : m_Radius(0) {} Circle() : m_Radius(0) {}
const Point& getCenter() const { return m_Center; } const Point& GetCenter() const { return m_Center; }
float getCenterX() const { return m_Center.getX(); } float GetCenterX() const { return m_Center.GetX(); }
float getCenterY() const { return m_Center.getY(); } float GetCenterY() const { return m_Center.GetY(); }
float getRadius() const { return m_Radius; } float GetRadius() const { return m_Radius; }
void setCenter(const Point& center) { m_Center = center; } void SetCenter(const Point& center) { m_Center = center; }
void setCenterX(float x) { m_Center.setX(x); } void SetCenterX(float x) { m_Center.SetX(x); }
void setCenterY(float y) { m_Center.setY(y); } void SetCenterY(float y) { m_Center.SetY(y); }
void setRadius(float radius) { m_Radius = radius; } void SetRadius(float radius) { m_Radius = radius; }
bool collidesWith(const Point& point) const; bool CollidesWith(const Point& point) const;
bool collidesWith(const Rectangle& rect) const; bool CollidesWith(const Rectangle& rect) const;
bool collidesWith(const Circle& circle) const; bool CollidesWith(const Circle& circle) const;
// distance from the closest side of the rectangle // distance from the closest side of the rectangle
float distance(const Rectangle& rect) const; float Distance(const Rectangle& rect) const;
float distanceSquared(const Rectangle& rect) const; float DistanceSquared(const Rectangle& rect) const;
}; };
} // namespace shape } // namespace shape

View File

@@ -6,7 +6,7 @@
namespace td { namespace td {
namespace utils { namespace utils {
std::uint64_t getTime(); std::uint64_t GetTime();
typedef std::function<void()> TimerExecFunction; typedef std::function<void()> TimerExecFunction;
@@ -14,62 +14,62 @@ typedef std::function<void()> TimerExecFunction;
// utililty class to call function at regular period of time // utililty class to call function at regular period of time
class AutoTimer { class AutoTimer {
private: private:
std::uint64_t m_Interval; std::uint64_t m_Interval;
TimerExecFunction m_Function; TimerExecFunction m_Function;
std::uint64_t m_LastTime = getTime(); std::uint64_t m_LastTime = GetTime();
std::uint64_t m_InternalTime = 0; std::uint64_t m_InternalTime = 0;
public: public:
AutoTimer() : m_Interval(0), m_Function(nullptr) {} AutoTimer() : m_Interval(0), m_Function(nullptr) {}
AutoTimer(std::uint64_t interval) : m_Interval(interval), m_Function(nullptr) {} AutoTimer(std::uint64_t interval) : m_Interval(interval), m_Function(nullptr) {}
AutoTimer(std::uint64_t interval, TimerExecFunction callback) : m_Interval(interval), m_Function(callback) {} AutoTimer(std::uint64_t interval, TimerExecFunction callback) : m_Interval(interval), m_Function(callback) {}
void update(); void Update();
void update(std::uint64_t delta); void Update(std::uint64_t delta);
void reset(); void Reset();
void setInterval(std::uint64_t newInterval) { m_Interval = newInterval; } void SetInterval(std::uint64_t newInterval) { m_Interval = newInterval; }
std::uint64_t getInterval() const { return m_Interval; } std::uint64_t GetInterval() const { return m_Interval; }
void setCallbackFunction(TimerExecFunction newCallback) { m_Function = newCallback; } void SetCallbackFunction(TimerExecFunction newCallback) { m_Function = newCallback; }
TimerExecFunction getCallbackFunction() const { return m_Function; } TimerExecFunction GetCallbackFunction() const { return m_Function; }
}; };
// 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; // in millis 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) {}
Timer(std::uint64_t interval) : m_Interval(interval) {} Timer(std::uint64_t interval) : m_Interval(interval) {}
bool update(std::uint64_t delta); bool Update(std::uint64_t delta);
void reset(); void Reset();
void setInterval(std::uint64_t newInterval) { m_Interval = newInterval; } void SetInterval(std::uint64_t newInterval) { m_Interval = newInterval; }
std::uint64_t getInterval() const { return m_Interval; } std::uint64_t GetInterval() const { return m_Interval; }
}; };
// utililty class to call function at regular period of time with a cooldown (used for towers and mobs ) // utililty class to call function at regular period of time with a cooldown (used for towers and mobs )
class CooldownTimer { class CooldownTimer {
private: private:
std::uint64_t m_Cooldown; // in millis std::uint64_t m_Cooldown; // in millis
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) {}
CooldownTimer(std::uint64_t cooldown) : m_Cooldown(0), m_CooldownTime(cooldown) {} CooldownTimer(std::uint64_t cooldown) : m_Cooldown(0), m_CooldownTime(cooldown) {}
bool update(std::uint64_t delta); bool Update(std::uint64_t delta);
void applyCooldown(); void ApplyCooldown();
void reset(); void Reset();
void setCooldown(std::uint64_t newCooldown) { m_CooldownTime = newCooldown; } void SetCooldown(std::uint64_t newCooldown) { m_CooldownTime = newCooldown; }
std::uint64_t getCooldown() const { return m_CooldownTime; } std::uint64_t GetCooldown() const { return m_CooldownTime; }
}; };
} // namespace utils } // namespace utils

View File

@@ -11,38 +11,38 @@ namespace network {
/* IPv4 address */ /* IPv4 address */
class IPAddress { class IPAddress {
private: private:
std::uint32_t m_Address; std::uint32_t m_Address;
bool m_Valid; bool m_Valid;
public: public:
/* Create an invalid address */ /* Create an invalid address */
IPAddress() noexcept; IPAddress() noexcept;
/* Initialize by string IP */ /* Initialize by string IP */
IPAddress(const std::string& str); IPAddress(const std::string& str);
/* Initialize by string IP */ /* Initialize by string IP */
IPAddress(const std::wstring& str); IPAddress(const std::wstring& str);
/* Initialize by octets */ /* Initialize by octets */
IPAddress(std::uint8_t octet1, std::uint8_t octet2, std::uint8_t octet3, std::uint8_t octet4) noexcept; IPAddress(std::uint8_t octet1, std::uint8_t octet2, std::uint8_t octet3, std::uint8_t octet4) noexcept;
/* Get the specific octet. 1-4 */ /* Get the specific octet. 1-4 */
std::uint8_t GetOctet(std::uint8_t num) const; std::uint8_t GetOctet(std::uint8_t num) const;
/* Set the specific octet. 1-4 */ /* Set the specific octet. 1-4 */
void SetOctet(std::uint8_t num, std::uint8_t value); void SetOctet(std::uint8_t num, std::uint8_t value);
/* Make sure the IP is valid. It will be invalid if the host wasn't found. */ /* Make sure the IP is valid. It will be invalid if the host wasn't found. */
bool IsValid() const noexcept { return m_Valid; } bool IsValid() const noexcept { return m_Valid; }
std::string ToString() const; std::string ToString() const;
static IPAddress LocalAddress(); static IPAddress LocalAddress();
bool operator==(const IPAddress& right); bool operator==(const IPAddress& right);
bool operator!=(const IPAddress& right); bool operator!=(const IPAddress& right);
bool operator==(bool b); bool operator==(bool b);
}; };
typedef std::vector<IPAddress> IPAddresses; typedef std::vector<IPAddress> IPAddresses;

View File

@@ -22,7 +22,7 @@ namespace network {
class Dns { class Dns {
public: public:
static IPAddresses Resolve(const std::string& host); static IPAddresses Resolve(const std::string& host);
}; };
} // ns network } // ns network

View File

@@ -40,45 +40,45 @@ typedef int SocketHandle;
class Socket { class Socket {
public: public:
enum Status { Connected, Disconnected, Error }; enum Status { Connected, Disconnected, Error };
enum Type { TCP, UDP }; enum Type { TCP, UDP };
private: private:
bool m_Blocking; bool m_Blocking;
Type m_Type; Type m_Type;
Status m_Status; Status m_Status;
protected: protected:
SocketHandle m_Handle; SocketHandle m_Handle;
Socket(Type type); Socket(Type type);
void SetStatus(Status status); void SetStatus(Status status);
public: public:
virtual ~Socket(); virtual ~Socket();
Socket(Socket&& rhs) = default; Socket(Socket&& rhs) = default;
Socket& operator=(Socket&& rhs) = default; Socket& operator=(Socket&& rhs) = default;
bool SetBlocking(bool block); bool SetBlocking(bool block);
bool IsBlocking() const noexcept; bool IsBlocking() const noexcept;
Type GetType() const noexcept; Type GetType() const noexcept;
Status GetStatus() const noexcept; Status GetStatus() const noexcept;
SocketHandle GetHandle() const noexcept; SocketHandle GetHandle() const noexcept;
bool Connect(const std::string& ip, std::uint16_t port); bool Connect(const std::string& ip, std::uint16_t port);
virtual bool Connect(const IPAddress& address, std::uint16_t port) = 0; virtual bool Connect(const IPAddress& address, std::uint16_t port) = 0;
void Disconnect(); void Disconnect();
std::size_t Send(const std::string& data); std::size_t Send(const std::string& data);
std::size_t Send(DataBuffer& buffer); std::size_t Send(DataBuffer& buffer);
virtual std::size_t Send(const uint8_t* data, std::size_t size) = 0; virtual std::size_t Send(const uint8_t* data, std::size_t size) = 0;
virtual DataBuffer Receive(std::size_t amount) = 0; virtual DataBuffer Receive(std::size_t amount) = 0;
virtual std::size_t Receive(DataBuffer& buffer, std::size_t amount) = 0; virtual std::size_t Receive(DataBuffer& buffer, std::size_t amount) = 0;
}; };
typedef std::shared_ptr<Socket> SocketPtr; typedef std::shared_ptr<Socket> SocketPtr;

View File

@@ -5,29 +5,30 @@ namespace td {
namespace network { namespace network {
class TCPListener { class TCPListener {
int m_Handle; int m_Handle;
std::uint16_t m_Port; std::uint16_t m_Port;
int m_MaxConnections; int m_MaxConnections;
public: public:
TCPListener(); TCPListener();
~TCPListener(); ~TCPListener();
bool listen(std::uint16_t port, int maxConnections); bool Listen(std::uint16_t port, int maxConnections);
bool accept(TCPSocket& newSocket); bool Accept(TCPSocket& newSocket);
void destroy(); void Destroy();
bool close(); bool Close();
bool setBlocking(bool blocking); bool SetBlocking(bool blocking);
std::uint16_t getListeningPort() const { std::uint16_t GetListeningPort() const {
return m_Port; return m_Port;
} }
int getMaximumConnections() const {
return m_MaxConnections;
}
REMOVE_COPY(TCPListener); int GetMaximumConnections() const {
return m_MaxConnections;
}
REMOVE_COPY(TCPListener);
}; };
} // namespace network } // namespace network

View File

@@ -13,22 +13,22 @@ class TCPListener;
class TCPSocket : public Socket { class TCPSocket : public Socket {
private: private:
IPAddress m_RemoteIP; IPAddress m_RemoteIP;
uint16_t m_Port; uint16_t m_Port;
sockaddr_in m_RemoteAddr; sockaddr m_RemoteAddr;
public: public:
TCPSocket(); TCPSocket();
TCPSocket(TCPSocket&& other); TCPSocket(TCPSocket&& other);
virtual bool Connect(const IPAddress& address, std::uint16_t port); virtual bool Connect(const IPAddress& address, std::uint16_t port);
virtual std::size_t Send(const std::uint8_t* data, std::size_t size); virtual std::size_t Send(const std::uint8_t* data, std::size_t size);
virtual DataBuffer Receive(std::size_t amount); virtual DataBuffer Receive(std::size_t amount);
virtual std::size_t Receive(DataBuffer& buffer, std::size_t amount); virtual std::size_t Receive(DataBuffer& buffer, std::size_t amount);
REMOVE_COPY(TCPSocket); REMOVE_COPY(TCPSocket);
friend class TCPListener; friend class TCPListener;
}; };
void SendPacket(const DataBuffer& data, network::TCPSocket& socket); void SendPacket(const DataBuffer& data, network::TCPSocket& socket);

View File

@@ -11,16 +11,18 @@ namespace network {
class UDPSocket : public Socket { class UDPSocket : public Socket {
private: private:
IPAddress m_RemoteIP; IPAddress m_RemoteIP;
uint16_t m_Port; uint16_t m_Port;
sockaddr_in m_RemoteAddr; sockaddr_in m_RemoteAddr;
public: public:
UDPSocket(); UDPSocket();
bool Connect(const IPAddress& address, std::uint16_t port); bool Connect(const IPAddress& address, std::uint16_t port);
std::size_t Send(const std::uint8_t* data, std::size_t size); std::size_t Send(const std::uint8_t* data, std::size_t size);
DataBuffer Receive(std::size_t amount);
virtual DataBuffer Receive(std::size_t amount);
virtual std::size_t Receive(DataBuffer& buffer, std::size_t amount);
}; };
} // ns network } // ns network

View File

@@ -12,21 +12,21 @@ class PacketHandler;
class PacketDispatcher { class PacketDispatcher {
private: private:
std::map<PacketType, std::vector<PacketHandler*>> m_Handlers; std::map<PacketType, std::vector<PacketHandler*>> m_Handlers;
public: public:
PacketDispatcher() = default; PacketDispatcher() = default;
PacketDispatcher(const PacketDispatcher& rhs) = delete; PacketDispatcher(const PacketDispatcher& rhs) = delete;
PacketDispatcher& operator=(const PacketDispatcher& rhs) = delete; PacketDispatcher& operator=(const PacketDispatcher& rhs) = delete;
PacketDispatcher(PacketDispatcher&& rhs) = delete; PacketDispatcher(PacketDispatcher&& rhs) = delete;
PacketDispatcher& operator=(PacketDispatcher&& rhs) = delete; PacketDispatcher& operator=(PacketDispatcher&& rhs) = delete;
void Dispatch(const PacketPtr& packet); void Dispatch(const PacketPtr& packet);
void RegisterHandler(PacketType type, PacketHandler* handler); void RegisterHandler(PacketType type, PacketHandler* handler);
void UnregisterHandler(PacketType type, PacketHandler* handler); void UnregisterHandler(PacketType type, PacketHandler* handler);
void UnregisterHandler(PacketHandler* handler); void UnregisterHandler(PacketHandler* handler);
}; };
} // namespace protocol } // namespace protocol

View File

@@ -6,7 +6,7 @@ namespace td {
namespace protocol { namespace protocol {
namespace PacketFactory { namespace PacketFactory {
PacketPtr createPacket(PacketType type, DataBuffer& buffer); PacketPtr CreatePacket(PacketType type, DataBuffer& buffer);
} }
} // namespace protocol } // namespace protocol

View File

@@ -9,37 +9,39 @@ class PacketDispatcher;
class PacketHandler { class PacketHandler {
private: private:
PacketDispatcher* m_Dispatcher; PacketDispatcher* m_Dispatcher;
public: public:
PacketHandler(PacketDispatcher* dispatcher) : m_Dispatcher(dispatcher) {} PacketHandler(PacketDispatcher* dispatcher) : m_Dispatcher(dispatcher) {}
virtual ~PacketHandler() {} virtual ~PacketHandler() {}
PacketDispatcher* GetDispatcher() { return m_Dispatcher; } PacketDispatcher* GetDispatcher() { return m_Dispatcher; }
virtual void HandlePacket(const PlayerLoginPacket* packet) {} virtual void HandlePacket(const ConnexionInfoPacket* packet) {}
virtual void HandlePacket(const WorldBeginDataPacket* packet) {} virtual void HandlePacket(const DisconnectPacket* packet) {}
virtual void HandlePacket(const WorldDataPacket* packet) {} virtual void HandlePacket(const KeepAlivePacket* packet) {}
virtual void HandlePacket(const KeepAlivePacket* packet) {} virtual void HandlePacket(const PlaceTowerPacket* packet) {}
virtual void HandlePacket(const UpdateMoneyPacket* packet) {} virtual void HandlePacket(const PlayerBuyItemPacket* packet) {}
virtual void HandlePacket(const UpdateExpPacket* packet) {} virtual void HandlePacket(const PlayerBuyMobUpgradePacket* packet) {}
virtual void HandlePacket(const UpdateLobbyTimePacket* packet) {} virtual void HandlePacket(const PlayerJoinPacket* packet) {}
virtual void HandlePacket(const UpdateGameStatePacket* packet) {} virtual void HandlePacket(const PlayerLeavePacket* packet) {}
virtual void HandlePacket(const PlayerListPacket* packet) {} virtual void HandlePacket(const PlayerListPacket* packet) {}
virtual void HandlePacket(const PlayerJoinPacket* packet) {} virtual void HandlePacket(const PlayerLoginPacket* packet) {}
virtual void HandlePacket(const PlayerLeavePacket* packet) {} virtual void HandlePacket(const RemoveTowerPacket* packet) {}
virtual void HandlePacket(const ConnexionInfoPacket* packet) {} virtual void HandlePacket(const SelectTeamPacket* packet) {}
virtual void HandlePacket(const SelectTeamPacket* packet) {} virtual void HandlePacket(const SendMobsPacket* packet) {}
virtual void HandlePacket(const UpdatePlayerTeamPacket* packet) {} virtual void HandlePacket(const ServerTpsPacket* packet) {}
virtual void HandlePacket(const DisconnectPacket* packet) {} virtual void HandlePacket(const SpawnMobPacket* packet) {}
virtual void HandlePacket(const ServerTpsPacket* packet) {} virtual void HandlePacket(const UpdateCastleLifePacket* packet) {}
virtual void HandlePacket(const SpawnMobPacket* packet) {} virtual void HandlePacket(const UpdateExpPacket* packet) {}
virtual void HandlePacket(const PlaceTowerPacket* packet) {} virtual void HandlePacket(const UpdateGameStatePacket* packet) {}
virtual void HandlePacket(const WorldAddTowerPacket* packet) {} virtual void HandlePacket(const UpdateLobbyTimePacket* packet) {}
virtual void HandlePacket(const RemoveTowerPacket* packet) {} virtual void HandlePacket(const UpdateMobStatesPacket* packet) {}
virtual void HandlePacket(const SendMobsPacket* packet) {} virtual void HandlePacket(const UpdateMoneyPacket* packet) {}
virtual void HandlePacket(const UpgradeTowerPacket* packet) {} virtual void HandlePacket(const UpdatePlayerTeamPacket* packet) {}
virtual void HandlePacket(const UpdateMobStatesPacket* packet) {} virtual void HandlePacket(const UpgradeTowerPacket* packet) {}
virtual void HandlePacket(const UpdateCastleLifePacket* packet) {} virtual void HandlePacket(const WorldAddTowerPacket* packet) {}
virtual void HandlePacket(const WorldBeginDataPacket* packet) {}
virtual void HandlePacket(const WorldDataPacket* packet) {}
}; };
} // namespace protocol } // namespace protocol

View File

@@ -12,565 +12,628 @@ namespace protocol {
class PacketHandler; class PacketHandler;
enum class PacketType : std::uint8_t { enum class PacketType : std::uint8_t {
// client --> server // client --> server
PlayerLogin = 0, PlayerLogin = 0,
SelectTeam, SelectTeam,
SpawnMob, SpawnMob,
SendMobs, SendMobs,
PlaceTower, PlaceTower,
// client <-- server // client <-- server
PlayerJoin, PlayerJoin,
PlayerLeave, PlayerLeave,
WorldBeginData, WorldBeginData,
WorldData, WorldData,
UpdateMoney, UpdateMoney,
UpdateEXP, UpdateEXP,
UpdateLobbyTime, UpdateLobbyTime,
UpdateGameState, UpdateGameState,
PlayerList, PlayerList,
ConnectionInfo, ConnectionInfo,
UpdatePlayerTeam, UpdatePlayerTeam,
ServerTps, ServerTps,
WorldAddTower, WorldAddTower,
UpdateMobStates, UpdateMobStates,
UpdateCastleLife, UpdateCastleLife,
// client <--> server // client <--> server
KeepAlive, KeepAlive,
Disconnect, Disconnect,
UpgradeTower, UpgradeTower,
RemoveTower, RemoveTower,
PlayerBuyItem,
PlayerBuyMobUpgrade,
PACKET_COUNT
}; };
struct WorldHeader { struct WorldHeader {
game::TowerTileColorPalette m_TowerPlacePalette; game::TowerTileColorPalette m_TowerPlacePalette;
game::Color m_WalkablePalette; Color m_WalkablePalette;
std::vector<game::Color> m_DecorationPalette; std::vector<Color> m_DecorationPalette;
game::Color m_Background; Color m_Background;
game::SpawnColorPalette m_SpawnColorPalette; game::SpawnColorPalette m_SpawnColorPalette;
game::TilePalette m_TilePalette; game::TilePalette m_TilePalette;
game::Spawn m_RedSpawn, m_BlueSpawn; game::Spawn m_RedSpawn, m_BlueSpawn;
game::TeamCastle m_RedCastle, m_BlueCastle; game::TeamCastle m_RedCastle, m_BlueCastle;
const game::World* m_World; const game::World* m_World;
}; };
struct WorldData { struct WorldData {
std::unordered_map<game::ChunkCoord, game::ChunkPtr> m_Chunks; std::unordered_map<game::ChunkCoord, game::ChunkPtr> m_Chunks;
}; };
class Packet { class Packet {
public: public:
Packet() {} Packet() {}
virtual ~Packet() {} virtual ~Packet() {}
virtual DataBuffer Serialize() const = 0; virtual DataBuffer Serialize(bool packetID = true) const = 0;
virtual void Deserialize(DataBuffer& data) = 0; virtual void Deserialize(DataBuffer& data) = 0;
virtual void Dispatch(PacketHandler* handler) const = 0; virtual void Dispatch(PacketHandler* handler) const = 0;
virtual PacketType getType() const = 0; void WritePacketID(DataBuffer& data, bool packetID) const;
std::uint8_t getID() const { return (std::uint8_t)getType(); }
virtual PacketType GetType() const = 0;
std::uint8_t GetID() const { return static_cast<std::uint8_t>(GetType()); }
}; };
typedef std::unique_ptr<Packet> PacketPtr; typedef std::unique_ptr<Packet> PacketPtr;
class KeepAlivePacket : public Packet { class KeepAlivePacket : public Packet {
private: private:
std::uint64_t m_AliveID; std::uint64_t m_AliveID;
public: public:
KeepAlivePacket() {} KeepAlivePacket() {}
KeepAlivePacket(std::uint64_t aliveID) : m_AliveID(aliveID) {} KeepAlivePacket(std::uint64_t aliveID) : m_AliveID(aliveID) {}
virtual ~KeepAlivePacket() {} virtual ~KeepAlivePacket() {}
virtual DataBuffer Serialize() const; virtual DataBuffer Serialize(bool packetID = true) const;
virtual void Deserialize(DataBuffer& data); virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const; virtual void Dispatch(PacketHandler* handler) const;
std::uint64_t getAliveID() const { return m_AliveID; } std::uint64_t GetAliveID() const { return m_AliveID; }
virtual PacketType getType() const { return PacketType::KeepAlive; } virtual PacketType GetType() const { return PacketType::KeepAlive; }
}; };
class PlayerLoginPacket : public Packet { class PlayerLoginPacket : public Packet {
private: private:
std::string m_PlayerName; std::string m_PlayerName;
public: public:
PlayerLoginPacket() {} PlayerLoginPacket() {}
PlayerLoginPacket(std::string playerName) : m_PlayerName(playerName) {} PlayerLoginPacket(std::string playerName) : m_PlayerName(playerName) {}
virtual ~PlayerLoginPacket() {} virtual ~PlayerLoginPacket() {}
virtual DataBuffer Serialize() const; virtual DataBuffer Serialize(bool packetID = true) const;
virtual void Deserialize(DataBuffer& data); virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const; virtual void Dispatch(PacketHandler* handler) const;
virtual PacketType getType() const { return PacketType::PlayerLogin; } virtual PacketType GetType() const { return PacketType::PlayerLogin; }
const std::string& getPlayerName() const { return m_PlayerName; } const std::string& GetPlayerName() const { return m_PlayerName; }
}; };
class WorldBeginDataPacket : public Packet { class WorldBeginDataPacket : public Packet {
private: private:
WorldHeader m_Header; WorldHeader m_Header;
public: public:
WorldBeginDataPacket() {} WorldBeginDataPacket() {}
WorldBeginDataPacket(const game::World* world) { WorldBeginDataPacket(const game::World* world) {
m_Header.m_World = world; m_Header.m_World = world;
} }
virtual ~WorldBeginDataPacket() {} virtual ~WorldBeginDataPacket() {}
virtual DataBuffer Serialize() const; virtual DataBuffer Serialize(bool packetID = true) const;
virtual void Deserialize(DataBuffer& data); virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const; virtual void Dispatch(PacketHandler* handler) const;
virtual PacketType getType() const { return PacketType::WorldBeginData; } virtual PacketType GetType() const { return PacketType::WorldBeginData; }
const game::TowerTileColorPalette& getTowerTilePalette() const { return m_Header.m_TowerPlacePalette; } const game::TowerTileColorPalette& GetTowerTilePalette() const { return m_Header.m_TowerPlacePalette; }
const game::Color& getWalkableTileColor() const { return m_Header.m_WalkablePalette; } const Color& GetWalkableTileColor() const { return m_Header.m_WalkablePalette; }
const std::vector<game::Color>& getDecorationPalette() const { return m_Header.m_DecorationPalette; } const std::vector<Color>& GetDecorationPalette() const { return m_Header.m_DecorationPalette; }
const game::Color& getBackgroundColor() const { return m_Header.m_Background; } const Color& GetBackgroundColor() const { return m_Header.m_Background; }
const game::Spawn& getRedSpawn() const { return m_Header.m_RedSpawn; } const game::Spawn& GetRedSpawn() const { return m_Header.m_RedSpawn; }
const game::Spawn& getBlueSpawn() const { return m_Header.m_BlueSpawn; } const game::Spawn& GetBlueSpawn() const { return m_Header.m_BlueSpawn; }
const game::SpawnColorPalette& getSpawnPalette() const { return m_Header.m_SpawnColorPalette; } const game::SpawnColorPalette& GetSpawnPalette() const { return m_Header.m_SpawnColorPalette; }
const game::TeamCastle& getRedCastle() const { return m_Header.m_RedCastle; } const game::TeamCastle& GetRedCastle() const { return m_Header.m_RedCastle; }
const game::TeamCastle& getBlueCastle() const { return m_Header.m_BlueCastle; } const game::TeamCastle& GetBlueCastle() const { return m_Header.m_BlueCastle; }
const game::TilePalette getTilePalette() const { return m_Header.m_TilePalette; } const game::TilePalette GetTilePalette() const { return m_Header.m_TilePalette; }
DataBuffer SerializeCustom() const; // allow serialisation with invalid World member void setWorldHeader(const WorldHeader& header) { m_Header = header; }
void setWorldHeader(const WorldHeader& header) { m_Header = header; }
}; };
class WorldDataPacket : public Packet { class WorldDataPacket : public Packet {
private: private:
WorldData m_WorldData; WorldData m_WorldData;
const game::World* m_World; const game::World* m_World;
public: public:
WorldDataPacket() {} WorldDataPacket() {}
WorldDataPacket(const game::World* world) : m_World(world) {} WorldDataPacket(const game::World* world) : m_World(world) {}
virtual ~WorldDataPacket() {} virtual ~WorldDataPacket() {}
virtual DataBuffer Serialize() const; virtual DataBuffer Serialize(bool packetID = true) const;
virtual void Deserialize(DataBuffer& data); virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const; virtual void Dispatch(PacketHandler* handler) const;
virtual PacketType getType() const { return PacketType::WorldData; } virtual PacketType GetType() const { return PacketType::WorldData; }
const std::unordered_map<game::ChunkCoord, game::ChunkPtr>& getChunks() const { return m_WorldData.m_Chunks; } const std::unordered_map<game::ChunkCoord, game::ChunkPtr>& GetChunks() const { return m_WorldData.m_Chunks; }
DataBuffer SerializeCustom() const; // allow serialisation with invalid World member DataBuffer SerializeCustom() const; // allow serialisation with invalid World member
void setWorldData(const WorldData& worldData) { m_WorldData = worldData; } void SetWorldData(const WorldData& worldData) { m_WorldData = worldData; }
}; };
class UpdateMoneyPacket : public Packet { class UpdateMoneyPacket : public Packet {
private: private:
std::uint32_t m_NewAmount; std::uint32_t m_NewAmount;
public: public:
UpdateMoneyPacket() {} UpdateMoneyPacket() {}
UpdateMoneyPacket(std::uint32_t newAmount) : m_NewAmount(newAmount) {} UpdateMoneyPacket(std::uint32_t newAmount) : m_NewAmount(newAmount) {}
virtual ~UpdateMoneyPacket() {} virtual ~UpdateMoneyPacket() {}
std::uint32_t getGold() const { return m_NewAmount; } std::uint32_t GetGold() const { return m_NewAmount; }
virtual DataBuffer Serialize() const; virtual DataBuffer Serialize(bool packetID = true) const;
virtual void Deserialize(DataBuffer& data); virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const; virtual void Dispatch(PacketHandler* handler) const;
virtual PacketType getType() const { return PacketType::UpdateMoney; } virtual PacketType GetType() const { return PacketType::UpdateMoney; }
}; };
class UpdateExpPacket : public Packet { class UpdateExpPacket : public Packet {
private: private:
std::uint32_t m_NewAmount; std::uint32_t m_NewAmount;
public: public:
UpdateExpPacket() {} UpdateExpPacket() {}
UpdateExpPacket(std::uint32_t newAmount) : m_NewAmount(newAmount) {} UpdateExpPacket(std::uint32_t newAmount) : m_NewAmount(newAmount) {}
virtual ~UpdateExpPacket() {} virtual ~UpdateExpPacket() {}
virtual DataBuffer Serialize() const; std::uint32_t GetExp() const { return m_NewAmount; }
virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const;
virtual PacketType getType() const { return PacketType::UpdateEXP; } virtual DataBuffer Serialize(bool packetID = true) const;
virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const;
virtual PacketType GetType() const { return PacketType::UpdateEXP; }
}; };
class UpdateLobbyTimePacket : public Packet { class UpdateLobbyTimePacket : public Packet {
private: private:
std::uint32_t m_RemainingTime; std::uint32_t m_RemainingTime;
public: public:
UpdateLobbyTimePacket() {} UpdateLobbyTimePacket() {}
UpdateLobbyTimePacket(std::uint32_t remainingTime) : m_RemainingTime(remainingTime) {} UpdateLobbyTimePacket(std::uint32_t remainingTime) : m_RemainingTime(remainingTime) {}
virtual ~UpdateLobbyTimePacket() {} virtual ~UpdateLobbyTimePacket() {}
virtual DataBuffer Serialize() const; virtual DataBuffer Serialize(bool packetID = true) const;
virtual void Deserialize(DataBuffer& data); virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const; virtual void Dispatch(PacketHandler* handler) const;
std::uint32_t getRemainingTime() const { return m_RemainingTime; } std::uint32_t GetRemainingTime() const { return m_RemainingTime; }
virtual PacketType getType() const { return PacketType::UpdateLobbyTime; } virtual PacketType GetType() const { return PacketType::UpdateLobbyTime; }
}; };
class UpdateGameStatePacket : public Packet { class UpdateGameStatePacket : public Packet {
private: private:
game::GameState m_GameState; game::GameState m_GameState;
public: public:
UpdateGameStatePacket() {} UpdateGameStatePacket() {}
UpdateGameStatePacket(game::GameState gameState) : m_GameState(gameState) {} UpdateGameStatePacket(game::GameState gameState) : m_GameState(gameState) {}
virtual ~UpdateGameStatePacket() {} virtual ~UpdateGameStatePacket() {}
virtual DataBuffer Serialize() const; virtual DataBuffer Serialize(bool packetID = true) const;
virtual void Deserialize(DataBuffer& data); virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const; virtual void Dispatch(PacketHandler* handler) const;
game::GameState getGameState() const { return m_GameState; } game::GameState GetGameState() const { return m_GameState; }
virtual PacketType getType() const { return PacketType::UpdateGameState; } virtual PacketType GetType() const { return PacketType::UpdateGameState; }
}; };
struct PlayerInfo { struct PlayerInfo {
std::string name; std::string name;
game::TeamColor team; game::TeamColor team;
}; };
class PlayerListPacket : public Packet { class PlayerListPacket : public Packet {
private: private:
std::map<std::uint8_t, PlayerInfo> m_Players; std::map<std::uint8_t, PlayerInfo> m_Players;
public: public:
PlayerListPacket() {} PlayerListPacket() {}
PlayerListPacket(std::map<std::uint8_t, PlayerInfo> players) : m_Players(players) {} PlayerListPacket(std::map<std::uint8_t, PlayerInfo> players) : m_Players(players) {}
virtual ~PlayerListPacket() {} virtual ~PlayerListPacket() {}
virtual DataBuffer Serialize() const; virtual DataBuffer Serialize(bool packetID = true) const;
virtual void Deserialize(DataBuffer& data); virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const; virtual void Dispatch(PacketHandler* handler) const;
const std::map<std::uint8_t, PlayerInfo>& getPlayers() const { return m_Players; } const std::map<std::uint8_t, PlayerInfo>& GetPlayers() const { return m_Players; }
virtual PacketType getType() const { return PacketType::PlayerList; } virtual PacketType GetType() const { return PacketType::PlayerList; }
}; };
class PlayerJoinPacket : public Packet { class PlayerJoinPacket : public Packet {
private: private:
std::uint8_t m_PlayerID; std::uint8_t m_PlayerID;
std::string m_PlayerName; std::string m_PlayerName;
public: public:
PlayerJoinPacket() {} PlayerJoinPacket() {}
PlayerJoinPacket(std::uint8_t playerID, const std::string& playerName) : m_PlayerID(playerID), m_PlayerName(playerName) {} PlayerJoinPacket(std::uint8_t playerID, const std::string& playerName) : m_PlayerID(playerID), m_PlayerName(playerName) {}
virtual ~PlayerJoinPacket() {} virtual ~PlayerJoinPacket() {}
virtual DataBuffer Serialize() const; virtual DataBuffer Serialize(bool packetID = true) const;
virtual void Deserialize(DataBuffer& data); virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const; virtual void Dispatch(PacketHandler* handler) const;
std::uint8_t getPlayerID() const { return m_PlayerID; } std::uint8_t GetPlayerID() const { return m_PlayerID; }
const std::string& getPlayerName() const { return m_PlayerName; } const std::string& GetPlayerName() const { return m_PlayerName; }
virtual PacketType getType() const { return PacketType::PlayerJoin; } virtual PacketType GetType() const { return PacketType::PlayerJoin; }
}; };
class PlayerLeavePacket : public Packet { class PlayerLeavePacket : public Packet {
private: private:
std::uint8_t m_PlayerID; std::uint8_t m_PlayerID;
public: public:
PlayerLeavePacket() {} PlayerLeavePacket() {}
PlayerLeavePacket(std::uint8_t playerID) : m_PlayerID(playerID) {} PlayerLeavePacket(std::uint8_t playerID) : m_PlayerID(playerID) {}
virtual ~PlayerLeavePacket() {} virtual ~PlayerLeavePacket() {}
virtual DataBuffer Serialize() const; virtual DataBuffer Serialize(bool packetID = true) const;
virtual void Deserialize(DataBuffer& data); virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const; virtual void Dispatch(PacketHandler* handler) const;
std::uint8_t getPlayerID() const { return m_PlayerID; } std::uint8_t GetPlayerID() const { return m_PlayerID; }
virtual PacketType getType() const { return PacketType::PlayerLeave; } virtual PacketType GetType() const { return PacketType::PlayerLeave; }
}; };
class ConnexionInfoPacket : public Packet { class ConnexionInfoPacket : public Packet {
private: private:
std::uint8_t m_ConnectionID; std::uint8_t m_ConnectionID;
public: public:
ConnexionInfoPacket() {} ConnexionInfoPacket() {}
ConnexionInfoPacket(std::uint8_t connectionID) : m_ConnectionID(connectionID) {} ConnexionInfoPacket(std::uint8_t connectionID) : m_ConnectionID(connectionID) {}
virtual ~ConnexionInfoPacket() {} virtual ~ConnexionInfoPacket() {}
virtual DataBuffer Serialize() const; virtual DataBuffer Serialize(bool packetID = true) const;
virtual void Deserialize(DataBuffer& data); virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const; virtual void Dispatch(PacketHandler* handler) const;
std::uint8_t getConnectionID() const { return m_ConnectionID; } std::uint8_t GetConnectionID() const { return m_ConnectionID; }
virtual PacketType getType() const { return PacketType::ConnectionInfo; } virtual PacketType GetType() const { return PacketType::ConnectionInfo; }
}; };
class SelectTeamPacket : public Packet { class SelectTeamPacket : public Packet {
private: private:
game::TeamColor m_SelectedTeam; game::TeamColor m_SelectedTeam;
public: public:
SelectTeamPacket() {} SelectTeamPacket() {}
SelectTeamPacket(game::TeamColor selectedTeam) : m_SelectedTeam(selectedTeam) {} SelectTeamPacket(game::TeamColor selectedTeam) : m_SelectedTeam(selectedTeam) {}
virtual ~SelectTeamPacket() {} virtual ~SelectTeamPacket() {}
virtual DataBuffer Serialize() const; virtual DataBuffer Serialize(bool packetID = true) const;
virtual void Deserialize(DataBuffer& data); virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const; virtual void Dispatch(PacketHandler* handler) const;
game::TeamColor getSelectedTeam() const { return m_SelectedTeam; } game::TeamColor GetSelectedTeam() const { return m_SelectedTeam; }
virtual PacketType getType() const { return PacketType::SelectTeam; } virtual PacketType GetType() const { return PacketType::SelectTeam; }
}; };
class UpdatePlayerTeamPacket : public Packet { class UpdatePlayerTeamPacket : public Packet {
private: private:
std::uint8_t m_PlayerID; std::uint8_t m_PlayerID;
game::TeamColor m_SelectedTeam; game::TeamColor m_SelectedTeam;
public: public:
UpdatePlayerTeamPacket() {} UpdatePlayerTeamPacket() {}
UpdatePlayerTeamPacket(std::uint8_t playerID, game::TeamColor selectedTeam) : m_PlayerID(playerID), m_SelectedTeam(selectedTeam) {} UpdatePlayerTeamPacket(std::uint8_t playerID, game::TeamColor selectedTeam) : m_PlayerID(playerID), m_SelectedTeam(selectedTeam) {}
virtual ~UpdatePlayerTeamPacket() {} virtual ~UpdatePlayerTeamPacket() {}
virtual DataBuffer Serialize() const; virtual DataBuffer Serialize(bool packetID = true) const;
virtual void Deserialize(DataBuffer& data); virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const; virtual void Dispatch(PacketHandler* handler) const;
game::TeamColor getSelectedTeam() const { return m_SelectedTeam; } game::TeamColor GetSelectedTeam() const { return m_SelectedTeam; }
std::uint8_t getPlayerID() const { return m_PlayerID; } std::uint8_t GetPlayerID() const { return m_PlayerID; }
virtual PacketType getType() const { return PacketType::UpdatePlayerTeam; } virtual PacketType GetType() const { return PacketType::UpdatePlayerTeam; }
}; };
class DisconnectPacket : public Packet { class DisconnectPacket : public Packet {
private: private:
std::string m_Reason; // only when sent from server std::string m_Reason; // only when sent from server
public: public:
DisconnectPacket() {} DisconnectPacket() {}
DisconnectPacket(std::string reason) : m_Reason(reason) {} DisconnectPacket(std::string reason) : m_Reason(reason) {}
virtual ~DisconnectPacket() {} virtual ~DisconnectPacket() {}
virtual DataBuffer Serialize() const; virtual DataBuffer Serialize(bool packetID = true) const;
virtual void Deserialize(DataBuffer& data); virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const; virtual void Dispatch(PacketHandler* handler) const;
const std::string& getReason() const { return m_Reason; } const std::string& GetReason() const { return m_Reason; }
virtual PacketType getType() const { return PacketType::Disconnect; } virtual PacketType GetType() const { return PacketType::Disconnect; }
}; };
class ServerTpsPacket : public Packet { class ServerTpsPacket : public Packet {
private: private:
float m_TPS; float m_TPS;
std::uint64_t m_PacketSendTime; // used to calculate ping float m_MSPT;
std::uint64_t m_PacketSendTime; // used to calculate ping
public: public:
ServerTpsPacket() {} ServerTpsPacket() {}
ServerTpsPacket(float tps, std::uint64_t sendTime) : m_TPS(tps), m_PacketSendTime(sendTime) {} ServerTpsPacket(float tps, float mspt, std::uint64_t sendTime) : m_TPS(tps), m_MSPT(mspt), m_PacketSendTime(sendTime) {}
virtual ~ServerTpsPacket() {} virtual ~ServerTpsPacket() {}
virtual DataBuffer Serialize() const; virtual DataBuffer Serialize(bool packetID = true) const;
virtual void Deserialize(DataBuffer& data); virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const; virtual void Dispatch(PacketHandler* handler) const;
float getTPS() const { return m_TPS; } float GetTPS() const { return m_TPS; }
std::uint64_t getPacketSendTime() const { return m_PacketSendTime; } float GetMSPT() const { return m_MSPT; }
std::uint64_t GetPacketSendTime() const { return m_PacketSendTime; }
virtual PacketType getType() const { return PacketType::ServerTps; } virtual PacketType GetType() const { return PacketType::ServerTps; }
}; };
struct MobSend { // represents a mob send struct MobSend { // represents a mob send
game::MobType mobType; game::MobType mobType : 4;
game::MobLevel mobLevel; game::MobLevel mobLevel : 4;
std::uint8_t mobCount; // the max is 12 std::uint8_t mobCount; // the max is 12
}; };
class SendMobsPacket : public Packet { class SendMobsPacket : public Packet {
private: private:
std::vector<MobSend> m_MobSends; std::vector<MobSend> m_MobSends;
public: public:
SendMobsPacket() {} SendMobsPacket() {}
SendMobsPacket(const std::vector<MobSend>& mobSends) : m_MobSends(mobSends) {} SendMobsPacket(const std::vector<MobSend>& mobSends) : m_MobSends(mobSends) {}
virtual ~SendMobsPacket() {} virtual ~SendMobsPacket() {}
virtual DataBuffer Serialize() const; virtual DataBuffer Serialize(bool packetID = true) const;
virtual void Deserialize(DataBuffer& data); virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const; virtual void Dispatch(PacketHandler* handler) const;
const std::vector<MobSend>& getMobSends() const { return m_MobSends; } const std::vector<MobSend>& GetMobSends() const { return m_MobSends; }
virtual PacketType getType() const { return PacketType::SendMobs; } virtual PacketType GetType() const { return PacketType::SendMobs; }
}; };
class SpawnMobPacket : public Packet { class SpawnMobPacket : public Packet {
private: private:
game::MobID m_MobID; game::MobID m_MobID;
game::MobType m_MobType; game::MobType m_MobType;
game::MobLevel m_MobLevel; game::MobLevel m_MobLevel;
game::Direction m_MobDirection; game::Direction m_MobDirection;
game::PlayerID m_Sender; game::PlayerID m_Sender;
float m_MobX, m_MobY; float m_MobX, m_MobY;
public: public:
SpawnMobPacket() {} SpawnMobPacket() {}
SpawnMobPacket(game::MobID id, game::MobType type, std::uint8_t level, game::PlayerID sender, SpawnMobPacket(game::MobID id, game::MobType type, std::uint8_t level, game::PlayerID sender,
float x, float y, game::Direction dir) : m_MobID(id), m_MobType(type), m_MobLevel(level), float x, float y, game::Direction dir) : m_MobID(id), m_MobType(type), m_MobLevel(level),
m_MobDirection(dir), m_Sender(sender), m_MobX(x), m_MobY(y) {} m_MobDirection(dir), m_Sender(sender), m_MobX(x), m_MobY(y) {
virtual ~SpawnMobPacket() {} }
virtual ~SpawnMobPacket() {}
virtual DataBuffer Serialize() const; virtual DataBuffer Serialize(bool packetID = true) const;
virtual void Deserialize(DataBuffer& data); virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const; virtual void Dispatch(PacketHandler* handler) const;
game::MobID getMobID() const { return m_MobID; } game::MobID GetMobID() const { return m_MobID; }
game::MobType getMobType() const { return m_MobType; } game::MobType GetMobType() const { return m_MobType; }
game::MobLevel getMobLevel() const { return m_MobLevel; } game::MobLevel GetMobLevel() const { return m_MobLevel; }
game::Direction getMobDirection() const { return m_MobDirection; } game::Direction GetMobDirection() const { return m_MobDirection; }
game::PlayerID getSender() const { return m_Sender; } game::PlayerID GetSender() const { return m_Sender; }
float getMobX() const { return m_MobX; } float GetMobX() const { return m_MobX; }
float getMobY() const { return m_MobY; } float GetMobY() const { return m_MobY; }
virtual PacketType getType() const { return PacketType::SpawnMob; } virtual PacketType GetType() const { return PacketType::SpawnMob; }
}; };
class PlaceTowerPacket : public Packet { class PlaceTowerPacket : public Packet {
private: private:
std::int32_t m_TowerX, m_TowerY; std::int32_t m_TowerX, m_TowerY;
game::TowerType m_TowerType; game::TowerType m_TowerType;
public: public:
PlaceTowerPacket() {} PlaceTowerPacket() {}
PlaceTowerPacket(std::int32_t x, std::int32_t y, game::TowerType type) : PlaceTowerPacket(std::int32_t x, std::int32_t y, game::TowerType type) :
m_TowerX(x), m_TowerY(y), m_TowerType(type) {} m_TowerX(x), m_TowerY(y), m_TowerType(type) {
virtual ~PlaceTowerPacket() {} }
virtual ~PlaceTowerPacket() {}
virtual DataBuffer Serialize() const; virtual DataBuffer Serialize(bool packetID = true) const;
virtual void Deserialize(DataBuffer& data); virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const; virtual void Dispatch(PacketHandler* handler) const;
std::int32_t getTowerX() const { return m_TowerX; } std::int32_t GetTowerX() const { return m_TowerX; }
std::int32_t getTowerY() const { return m_TowerY; } std::int32_t GetTowerY() const { return m_TowerY; }
game::TowerType getTowerType() const { return m_TowerType; } game::TowerType GetTowerType() const { return m_TowerType; }
virtual PacketType getType() const { return PacketType::PlaceTower; } virtual PacketType GetType() const { return PacketType::PlaceTower; }
}; };
class WorldAddTowerPacket : public Packet { class WorldAddTowerPacket : public Packet {
private: private:
game::TowerID m_TowerID; game::TowerID m_TowerID;
std::int32_t m_TowerX, m_TowerY; std::int32_t m_TowerX, m_TowerY;
game::TowerType m_TowerType; game::TowerType m_TowerType;
game::PlayerID m_Builder; game::PlayerID m_Builder;
public: public:
WorldAddTowerPacket() {} WorldAddTowerPacket() {}
WorldAddTowerPacket(game::TowerID id, std::int32_t x, std::int32_t y, game::TowerType type, game::PlayerID player) : WorldAddTowerPacket(game::TowerID id, std::int32_t x, std::int32_t y, game::TowerType type, game::PlayerID player) :
m_TowerID(id), m_TowerX(x), m_TowerY(y), m_TowerType(type), m_Builder(player) {} m_TowerID(id), m_TowerX(x), m_TowerY(y), m_TowerType(type), m_Builder(player) {
virtual ~WorldAddTowerPacket() {} }
virtual ~WorldAddTowerPacket() {}
virtual DataBuffer Serialize() const; virtual DataBuffer Serialize(bool packetID = true) const;
virtual void Deserialize(DataBuffer& data); virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const; virtual void Dispatch(PacketHandler* handler) const;
game::TowerID getTowerID() const { return m_TowerID; } game::TowerID GetTowerID() const { return m_TowerID; }
std::int32_t getTowerX() const { return m_TowerX; } std::int32_t GetTowerX() const { return m_TowerX; }
std::int32_t getTowerY() const { return m_TowerY; } std::int32_t GetTowerY() const { return m_TowerY; }
game::TowerType getTowerType() const { return m_TowerType; } game::TowerType GetTowerType() const { return m_TowerType; }
game::PlayerID getBuilder() const { return m_Builder; } game::PlayerID GetBuilder() const { return m_Builder; }
virtual PacketType getType() const { return PacketType::WorldAddTower; } virtual PacketType GetType() const { return PacketType::WorldAddTower; }
}; };
class RemoveTowerPacket : public Packet { class RemoveTowerPacket : public Packet {
private: private:
game::TowerID m_TowerID; game::TowerID m_TowerID;
public: public:
RemoveTowerPacket() {} RemoveTowerPacket() {}
RemoveTowerPacket(game::TowerID id) : m_TowerID(id) {} RemoveTowerPacket(game::TowerID id) : m_TowerID(id) {}
virtual ~RemoveTowerPacket() {} virtual ~RemoveTowerPacket() {}
virtual DataBuffer Serialize() const; virtual DataBuffer Serialize(bool packetID = true) const;
virtual void Deserialize(DataBuffer& data); virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const; virtual void Dispatch(PacketHandler* handler) const;
game::TowerID getTowerID() const { return m_TowerID; } game::TowerID GetTowerID() const { return m_TowerID; }
virtual PacketType getType() const { return PacketType::RemoveTower; } virtual PacketType GetType() const { return PacketType::RemoveTower; }
}; };
class UpgradeTowerPacket : public Packet { class UpgradeTowerPacket : public Packet {
private: private:
game::TowerID m_TowerID; game::TowerID m_TowerID;
game::TowerLevel m_TowerLevel; game::TowerLevel m_TowerLevel;
public: public:
UpgradeTowerPacket() {} UpgradeTowerPacket() {}
UpgradeTowerPacket(game::TowerID tower, game::TowerLevel level) : m_TowerID(tower), m_TowerLevel(level) {} UpgradeTowerPacket(game::TowerID tower, game::TowerLevel level) : m_TowerID(tower), m_TowerLevel(level) {}
virtual ~UpgradeTowerPacket() {} virtual ~UpgradeTowerPacket() {}
virtual DataBuffer Serialize() const; virtual DataBuffer Serialize(bool packetID = true) const;
virtual void Deserialize(DataBuffer& data); virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const; virtual void Dispatch(PacketHandler* handler) const;
game::TowerID getTowerID() const { return m_TowerID; } game::TowerID GetTowerID() const { return m_TowerID; }
game::TowerLevel getTowerLevel() const { return m_TowerLevel; } game::TowerLevel GetTowerLevel() const { return m_TowerLevel; }
virtual PacketType getType() const { return PacketType::UpgradeTower; } virtual PacketType GetType() const { return PacketType::UpgradeTower; }
}; };
class MobState { class MobState {
using Point = utils::shape::Point; using Point = utils::shape::Point;
private: private:
game::MobID m_MobID; game::MobID m_MobID;
Point m_MobPosition; Point m_MobPosition;
float m_MobLife; float m_MobLife;
game::Direction m_MobDirection; game::Direction m_MobDirection;
public: public:
MobState() {} MobState() {}
MobState(game::MobID id, Point position, float life, game::Direction direction) : MobState(game::MobID id, const Point& position, float life, game::Direction direction) :
m_MobID(id), m_MobPosition(position), m_MobLife(life), m_MobDirection(direction) {} m_MobID(id), m_MobPosition(position), m_MobLife(life), m_MobDirection(direction) {
}
game::MobID getMobId() const { return m_MobID; } game::MobID GetMobId() const { return m_MobID; }
Point getMobPosition() const { return m_MobPosition; } Point GetMobPosition() const { return m_MobPosition; }
float getMobLife() const { return m_MobLife; } float GetMobLife() const { return m_MobLife; }
game::Direction getMobDirection() const { return m_MobDirection; } game::Direction GetMobDirection() const { return m_MobDirection; }
}; };
class UpdateMobStatesPacket : public Packet { class UpdateMobStatesPacket : public Packet {
private: private:
std::vector<MobState> m_MobStates; std::vector<MobState> m_MobStates;
public: public:
UpdateMobStatesPacket() {} UpdateMobStatesPacket() {}
virtual ~UpdateMobStatesPacket() {} virtual ~UpdateMobStatesPacket() {}
virtual DataBuffer Serialize() const; virtual DataBuffer Serialize(bool packetID = true) const;
virtual void Deserialize(DataBuffer& data); virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const; virtual void Dispatch(PacketHandler* handler) const;
void addMobState(MobState mobState) { m_MobStates.push_back(mobState); } void addMobState(MobState mobState) { m_MobStates.push_back(mobState); }
const std::vector<MobState>& getMobStates() const { return m_MobStates; } const std::vector<MobState>& GetMobStates() const { return m_MobStates; }
virtual PacketType getType() const { return PacketType::UpdateMobStates; } virtual PacketType GetType() const { return PacketType::UpdateMobStates; }
}; };
class UpdateCastleLifePacket : public Packet { class UpdateCastleLifePacket : public Packet {
private: private:
std::uint16_t m_CastleLife; std::uint16_t m_CastleLife;
game::TeamColor m_Team; game::TeamColor m_Team;
public: public:
UpdateCastleLifePacket() {} UpdateCastleLifePacket() {}
UpdateCastleLifePacket(std::uint16_t life, game::TeamColor team) : m_CastleLife(life), m_Team(team) {} UpdateCastleLifePacket(std::uint16_t life, game::TeamColor team) : m_CastleLife(life), m_Team(team) {}
virtual ~UpdateCastleLifePacket() {} virtual ~UpdateCastleLifePacket() {}
virtual DataBuffer Serialize() const; virtual DataBuffer Serialize(bool packetID = true) const;
virtual void Deserialize(DataBuffer& data); virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const; virtual void Dispatch(PacketHandler* handler) const;
std::uint16_t getCastleLife() const { return m_CastleLife; } std::uint16_t GetCastleLife() const { return m_CastleLife; }
game::TeamColor getTeamColor() const { return m_Team; } game::TeamColor GetTeamColor() const { return m_Team; }
virtual PacketType getType() const { return PacketType::UpdateCastleLife; } virtual PacketType GetType() const { return PacketType::UpdateCastleLife; }
}; };
} enum class ItemType : std::uint8_t {
} // Upgrades
ClickerUpgrade,
GoldPerSecUpgrade,
// Items
};
/** Packet used by the client to buy items or upgrades
Packet used by the server to confirm transaction */
class PlayerBuyItemPacket : public Packet {
private:
ItemType m_ItemType;
std::uint8_t m_Count;
public:
PlayerBuyItemPacket() {}
PlayerBuyItemPacket(ItemType itemType, std::uint8_t count) : m_ItemType(itemType), m_Count(count) {}
virtual ~PlayerBuyItemPacket() {}
virtual DataBuffer Serialize(bool packetID = true) const;
virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const;
ItemType GetItemType() const { return m_ItemType; }
std::uint8_t GetCount() const { return m_Count; }
virtual PacketType GetType() const { return PacketType::PlayerBuyItem; }
};
/** Packet used by the client to buy mob upgrades
Packet used by the server to confirm transaction */
class PlayerBuyMobUpgradePacket : public Packet {
private:
game::MobType m_MobType;
std::uint8_t m_MobLevel;
public:
PlayerBuyMobUpgradePacket() {}
PlayerBuyMobUpgradePacket(game::MobType mobType, std::uint8_t level) : m_MobType(mobType), m_MobLevel(level) {}
virtual ~PlayerBuyMobUpgradePacket() {}
virtual DataBuffer Serialize(bool packetID = true) const;
virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const;
game::MobType GetMobType() const { return m_MobType; }
std::uint8_t GetLevel() const { return m_MobLevel; }
virtual PacketType GetType() const { return PacketType::PlayerBuyMobUpgrade; }
};
} // namespace protocol
} // namespace td

View File

@@ -1,8 +1,62 @@
#pragma once #pragma once
#ifdef __ANDROID__ #if !defined(TD_IMPL_OPENGL_ES2) \
#include <GLES3/gl3.h> && !defined(TD_IMPL_OPENGL_ES3) \
&& !defined(TD_IMPL_OPENGL_LOADER_GL3W) \
&& !defined(TD_IMPL_OPENGL_LOADER_GLEW) \
&& !defined(TD_IMPL_OPENGL_LOADER_GLAD) \
&& !defined(TD_IMPL_OPENGL_LOADER_GLBINDING2) \
&& !defined(TD_IMPL_OPENGL_LOADER_GLBINDING3) \
&& !defined(TD_IMPL_OPENGL_LOADER_CUSTOM) \
&& !defined(__ANDROID__)
#if defined(__has_include)
#if __has_include(<GL/glew.h>)
#define TD_IMPL_OPENGL_LOADER_GLEW
#elif __has_include(<glad/glad.h>)
#define TD_IMPL_OPENGL_LOADER_GLAD
#elif __has_include(<GL/gl3w.h>)
#define TD_IMPL_OPENGL_LOADER_GL3W
#elif __has_include(<glbinding/glbinding.h>)
#define TD_IMPL_OPENGL_LOADER_GLBINDING3
#elif __has_include(<glbinding/Binding.h>)
#define TD_IMPL_OPENGL_LOADER_GLBINDING2
#else #else
#include "glbinding/gl/gl.h" #error "Cannot detect OpenGL loader!"
using namespace gl; #endif
#else
#error "Cannot detect loader with include detection !"
#endif
#endif
// Include correct files
#if defined(__ANDROID__)
#include <GLES3/gl3.h>
#elif defined(TD_IMPL_OPENGL_LOADER_GL3W)
#include <GL/gl3w.h> // Needs to be initialized with gl3wInit() in user's code
#elif defined(TD_IMPL_OPENGL_LOADER_GLEW)
#include <GL/glew.h> // Needs to be initialized with glewInit() in user's code.
#elif defined(TD_IMPL_OPENGL_LOADER_GLAD)
#include <glad/glad.h> // Needs to be initialized with gladLoadGL() in user's code.
#elif defined(TD_IMPL_OPENGL_LOADER_GLBINDING2)
#ifndef GLFW_INCLUDE_NONE
#define GLFW_INCLUDE_NONE // GLFW including OpenGL headers causes ambiguity or multiple definition errors.
#endif
#include <glbinding/Binding.h> // Needs to be initialized with glbinding::Binding::initialize() in user's code.
#include <glbinding/gl/gl.h>
using namespace gl;
#elif defined(TD_IMPL_OPENGL_LOADER_GLBINDING3)
#ifndef GLFW_INCLUDE_NONE
#define GLFW_INCLUDE_NONE // GLFW including OpenGL headers causes ambiguity or multiple definition errors.
#endif
#include <glbinding/glbinding.h>// Needs to be initialized with glbinding::initialize() in user's code.
#include <glbinding/gl/gl.h>
using namespace gl;
#else
#include TD_IMPL_OPENGL_LOADER_CUSTOM
#endif #endif

View File

@@ -1,14 +1,6 @@
/* #pragma once
* Renderer.h
*
* Created on: 4 nov. 2020
* Author: simon
*/
#ifndef RENDER_RENDERER_H_ #include "Defines.h"
#define RENDER_RENDERER_H_
#include <glm/glm.hpp>
#include <memory> #include <memory>
#include "loader/GLLoader.h" #include "loader/GLLoader.h"
#include "render/shaders/WorldShader.h" #include "render/shaders/WorldShader.h"
@@ -17,50 +9,63 @@
namespace td { namespace td {
namespace render { namespace render {
struct Camera {
Mat4f viewMatrix;
Mat4f projectionMatrix;
Mat4f InvViewMatrix;
Mat4f InvProjectionMatrix;
float CamDistance = 25.0f;
Vec3f CamPos {0, CamDistance, 0};
Vec2f CamLook {};
float m_Yaw = -PI / 2.0f;
float m_Pitch = -PI / 2.0f + 0.0000001f;
};
class Renderer { class Renderer {
public: public:
static constexpr float m_AnimationSpeed = 2.0f; static constexpr float m_AnimationSpeed = 2.0f;
static constexpr float m_MouseSensitivity = 200.0f;
struct Model { struct Model {
GL::VertexArray* vao; GL::VertexArray* vao;
glm::vec2 positon; Vec3f positon;
}; Vec3f color = { 1, 1, 1 };
};
private: private:
std::unique_ptr<WorldShader> m_WorldShader; std::unique_ptr<shader::WorldShader> m_WorldShader;
std::unique_ptr<EntityShader> m_EntityShader; std::unique_ptr<shader::EntityShader> m_EntityShader;
glm::vec3 m_BackgroundColor; Vec2i m_WindowSize;
bool m_IsometricView = true; Vec3f m_BackgroundColor;
float m_IsometricShade = m_IsometricView;
glm::vec2 m_CamPos{}; Camera m_Camera {};
public: public:
Renderer(); Renderer();
~Renderer(); ~Renderer();
bool init(); bool Init();
void prepare(); void Prepare();
void resize(const int width, const int height); void Resize(const int width, const int height);
void renderVAO(const GL::VertexArray& vao); void RenderVAO(const GL::VertexArray& vao);
void renderModel(const Model& model); void RenderModel(const Model& model);
void setZoom(float zoom); void AddZoom(float zoom);
void setCamMovement(const glm::vec2& mov); void SetCamAngularMovement(const Vec2f& mov);
void setCamPos(const glm::vec2& newPos); void SetCamMovement(const Vec2f& lastCursorPos, const Vec2f& currentCursorPos);
void setIsometricView(bool isometric); // false = 2D true = Isometric void SetCamLook(const Vec2f& worldPos);
void setBackgroundColor(const glm::vec3& color) { m_BackgroundColor = color; } void SetBackgroundColor(const Vec3f& color) { m_BackgroundColor = color; }
glm::vec2 getCursorWorldPos(const glm::vec2& cursorPos, float aspectRatio, float zoom, float windowWidth, float windowHeight); Vec2f GetCursorWorldPos(const Vec2f& cursorPos, float windowWidth, float windowHeight);
private: private:
void updateIsometricView(); void InitShaders();
void updateIsometricFade(); void SetCamPos(const Vec3f& newPos);
void initShader();
}; };
} // namespace render } // namespace render
} // namespace td } // namespace td
#endif /* RENDER_RENDERER_H_ */

View File

@@ -11,27 +11,27 @@ namespace render {
class VertexCache { class VertexCache {
typedef std::vector<float> Vector; typedef std::vector<float> Vector;
struct DataIndex { struct DataIndex {
Vector position; Vector position;
Vector color; Vector color;
}; };
private: private:
std::size_t m_VertexCount; std::size_t m_VertexCount;
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) {} 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();
void updateVertexArray(); void UpdateVertexArray();
const GL::VertexArray& getVertexArray() const { return *m_VertexArray; } const GL::VertexArray& GetVertexArray() const { return *m_VertexArray; }
bool isEmpty() const { return m_VertexArray == nullptr; } bool IsEmpty() const { return m_VertexArray == nullptr; }
}; };
} // namespace render } // namespace render

View File

@@ -6,13 +6,12 @@
#include "render/VertexCache.h" #include "render/VertexCache.h"
#include "render/gui/TowerPlacePopup.h" #include "render/gui/TowerPlacePopup.h"
#include "render/gui/TowerUpgradePopup.h"
#include "render/gui/MobTooltip.h" #include "render/gui/MobTooltip.h"
#include "render/gui/CastleTooltip.h" #include "render/gui/CastleTooltip.h"
#include "render/gui/imgui/imgui.h" #include "render/gui/imgui/imgui.h"
#include <glm/glm.hpp>
namespace td { namespace td {
namespace client { namespace client {
@@ -26,61 +25,61 @@ namespace render {
class WorldRenderer : public game::WorldListener { class WorldRenderer : public game::WorldListener {
private: private:
client::ClientGame* m_Client; client::ClientGame* m_Client;
Renderer* m_Renderer; Renderer* m_Renderer;
game::World* m_World; game::World* m_World;
std::unique_ptr<GL::VertexArray> m_WorldVao, m_MobVao, m_SelectTileVao; std::unique_ptr<GL::VertexArray> m_WorldVao, m_MobVao, m_SelectTileVao;
glm::vec2 m_CamPos; Vec2f m_CamPos;
glm::vec2 m_CursorPos; Vec2f m_CursorPos;
glm::vec2 m_HoldCursorPos; Vec2f m_HoldCursorPos;
glm::vec2 m_LastClicked; Vec2f m_LastClicked;
float m_Zoom; float m_Zoom;
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::TowerUpgradePopup> m_TowerUpgradePopup;
std::unique_ptr<gui::CastleTooltip> m_CastleTooltip; std::unique_ptr<gui::MobTooltip> m_MobTooltip;
std::unique_ptr<gui::CastleTooltip> m_CastleTooltip;
public: public:
WorldRenderer(game::World* world, client::ClientGame* client); WorldRenderer(game::World* world, client::ClientGame* client);
~WorldRenderer(); ~WorldRenderer();
void loadModels(); void LoadModels();
static ImVec4 getImGuiTeamColor(game::TeamColor color); static ImVec4 GetImGuiTeamColor(game::TeamColor color);
void update(); void Update();
void render(); void Render();
void setCamPos(float camX, float camY); void SetCamPos(float camX, float camY);
void moveCam(float relativeX, float relativeY, float aspectRatio); void MoveCam(float relativeX, float relativeY);
void changeZoom(float zoom); void ChangeZoom(float zoom);
// WorldListener // WorldListener
virtual void OnTowerAdd(game::TowerPtr tower); virtual void OnTowerAdd(game::TowerPtr tower);
virtual void OnTowerRemove(game::TowerPtr tower); virtual void OnTowerRemove(game::TowerPtr tower);
private: private:
void click(); void Click();
void renderWorld() const; void RenderWorld() const;
void renderTowers() const; void RenderTowers() const;
void renderMobs() const; void RenderMobs() const;
void renderTileSelect() const; void RenderTileSelect() const;
void renderPopups(); void RenderPopups();
void renderTowerUpgradePopup(); void RenderMobTooltip() const;
void renderMobTooltip() const; void RenderCastleTooltip() const;
void renderCastleTooltip() const; void DetectClick();
void detectClick(); void DetectMobHovering() const;
void detectMobHovering() const; void DetectCastleHovering() const;
void detectCastleHovering() const; void RenderTooltips() const;
void renderTooltips() const; void RemoveTower();
void removeTower(); Vec2f GetCursorWorldPos() const;
glm::vec2 getCursorWorldPos() const; Vec2f GetClickWorldPos() const;
glm::vec2 getClickWorldPos() const;
void updateCursorPos(); void UpdateCursorPos();
}; };
} // namespace render } // namespace render

View File

@@ -14,14 +14,14 @@ namespace gui {
class CastleTooltip : public GuiWidget { class CastleTooltip : public GuiWidget {
private: private:
const game::TeamCastle* m_Castle; const game::TeamCastle* m_Castle;
public: public:
CastleTooltip(client::Client* client); CastleTooltip(client::Client* client);
virtual void render(); virtual void Render();
void setCastle(const game::TeamCastle* castle) { m_Castle = castle; } void SetCastle(const game::TeamCastle* castle) { m_Castle = castle; }
bool isShown() { return m_Castle != nullptr; } bool IsShown() { return m_Castle != nullptr; }
}; };
} // namespace gui } // namespace gui

View File

@@ -7,13 +7,13 @@ namespace gui {
class FrameMenu : public GuiWidget { class FrameMenu : public GuiWidget {
private: private:
bool m_VSync; bool m_VSync;
bool m_IsometricView; bool m_IsometricView;
bool m_ShowDemoWindow; bool m_ShowDemoWindow;
public: public:
FrameMenu(client::Client* client); FrameMenu(client::Client* client);
virtual void render(); virtual void Render();
}; };
} // namespace gui } // namespace gui

View File

@@ -7,17 +7,17 @@ namespace gui {
class GameMenu : public GuiWidget { class GameMenu : public GuiWidget {
private: private:
std::unique_ptr<SummonMenu> m_SummonMenu; std::unique_ptr<SummonMenu> m_SummonMenu;
public: public:
GameMenu(client::Client* client); GameMenu(client::Client* client);
virtual void render(); virtual void Render();
private: private:
void showTPS(); void ShowTPS();
void showStats(); void ShowStats();
void showPlayers(); void ShowPlayers();
void showLobbyProgress(); void ShowLobbyProgress();
void showTeamSelection(); void ShowTeamSelection();
}; };
} // namespace gui } // namespace gui

View File

@@ -10,19 +10,19 @@ namespace gui {
class GuiManager { class GuiManager {
private: private:
std::vector<std::unique_ptr<GuiWidget>> m_Widgets; std::vector<std::unique_ptr<GuiWidget>> m_Widgets;
public: public:
GuiManager(){} GuiManager() {}
void renderWidgets() { void RenderWidgets() {
for (auto& widget : m_Widgets) { for (auto& widget : m_Widgets) {
widget->render(); widget->Render();
} }
} }
void addWidget(std::unique_ptr<GuiWidget>&& widget) { void AddWidget(std::unique_ptr<GuiWidget>&& widget) {
m_Widgets.push_back(std::move(widget)); m_Widgets.push_back(std::move(widget));
} }
}; };
} // namespace gui } // namespace gui

View File

@@ -10,13 +10,13 @@ namespace gui {
class GuiWidget { class GuiWidget {
protected: protected:
client::Client* m_Client; client::Client* m_Client;
public: public:
GuiWidget(client::Client* client) : m_Client(client) {} GuiWidget(client::Client* client) : m_Client(client) {}
client::Client* getClient() { return m_Client; } client::Client* GetClient() { return m_Client; }
virtual void render() = 0; virtual void Render() = 0;
}; };
} // namespace gui } // namespace gui

View File

@@ -0,0 +1,9 @@
#pragma once
namespace td {
namespace gui {
extern void RenderLifeProgress(float progress);
} // namespace gui
} // namespace td

View File

@@ -13,24 +13,24 @@ namespace gui {
class MainMenu : public GuiWidget { class MainMenu : public GuiWidget {
private: private:
bool m_TriedToConnect = false; bool m_TriedToConnect = false;
bool m_TriedToCreate = false; bool m_TriedToCreate = false;
std::string m_ConnectAddress; std::string m_ConnectAddress;
int m_ConnectPort; int m_ConnectPort;
int m_ServerPort = 25565; int m_ServerPort = 25565;
std::string m_WorldFilePath; std::string m_WorldFilePath;
imgui_addons::ImGuiFileBrowser m_FileDialog; imgui_addons::ImGuiFileBrowser m_FileDialog;
std::unique_ptr<server::Server> m_Server; std::unique_ptr<server::Server> m_Server;
public: public:
MainMenu(client::Client* client); MainMenu(client::Client* client);
~MainMenu(); ~MainMenu();
virtual void render(); virtual void Render();
const server::Server* getServer() const { return m_Server.get(); } const server::Server* GetServer() const { return m_Server.get(); }
private: private:
bool startServer(); bool StartServer();
}; };
} // namespace gui } // namespace gui

View File

@@ -14,14 +14,14 @@ namespace gui {
class MobTooltip : public GuiWidget { class MobTooltip : public GuiWidget {
private: private:
const game::Mob* m_Mob; const game::Mob* m_Mob;
public: public:
MobTooltip(client::Client* client); MobTooltip(client::Client* client);
virtual void render(); virtual void Render();
void setMob(const game::Mob* mob) { m_Mob = mob; } void SetMob(const game::Mob* mob) { m_Mob = mob; }
bool isShown() { return m_Mob != nullptr; } bool IsShown() { return m_Mob != nullptr; }
}; };
} // namespace gui } // namespace gui

View File

@@ -10,16 +10,20 @@ 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;
static constexpr int m_MobTypeCount = static_cast<std::size_t>(td::game::MobType::MOB_COUNT); float m_Cooldown;
std::array<int, static_cast<std::size_t>(m_MobTypeCount)> m_Values; float m_LastCooldown;
static constexpr int m_MobTypeCount = static_cast<std::size_t>(td::game::MobType::MOB_COUNT);
std::array<int, static_cast<std::size_t>(m_MobTypeCount)> m_Values;
public: public:
SummonMenu(client::Client* client); SummonMenu(client::Client* client);
virtual void render(); void SetCooldown(float cooldown);
virtual void Render();
private: private:
void setSummonMax(int valueIndex); void SetSummonMax(int valueIndex);
}; };
} // namespace gui } // namespace gui

View File

@@ -28,21 +28,21 @@ class Renderer;
class TowerGui { class TowerGui {
private: private:
SDL_Window* m_Window; SDL_Window* m_Window;
SDL_GLContext m_GlContext; SDL_GLContext m_GlContext;
td::render::Renderer* m_Renderer; td::render::Renderer* m_Renderer;
td::gui::GuiManager m_GuiManager; td::gui::GuiManager m_GuiManager;
std::unique_ptr<td::client::Client> m_Client; std::unique_ptr<td::client::Client> m_Client;
public: public:
TowerGui(SDL_Window* wndow, SDL_GLContext glContext, td::render::Renderer* renderer); TowerGui(SDL_Window* wndow, SDL_GLContext glContext, td::render::Renderer* renderer);
~TowerGui(); ~TowerGui();
void render(); void Render();
private: private:
void initWidgets(); void InitWidgets();
void tick(); void Tick();
void beginFrame(); void BeginFrame();
void endFrame(); void EndFrame();
}; };
} // namespace render } // namespace render

View File

@@ -2,26 +2,26 @@
#include "GuiWidget.h" #include "GuiWidget.h"
#include <glm/glm.hpp> #include "Defines.h"
namespace td { namespace td {
namespace gui { namespace gui {
class TowerPlacePopup : public GuiWidget { class TowerPlacePopup : public GuiWidget {
private: private:
glm::vec2 m_ClickWorldPos; Vec2f m_ClickWorldPos;
public: public:
TowerPlacePopup(client::Client* client); TowerPlacePopup(client::Client* client);
virtual void render(); virtual void Render();
void setClickPos(const glm::vec2& worldPos); void SetClickPos(const Vec2f& worldPos);
private: private:
static constexpr float m_TowerPopupTileWidth = 200.0f; static constexpr float m_TowerPopupTileWidth = 200.0f;
static constexpr float m_TowerPopupTileHeight = 200.0f; static constexpr float m_TowerPopupTileHeight = 200.0f;
static constexpr float m_PlaceTowerButtonWidth = 150.0f; static constexpr float m_PlaceTowerButtonWidth = 150.0f;
static constexpr float m_PlaceTowerButtonHeight = 35.0f; static constexpr float m_PlaceTowerButtonHeight = 35.0f;
}; };
} // namespace gui } // namespace gui

View File

@@ -0,0 +1,32 @@
#pragma once
#include "GuiWidget.h"
#include "Defines.h"
namespace td {
namespace gui {
class TowerUpgradePopup : public GuiWidget {
private:
Vec2f m_ClickWorldPos;
bool m_ShouldBeClosed;
bool m_Opened;
public:
TowerUpgradePopup(client::Client* client);
virtual void Render();
void SetClickPos(const Vec2f& worldPos);
bool IsPopupOpened();
private:
static constexpr float m_TowerPopupTileWidth = 200.0f;
static constexpr float m_TowerPopupTileHeight = 200.0f;
static constexpr float m_PlaceTowerButtonWidth = 150.0f;
static constexpr float m_PlaceTowerButtonHeight = 35.0f;
};
} // namespace gui
} // namespace td

View File

@@ -2,27 +2,34 @@
#include "GuiWidget.h" #include "GuiWidget.h"
#include "updater/Updater.h"
#include <future> #include <future>
#include <memory>
namespace td { namespace td {
namespace utils {
class Updater;
} // namespace utils
namespace gui { namespace gui {
class UpdateMenu : public GuiWidget { class UpdateMenu : public GuiWidget {
private: private:
bool m_Opened; bool m_Opened;
std::string m_Error; std::string m_Error;
utils::Updater m_Updater; std::unique_ptr<utils::Updater> m_Updater;
std::shared_future<bool> m_UpdateAvailable; std::shared_future<bool> m_UpdateAvailable;
public: public:
UpdateMenu(client::Client* client); UpdateMenu(client::Client* client);
virtual ~UpdateMenu();
virtual void render(); virtual void Render();
private: private:
void checkUpdates(); void CheckUpdates();
bool isUpdateChecked(); bool IsUpdateChecked();
void renderErrorPopup(); void RenderErrorPopup();
}; };
} // namespace gui } // namespace gui

View File

@@ -107,8 +107,20 @@ namespace ImGui
} }
*/ */
#ifdef __ANDROID__ #include "render/GL.h"
#define IMGUI_IMPL_OPENGL_ES3
#if defined(__ANDROID__)
#define IMGUI_IMPL_OPENGL_LOADER_ES3
#elif defined(TD_IMPL_OPENGL_LOADER_GL3W)
#define IMGUI_IMPL_OPENGL_LOADER_GL3W
#elif defined(TD_IMPL_OPENGL_LOADER_GLEW)
#define IMGUI_IMPL_OPENGL_LOADER_GLEW
#elif defined(TD_IMPL_OPENGL_LOADER_GLAD)
#define IMGUI_IMPL_OPENGL_LOADER_GLAD
#elif defined(TD_IMPL_OPENGL_LOADER_GLBINDING2)
#define IMGUI_IMPL_OPENGL_LOADER_GLBINDING2
#elif defined(TD_IMPL_OPENGL_LOADER_GLBINDING3)
#define IMGUI_IMPL_OPENGL_LOADER_GLBINDING3
#else #else
#define IMGUI_IMPL_OPENGL_LOADER_GLBINDING2 #define IMGUI_IMPL_OPENGL_LOADER_CUSTOM
#endif #endif

View File

@@ -17,8 +17,9 @@
namespace GL { namespace GL {
struct VertexAttribPointer { struct VertexAttribPointer {
unsigned int m_Index, m_Size; unsigned int m_Index;
int m_Offset; unsigned int m_Size;
unsigned int m_Offset;
}; };
class VertexBuffer { class VertexBuffer {
@@ -27,6 +28,7 @@ private:
std::vector<VertexAttribPointer> m_VertexAttribs; std::vector<VertexAttribPointer> m_VertexAttribs;
public: public:
REMOVE_COPY(VertexBuffer); REMOVE_COPY(VertexBuffer);
VertexBuffer(VertexBuffer&& other) { VertexBuffer(VertexBuffer&& other) {
m_VertexAttribs = std::move(other.m_VertexAttribs); m_VertexAttribs = std::move(other.m_VertexAttribs);
m_ID = other.m_ID; m_ID = other.m_ID;
@@ -34,12 +36,14 @@ public:
other.m_ID = 0; other.m_ID = 0;
other.m_DataStride = 0; other.m_DataStride = 0;
} }
VertexBuffer(const std::vector<float>& data, unsigned int stride); VertexBuffer(const std::vector<float>& data, unsigned int stride);
~VertexBuffer(); ~VertexBuffer();
void bind() const;
void unbind() const; void Bind() const;
void addVertexAttribPointer(unsigned int index, unsigned int coordinateSize, unsigned int offset); void Unbind() const;
void bindVertexAttribs() const; void AddVertexAttribPointer(unsigned int index, unsigned int coordinateSize, unsigned int offset);
void BindVertexAttribs() const;
}; };
class VertexArray { class VertexArray {
@@ -48,6 +52,7 @@ private:
std::vector<VertexBuffer> m_VertexBuffers; //use to destroy vbos when become unused std::vector<VertexBuffer> m_VertexBuffers; //use to destroy vbos when become unused
public: public:
REMOVE_COPY(VertexArray); REMOVE_COPY(VertexArray);
VertexArray(VertexArray&& other) { VertexArray(VertexArray&& other) {
m_ID = other.m_ID; m_ID = other.m_ID;
m_VertexCount = other.m_VertexCount; m_VertexCount = other.m_VertexCount;
@@ -55,12 +60,14 @@ public:
other.m_VertexCount = 0; other.m_VertexCount = 0;
other.m_ID = 0; other.m_ID = 0;
} }
VertexArray(unsigned int vertexCount); VertexArray(unsigned int vertexCount);
~VertexArray(); ~VertexArray();
unsigned int getVertexCount() const { return m_VertexCount; }
void bindVertexBuffer(VertexBuffer& vbo); unsigned int GetVertexCount() const { return m_VertexCount; }
void bind() const; void BindVertexBuffer(VertexBuffer& vbo);
void unbind() const; void Bind() const;
void Unbind() const;
}; };
} }

View File

@@ -9,7 +9,9 @@
#define RENDER_LOADER_TEXTURELOADER_H_ #define RENDER_LOADER_TEXTURELOADER_H_
namespace TextureLoader { namespace TextureLoader {
const unsigned int loadGLTexture(const char* fileName);
unsigned int LoadGLTexture(const char* fileName);
} }

View File

@@ -9,14 +9,14 @@ namespace render {
namespace WorldLoader { namespace WorldLoader {
struct RenderData { struct RenderData {
std::vector<float> positions; std::vector<float> positions;
std::vector<float> colors; std::vector<float> colors;
}; };
GL::VertexArray loadMobModel(); GL::VertexArray LoadMobModel();
GL::VertexArray loadWorldModel(const td::game::World* world); GL::VertexArray LoadWorldModel(const td::game::World* world);
GL::VertexArray loadTileSelectModel(); GL::VertexArray LoadTileSelectModel();
RenderData loadTowerModel(game::TowerPtr tower); RenderData LoadTowerModel(game::TowerPtr tower);
} // namespace WorldLoader } // namespace WorldLoader

View File

@@ -2,17 +2,27 @@
#include "ShaderProgram.h" #include "ShaderProgram.h"
namespace td {
namespace shader {
class EntityShader : public ShaderProgram { class EntityShader : public ShaderProgram {
private: private:
unsigned int location_cam = 0, location_zoom = 0, location_aspect_ratio = 0, location_translation = 0, location_viewtype = 0; unsigned int m_LocationProjectionMatrix = 0;
unsigned int m_LocationViewMatrix = 0;
unsigned int m_LocationPosition = 0;
unsigned int m_LocationColorEffect = 0;
protected: protected:
void getAllUniformLocation(); virtual void GetAllUniformLocation();
public: public:
EntityShader(); EntityShader();
void loadShader();
void setCamPos(const glm::vec2& camPos); void LoadShader();
void setZoom(float zoom);
void setAspectRatio(float aspectRatio); void SetColorEffect(const Vec3f& color);
void setModelPos(const glm::vec2& modelPos); void SetProjectionMatrix(const Mat4f& proj) const;
void setIsometricView(float isometric); void SetViewMatrix(const Mat4f& view) const;
void SetModelPos(const Vec3f& pos) const;
}; };
} // namespace shader
} // namespace td

View File

@@ -1,44 +1,43 @@
/* #pragma once
* ShaderProgram.h
*
* Created on: 31 janv. 2020
* Author: simon
*/
#ifndef RENDER_SHADERS_SHADERPROGRAM_H_
#define RENDER_SHADERS_SHADERPROGRAM_H_
#include <string> #include <string>
#include <glm/glm.hpp> #include "Defines.h"
#include "render/GL.h" #include "render/GL.h"
namespace td {
namespace shader {
class ShaderProgram { class ShaderProgram {
public: public:
ShaderProgram(); ShaderProgram();
virtual ~ShaderProgram(); virtual ~ShaderProgram();
void start() const;
void stop() const; void Start() const;
void loadProgramFile(const std::string& vertexFile, const std::string& fragmentFile); void Stop() const;
void loadProgram(const std::string& vertexSource, const std::string& fragmentSource);
void LoadProgramFile(const std::string& vertexFile, const std::string& fragmentFile);
void LoadProgram(const std::string& vertexSource, const std::string& fragmentSource);
protected: protected:
virtual void getAllUniformLocation() = 0; virtual void GetAllUniformLocation() = 0;
int getUniformLocation(const std::string& uniformName)const; int GetUniformLocation(const std::string& uniformName) const;
void loadFloat(const int location, const float value)const;
void loadInt(const int& location, const int& value)const; void LoadFloat(unsigned int location, float value) const;
void loadVector(const int& location, const glm::vec2& vector)const; void LoadInt(unsigned int location, int value) const;
void loadVector(const int& location, const glm::vec3& vector)const; void LoadVector(unsigned int location, const Vec2f& vector) const;
void loadVector(const int& location, const glm::vec4& vector)const; void LoadVector(unsigned int location, const Vec3f& vector) const;
void loadBoolean(const int& location, const bool& value)const; void LoadBoolean(unsigned int location, bool value) const;
void loadMatrix(const int& location, const glm::mat4& matrix); void LoadMat4(unsigned int location, const Mat4f& mat) const;
void cleanUp() const; void CleanUp() const;
private: private:
unsigned int programID; unsigned int m_ProgramID;
unsigned int vertexShaderID; unsigned int m_VertexShaderID;
unsigned int fragmentShaderID; unsigned int m_FragmentShaderID;
int loadShaderFromFile(const std::string& file, GLenum type);
int loadShader(const std::string& source, GLenum type); unsigned int LoadShaderFromFile(const std::string& file, GLenum type);
unsigned int LoadShader(const std::string& source, GLenum type);
}; };
#endif /* RENDER_SHADERS_SHADERPROGRAM_H_ */ } // namespace shader
} // namespace td

View File

@@ -1,27 +1,22 @@
/* #pragma once
* GameShader.h
*
* Created on: 4 nov. 2020
* Author: simon
*/
#ifndef RENDER_SHADERS_GAMESHADER_H_
#define RENDER_SHADERS_GAMESHADER_H_
#include "ShaderProgram.h" #include "ShaderProgram.h"
namespace td {
namespace shader {
class WorldShader : public ShaderProgram { class WorldShader : public ShaderProgram {
private: private:
unsigned int location_cam = 0, location_zoom = 0, location_aspect_ratio = 0, location_viewtype = 0; unsigned int m_LocationProjection = 0, m_LocationView = 0;
protected: protected:
void getAllUniformLocation(); void GetAllUniformLocation();
public: public:
WorldShader(); WorldShader();
void loadShader(); void LoadShader();
void setCamPos(const glm::vec2& camPos);
void setZoom(float zoom); void SetProjectionMatrix(const Mat4f& proj) const;
void setAspectRatio(float aspectRatio); void SetViewMatrix(const Mat4f& view) const;
void setIsometricView(float isometric);
}; };
#endif /* RENDER_SHADERS_GAMESHADER_H_ */ } // namespace shader
} // namespace td

View File

@@ -2,42 +2,42 @@
#include "misc/DataBuffer.h" #include "misc/DataBuffer.h"
#define TD_VERSION "alpha-0.2.0" #define TD_VERSION "alpha-0.3.0"
namespace td { namespace td {
namespace utils { namespace utils {
class Updater { class Updater {
private: private:
float m_Progress; float m_Progress;
bool m_DownloadComplete; bool m_DownloadComplete;
bool m_FileWrited; bool m_FileWrited;
bool m_CancelDownload; bool m_CancelDownload;
DataBuffer m_FileBuffer; DataBuffer m_FileBuffer;
std::string m_LastVersion; std::string m_LastVersion;
public: public:
Updater() : m_Progress(0), m_DownloadComplete(false), m_FileWrited(false), m_CancelDownload(false) {} Updater() : m_Progress(0), m_DownloadComplete(false), m_FileWrited(false), m_CancelDownload(false) {}
bool checkUpdate(); bool CheckUpdate();
void downloadUpdate(); void DownloadUpdate();
void cancelDownload() { m_CancelDownload = true; m_Progress = 0.0f; m_DownloadComplete = false; } void CancelDownload() { m_CancelDownload = true; m_Progress = 0.0f; m_DownloadComplete = false; }
bool writeFile(); bool WriteFile();
void clearCache() { m_FileBuffer.Clear(); } void ClearCache() { m_FileBuffer.Clear(); }
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();
private: private:
std::string getDownloadFileURL(); std::string GetDownloadFileURL();
}; };
} // namespace utils } // namespace utils

View File

@@ -11,19 +11,19 @@
namespace Display { namespace Display {
bool create(); bool Create();
void render(); void Render();
void update(); void Update();
void destroy(); void Destroy();
void pollEvents(); void PollEvents();
bool isCloseRequested(); bool IsCloseRequested();
bool isMouseDown(int button); bool IsMouseDown(int button);
float getAspectRatio(); float GetAspectRatio();
int getWindowWidth(); int GetWindowWidth();
int getWindowHeight(); int GetWindowHeight();
} }

View File

@@ -20,20 +20,20 @@ extern "C"
#endif #endif
int main(int argc, const char* args[]) { int main(int argc, const char* args[]) {
#if !defined(NDEBUG) #if !defined(NDEBUG)
// setup signal handling // setup signal handling
backward::SignalHandling sh; backward::SignalHandling sh;
#endif #endif
// remove the outdated binary // remove the outdated binary
td::utils::Updater::removeOldFile(); td::utils::Updater::RemoveOldFile();
Display::create(); Display::Create();
while (!Display::isCloseRequested()) { while (!Display::IsCloseRequested()) {
Display::pollEvents(); Display::PollEvents();
Display::render(); Display::Render();
Display::update(); Display::Update();
} }
Display::destroy(); Display::Destroy();
return 0; return 0;
} }

View File

@@ -11,26 +11,26 @@ Game::~Game() {
} }
void Game::tick(std::uint64_t delta) { void Game::Tick(std::uint64_t delta) {
if (m_GameState == GameState::Game) { if (m_GameState == GameState::Game) {
m_World->tick(delta); m_World->Tick(delta);
} }
} }
Player* Game::getPlayerById(PlayerID id) { Player* Game::GetPlayerById(PlayerID id) {
auto it = m_Players.find(id); auto it = m_Players.find(id);
if (it == m_Players.end()) return nullptr; if (it == m_Players.end()) return nullptr;
return &it->second; return &it->second;
} }
const Player* Game::getPlayerById(PlayerID id) const { const Player* Game::GetPlayerById(PlayerID id) const {
auto it = m_Players.find(id); auto it = m_Players.find(id);
if (it == m_Players.end()) return nullptr; if (it == m_Players.end()) return nullptr;
return &it->second; return &it->second;
} }
} // namespace game } // namespace game

View File

@@ -28,45 +28,45 @@ Connexion::Connexion(protocol::PacketDispatcher* dispatcher, network::TCPSocket&
} }
bool Connexion::updateSocket() { bool Connexion::UpdateSocket() {
if (m_Socket.GetStatus() != network::Socket::Connected) if (m_Socket.GetStatus() != network::Socket::Connected)
return false; return false;
while (true) { while (true) {
DataBuffer buffer; DataBuffer buffer;
m_Socket.Receive(buffer, sizeof(std::uint64_t)); m_Socket.Receive(buffer, sizeof(std::uint64_t));
if (buffer.GetSize() == 0) if (buffer.GetSize() == 0)
break; break;
std::uint64_t packetLenght; std::uint64_t packetLenght;
buffer >> packetLenght; buffer >> packetLenght;
m_Socket.Receive(buffer, packetLenght); m_Socket.Receive(buffer, packetLenght);
DataBuffer decompressed = utils::Decompress(buffer, packetLenght); DataBuffer decompressed = utils::Decompress(buffer, packetLenght);
protocol::PacketType packetType; protocol::PacketType packetType;
decompressed >> packetType; decompressed >> packetType;
PacketPtr packet = protocol::PacketFactory::createPacket(packetType, decompressed); PacketPtr packet = protocol::PacketFactory::CreatePacket(packetType, decompressed);
GetDispatcher()->Dispatch(packet); GetDispatcher()->Dispatch(packet);
} }
return true; return true;
} }
bool Connexion::connect(const std::string& address, std::uint16_t port) { bool Connexion::Connect(const std::string& address, std::uint16_t port) {
if (!m_Socket.Connect(address, port)) { if (!m_Socket.Connect(address, port)) {
return false; return false;
} }
m_Socket.SetBlocking(false); m_Socket.SetBlocking(false);
return true; return true;
} }
void Connexion::sendPacket(const protocol::Packet* packet) { void Connexion::SendPacket(const protocol::Packet* packet) {
network::SendPacket(packet->Serialize(), m_Socket); network::SendPacket(packet->Serialize(), m_Socket);
} }
void Connexion::closeConnection() { void Connexion::CloseConnection() {
m_Socket.Disconnect(); m_Socket.Disconnect();
} }
Connexion::~Connexion() { Connexion::~Connexion() {

View File

@@ -8,245 +8,253 @@
namespace td { namespace td {
namespace game { namespace game {
bool Mob::isImmuneTo(TowerType type) { bool Mob::IsImmuneTo(TowerType type) {
return std::find(getTowerImmunities().begin(), getTowerImmunities().end(), type) != getTowerImmunities().end(); return std::find(GetTowerImmunities().begin(), GetTowerImmunities().end(), type) != GetTowerImmunities().end();
} }
bool Mob::isImmuneTo(EffectType type) { 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;});
} }
void Mob::addEffect(EffectType effectType, float durationSec, Tower* tower) { void Mob::AddEffect(EffectType effectType, float durationSec, Tower* tower) {
if (isImmuneTo(effectType)) if (IsImmuneTo(effectType))
return; return;
if (hasEffect(effectType)) { if (HasEffect(effectType)) {
EffectDuration& effect = getEffect(effectType); EffectDuration& effect = GetEffect(effectType);
if (effect.duration < durationSec) if (effect.duration < durationSec)
effect.duration = durationSec; // setting new duration if it's greater then the actual effect.duration = durationSec; // Setting new duration if it's greater then the actual
} else { } else {
m_Effects.push_back({ effectType, durationSec, tower }); m_Effects.push_back({ effectType, durationSec, tower });
} }
} }
void Mob::attackCastle(std::uint64_t delta, World* world) { void Mob::AttackCastle(std::uint64_t delta, World* world) {
if(!hasReachedEnemyCastle()) return; if (!HasReachedEnemyCastle()) return;
if (m_AttackTimer.update(delta)) { if (m_AttackTimer.Update(delta)) {
world->getMobNotifier().notifyListeners(&MobListener::OnMobCastleDamage, this, m_CastleTarget, getStats()->getDamage()); world->GetMobNotifier().NotifyListeners(&MobListener::OnMobCastleDamage, this, m_CastleTarget, GetStats()->GetDamage());
m_AttackTimer.applyCooldown(); m_AttackTimer.ApplyCooldown();
} }
} }
void Mob::walk(std::uint64_t delta, World* world) { void Mob::Walk(std::uint64_t delta, World* world) {
float mobWalkSpeed = getStats()->getMovementSpeed(); float mobWalkSpeed = GetStats()->GetMovementSpeed();
float walkAmount = mobWalkSpeed * ((float)delta / 1000.0f); float walkAmount = mobWalkSpeed * (static_cast<float>(delta) / 1000.0f);
if (hasEffect(EffectType::Slowness)) if (HasEffect(EffectType::Slowness))
walkAmount *= 0.70; // walk 30% slower walkAmount *= 0.70; // walk 30% slower
switch (getDirection()) { switch (GetDirection()) {
case Direction::NegativeX: { case Direction::NegativeX: {
setCenterX(getCenterX() - walkAmount); SetCenterX(GetCenterX() - walkAmount);
break; break;
} }
case Direction::PositiveX: { case Direction::PositiveX: {
setCenterX(getCenterX() + walkAmount); SetCenterX(GetCenterX() + walkAmount);
break; break;
} }
case Direction::NegativeY: { case Direction::NegativeY: {
setCenterY(getCenterY() - walkAmount); SetCenterY(GetCenterY() - walkAmount);
break; break;
} }
case Direction::PositiveY: { case Direction::PositiveY: {
setCenterY(getCenterY() + walkAmount); SetCenterY(GetCenterY() + walkAmount);
break; break;
} }
} default:
break;
}
} }
void Mob::move(std::uint64_t delta, World* world) { void Mob::Move(std::uint64_t delta, World* world) {
TilePtr tile = world->getTile(getCenter().getX(), getCenter().getY()); TilePtr tile = world->GetTile(GetCenter().GetX(), GetCenter().GetY());
if (tile != nullptr && tile->getType() == TileType::Walk) { if (tile != nullptr && tile->GetType() == TileType::Walk) {
WalkableTilePtr walkTile = std::static_pointer_cast<WalkableTile>(tile); WalkableTilePtr walkTile = std::static_pointer_cast<WalkableTile>(tile);
changeDirection(*walkTile, world); ChangeDirection(*walkTile, world);
} }
if (hasReachedEnemyCastle()) return; if (HasReachedEnemyCastle()) return;
walk(delta, world); Walk(delta, world);
TeamColor mobTeam = world->getPlayerById(getSender())->getTeamColor(); TeamColor mobTeam = world->GetPlayerById(GetSender())->GetTeamColor();
TeamCastle* enemyCastle = nullptr; TeamCastle* enemyCastle = nullptr;
if (mobTeam == TeamColor::Red) { if (mobTeam == TeamColor::Red) {
enemyCastle = &world->getBlueTeam().getCastle(); enemyCastle = &world->GetBlueTeam().GetCastle();
} else if (mobTeam == TeamColor::Blue) { } else if (mobTeam == TeamColor::Blue) {
enemyCastle = &world->getRedTeam().getCastle(); enemyCastle = &world->GetRedTeam().GetCastle();
} }
if (isTouchingCastle(*enemyCastle)) { if (IsTouchingCastle(*enemyCastle)) {
moveBack(*enemyCastle, world); MoveBack(*enemyCastle, world);
setMobReachedCastle(enemyCastle); SetMobReachedCastle(enemyCastle);
world->getMobNotifier().notifyListeners(&MobListener::OnMobTouchCastle, this, enemyCastle); world->GetMobNotifier().NotifyListeners(&MobListener::OnMobTouchCastle, this, enemyCastle);
} }
} }
void Mob::moveBack(const TeamCastle& enemyCastle, World* world) { void Mob::MoveBack(const TeamCastle& enemyCastle, World* world) {
switch (getDirection()) { switch (GetDirection()) {
case Direction::NegativeX: { case Direction::NegativeX: {
setCenterX(enemyCastle.getBottomRight().getX() + getWidth() / 2.0f); SetCenterX(enemyCastle.GetBottomRight().GetX() + GetWidth() / 2.0f);
break; break;
} }
case Direction::PositiveX: { case Direction::PositiveX: {
setCenterX(enemyCastle.getTopLeft().getX() - getWidth() / 2.0f); SetCenterX(enemyCastle.GetTopLeft().GetX() - GetWidth() / 2.0f);
break; break;
} }
case Direction::NegativeY: { case Direction::NegativeY: {
setCenterY(enemyCastle.getBottomRight().getY() + getHeight() / 2.0f); SetCenterY(enemyCastle.GetBottomRight().GetY() + GetHeight() / 2.0f);
break; break;
} }
case Direction::PositiveY: { case Direction::PositiveY: {
setCenterY(enemyCastle.getTopLeft().getY() - getHeight() / 2.0f); SetCenterY(enemyCastle.GetTopLeft().GetY() - GetHeight() / 2.0f);
break; break;
} }
} default:
break;
}
} }
void Mob::changeDirection(const WalkableTile& tile, World* world) { void Mob::ChangeDirection(const WalkableTile& tile, World* world) {
if (getDirection() == tile.direction) return; if (GetDirection() == tile.direction) return;
float tileX = static_cast<float>(static_cast<std::int32_t>(getCenterX())); float tileX = static_cast<float>(static_cast<std::int32_t>(GetCenterX()));
float tileY = static_cast<float>(static_cast<std::int32_t>(getCenterY())); float tileY = static_cast<float>(static_cast<std::int32_t>(GetCenterY()));
switch (getDirection()) { switch (GetDirection()) {
case Direction::PositiveY: { case Direction::PositiveY: {
if (tile.direction == Direction::NegativeX) { if (tile.direction == Direction::NegativeX) {
if (getTileY() > getTileX()) { if (GetTileY() > GetTileX()) {
setCenterY(tileY + getTileX()); SetCenterY(tileY + GetTileX());
setDirection(tile.direction); SetDirection(tile.direction);
} }
} else { // tile->direction = Direction::PositiveX } else { // tile->direction = Direction::PositiveX
if (getTileY() > 1 - getTileX()) { if (GetTileY() > 1 - GetTileX()) {
setCenterY(tileY + (1 - getTileX())); SetCenterY(tileY + (1 - GetTileX()));
setDirection(tile.direction); SetDirection(tile.direction);
} }
} }
return; return;
} }
case Direction::NegativeY: { case Direction::NegativeY: {
if (tile.direction == Direction::PositiveX) { if (tile.direction == Direction::PositiveX) {
if (getTileY() < getTileX()) { if (GetTileY() < GetTileX()) {
setCenterY(tileY + getTileX()); SetCenterY(tileY + GetTileX());
setDirection(tile.direction); SetDirection(tile.direction);
} }
} else { // tile.direction = Direction::NegativeX } else { // tile.direction = Direction::NegativeX
if (getTileY() < 1 - getTileX()) { if (GetTileY() < 1 - GetTileX()) {
setCenterY(tileY + (1 - getTileX())); SetCenterY(tileY + (1 - GetTileX()));
setDirection(tile.direction); SetDirection(tile.direction);
} }
} }
return; return;
} }
case Direction::PositiveX: { case Direction::PositiveX: {
if (tile.direction == Direction::NegativeY) { if (tile.direction == Direction::NegativeY) {
if (getTileX() > getTileY()) { if (GetTileX() > GetTileY()) {
setCenterX(tileX + getTileY()); SetCenterX(tileX + GetTileY());
setDirection(tile.direction); SetDirection(tile.direction);
} }
} else { // tile.direction = Direction::PositiveY } else { // tile.direction = Direction::PositiveY
if (getTileX() > 1 - getTileY()) { if (GetTileX() > 1 - GetTileY()) {
setCenterX(tileX + (1 - getTileY())); SetCenterX(tileX + (1 - GetTileY()));
setDirection(tile.direction); SetDirection(tile.direction);
} }
} }
return; return;
} }
case Direction::NegativeX: { case Direction::NegativeX: {
if (tile.direction == Direction::PositiveY) { if (tile.direction == Direction::PositiveY) {
if (getTileX() < getTileY()) { if (GetTileX() < GetTileY()) {
setCenterX(tileX + getTileY()); SetCenterX(tileX + GetTileY());
setDirection(tile.direction); SetDirection(tile.direction);
} }
} else { // tile.direction = Direction::NegativeY } else { // tile.direction = Direction::NegativeY
if (getTileX() < 1 - getTileY()) { if (GetTileX() < 1 - GetTileY()) {
setCenterX(tileX + (1 - getTileY())); SetCenterX(tileX + (1 - GetTileY()));
setDirection(tile.direction); SetDirection(tile.direction);
} }
} }
return; return;
} }
} default:
break;
}
} }
bool Mob::isTouchingCastle(const TeamCastle& enemyCastle) const { bool Mob::IsTouchingCastle(const TeamCastle& enemyCastle) const {
return enemyCastle.collidesWith(*this); return enemyCastle.CollidesWith(*this);
} }
void Mob::tick(std::uint64_t delta, World* world) { void Mob::Tick(std::uint64_t delta, World* world) {
updateEffects(delta, world); m_HitCooldown = std::max(0.0f, m_HitCooldown - static_cast<float>(delta / 1000.0f));
move(delta, world); UpdateEffects(delta, world);
attackCastle(delta, world); Move(delta, world);
AttackCastle(delta, world);
} }
void Mob::updateEffects(std::uint64_t delta, World* world) { void Mob::UpdateEffects(std::uint64_t delta, World* world) {
float deltaSec = (float)delta / 1000.0f; float deltaSec = static_cast<float>(delta / 1000.0f);
for (std::size_t i = 0; i < m_Effects.size(); i++) { for (std::size_t i = 0; i < m_Effects.size(); i++) {
EffectDuration& effect = m_Effects[i]; EffectDuration& effect = m_Effects[i];
effect.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() + static_cast<int>(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)) {
world->getMobNotifier().notifyListeners(&MobListener::OnMobDamage, this, 3.0f, getEffect(EffectType::Fire).tower); world->GetMobNotifier().NotifyListeners(&MobListener::OnMobDamage, this, 3.0f, GetEffect(EffectType::Fire).tower);
} }
} }
if (hasEffect(EffectType::Poison)) { if (HasEffect(EffectType::Poison)) {
if (m_EffectPoisonTimer.update(delta)) { if (m_EffectPoisonTimer.Update(delta)) {
world->getMobNotifier().notifyListeners(&MobListener::OnMobDamage, this, 1.0f, getEffect(EffectType::Poison).tower); world->GetMobNotifier().NotifyListeners(&MobListener::OnMobDamage, this, 1.0f, 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);
} }
} }
} }
bool Mob::hasEffect(EffectType type) { bool Mob::HasEffect(EffectType type) {
return std::find_if(m_Effects.begin(), m_Effects.end(), [&type](EffectDuration effect) { return effect.type == type;}) != m_Effects.end(); return std::find_if(m_Effects.begin(), m_Effects.end(), [&type](EffectDuration effect) { return effect.type == type;}) != m_Effects.end();
} }
@@ -254,249 +262,249 @@ 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 = { static const std::map<MobKey, MobStats> MobConstants = {
// damage speed size 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, {1, 1}, 15, 0, 7, 40}}}, {{MobType::Zombie, 1},{MobStats{1, 1.6, {1, 1}, 15, 0, 7, 40}}},
{{MobType::Zombie, 2},{MobStats{1, 1.6, {1, 1}, 18, 88, 9, 56}}}, {{MobType::Zombie, 2},{MobStats{1, 1.6, {1, 1}, 18, 88, 9, 56}}},
{{MobType::Zombie, 3},{MobStats{1, 1.6, {1, 1}, 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, {1, 1}, 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, {1, 1}, 31, 469, 15, 154}}}, {{MobType::Zombie, 5},{MobStats{2, 1.6, {1, 1}, 31, 469, 15, 154}}},
{{MobType::Spider, 1},{MobStats{1, 1.6, {1, 1}, 25, 100, 15, 80}}}, {{MobType::Spider, 1},{MobStats{1, 1.6, {1, 1}, 25, 100, 15, 80}}},
{{MobType::Spider, 2},{MobStats{1, 2, {1, 1}, 30, 175, 16, 112}}}, {{MobType::Spider, 2},{MobStats{1, 2, {1, 1}, 30, 175, 16, 112}}},
{{MobType::Spider, 3},{MobStats{1.5, 2, {1, 1}, 36, 306, 18, 157}}}, {{MobType::Spider, 3},{MobStats{1.5, 2, {1, 1}, 36, 306, 18, 157}}},
{{MobType::Spider, 4},{MobStats{2.5, 2, {1, 1}, 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, {1, 1}, 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, {1, 1}, 120, 200, 30, 350}}}, {{MobType::Skeleton, 1},{MobStats{1, 1.6, {1, 1}, 120, 200, 30, 350}}},
{{MobType::Skeleton, 2},{MobStats{1, 1.6, {1, 1}, 144, 350, 33, 490}}}, {{MobType::Skeleton, 2},{MobStats{1, 1.6, {1, 1}, 144, 350, 33, 490}}},
{{MobType::Skeleton, 3},{MobStats{1, 1.6, {1, 1}, 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, {1, 1}, 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, {1, 1}, 255, 1876, 43, 1345}}}, {{MobType::Skeleton, 5},{MobStats{2, 1.6, {1, 1}, 255, 1876, 43, 1345}}},
{{MobType::Pigman, 1},{MobStats{1, 2, {1, 1}, 100, 150, 22, 150}}}, {{MobType::Pigman, 1},{MobStats{1, 2, {1, 1}, 100, 150, 22, 150}}},
{{MobType::Pigman, 2},{MobStats{1, 2, {1, 1}, 120, 263, 24, 210}}}, {{MobType::Pigman, 2},{MobStats{1, 2, {1, 1}, 120, 263, 24, 210}}},
{{MobType::Pigman, 3},{MobStats{1, 2, {1, 1}, 144, 459, 25, 297}}}, {{MobType::Pigman, 3},{MobStats{1, 2, {1, 1}, 144, 459, 25, 297}}},
{{MobType::Pigman, 4},{MobStats{1, 2, {1, 1}, 173, 804, 25, 412}}}, {{MobType::Pigman, 4},{MobStats{1, 2, {1, 1}, 173, 804, 25, 412}}},
{{MobType::Pigman, 5},{MobStats{1.5, 2, {1, 1}, 207, 1407, 27, 576}}}, {{MobType::Pigman, 5},{MobStats{1.5, 2, {1, 1}, 207, 1407, 27, 576}}},
{{MobType::Creeper, 1},{MobStats{1, 2, {1, 1}, 250, 325, 46, 350}}}, {{MobType::Creeper, 1},{MobStats{1, 2, {1, 1}, 250, 325, 46, 350}}},
{{MobType::Creeper, 2},{MobStats{1, 2, {1, 1}, 290, 550, 49, 460}}}, {{MobType::Creeper, 2},{MobStats{1, 2, {1, 1}, 290, 550, 49, 460}}},
{{MobType::Creeper, 3},{MobStats{2, 2, {1, 1}, 350, 800, 55, 630}}}, {{MobType::Creeper, 3},{MobStats{2, 2, {1, 1}, 350, 800, 55, 630}}},
{{MobType::Creeper, 4},{MobStats{3, 2, {1, 1}, 420, 1300, 61, 900}}}, {{MobType::Creeper, 4},{MobStats{3, 2, {1, 1}, 420, 1300, 61, 900}}},
{{MobType::Creeper, 5},{MobStats{4, 2, {1, 1}, 510, 1850, 67, 1250}}}, {{MobType::Creeper, 5},{MobStats{4, 2, {1, 1}, 510, 1850, 67, 1250}}},
{{MobType::Silverfish, 1},{MobStats{1, 1.6, {1, 1}, 38, 125, 18, 120}}}, {{MobType::Silverfish, 1},{MobStats{1, 1.6, {1, 1}, 38, 125, 18, 120}}},
{{MobType::Silverfish, 2},{MobStats{1, 1.6, {1, 1}, 50, 230, 19, 170}}}, {{MobType::Silverfish, 2},{MobStats{1, 1.6, {1, 1}, 50, 230, 19, 170}}},
{{MobType::Silverfish, 3},{MobStats{1, 1.6, {1, 1}, 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, {1, 1}, 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, {1, 1}, 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, {1, 1}, 500, 500, 105, 410}}}, {{MobType::Blaze, 1},{MobStats{1, 1.6, {1, 1}, 500, 500, 105, 410}}},
{{MobType::Blaze, 2},{MobStats{1, 1.6, {1, 1}, 600, 875, 111, 574}}}, {{MobType::Blaze, 2},{MobStats{1, 1.6, {1, 1}, 600, 875, 111, 574}}},
{{MobType::Blaze, 3},{MobStats{1, 1.6, {1, 1}, 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, {1, 1}, 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, {1, 1}, 1037, 4689, 127, 1575}}}, {{MobType::Blaze, 5},{MobStats{2, 1.6, {1, 1}, 1037, 4689, 127, 1575}}},
{{MobType::Witch, 1},{MobStats{1, 1.6, {1, 1}, 150, 300, 37, 300}}}, {{MobType::Witch, 1},{MobStats{1, 1.6, {1, 1}, 150, 300, 37, 300}}},
{{MobType::Witch, 2},{MobStats{1, 1.6, {1, 1}, 165, 525, 39, 405}}}, {{MobType::Witch, 2},{MobStats{1, 1.6, {1, 1}, 165, 525, 39, 405}}},
{{MobType::Witch, 3},{MobStats{1, 1.6, {1, 1}, 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, {1, 1}, 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, {1, 1}, 220, 2810, 45, 996}}}, {{MobType::Witch, 5},{MobStats{2, 1.6, {1, 1}, 220, 2810, 45, 996}}},
{{MobType::Slime, 1},{MobStats{1, 0.8, {1, 1}, 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, {1, 1}, 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, {1, 1}, 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, {1, 1}, 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, {1, 1}, 3110, 9379, 366, 1171}}}, {{MobType::Slime, 5},{MobStats{3, 0.8, {1, 1}, 3110, 9379, 366, 1171}}},
{{MobType::Giant, 1},{MobStats{10, 0.8, {1, 1}, 4000, 2250, 600, 6250}}}, {{MobType::Giant, 1},{MobStats{10, 0.8, {1, 1}, 4000, 2250, 600, 6250}}},
{{MobType::Giant, 2},{MobStats{20, 0.8, {1, 1}, 4500, 4000, 612, 9375}}}, {{MobType::Giant, 2},{MobStats{20, 0.8, {1, 1}, 4500, 4000, 612, 9375}}},
{{MobType::Giant, 3},{MobStats{30, 0.8, {1, 1}, 5062, 7250, 624, 14062}}}, {{MobType::Giant, 3},{MobStats{30, 0.8, {1, 1}, 5062, 7250, 624, 14062}}},
{{MobType::Giant, 4},{MobStats{40, 0.8, {1, 1}, 5695, 12500, 636, 21093}}}, {{MobType::Giant, 4},{MobStats{40, 0.8, {1, 1}, 5695, 12500, 636, 21093}}},
{{MobType::Giant, 5},{MobStats{50, 0.8, {1, 1}, 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) {
return &MobConstants.at(MobKey{ type, level }); return &MobConstants.at(MobKey{ type, level });
} }
const std::map<MobKey, TowerImmunities> MobsTowerImmunities = { static const std::map<MobKey, TowerImmunities> MobsTowerImmunities = {
{{MobType::Zombie, 1},{}}, {{MobType::Zombie, 1},{}},
{{MobType::Zombie, 2},{}}, {{MobType::Zombie, 2},{}},
{{MobType::Zombie, 3},{}}, {{MobType::Zombie, 3},{}},
{{MobType::Zombie, 4},{}}, {{MobType::Zombie, 4},{}},
{{MobType::Zombie, 5},{}}, {{MobType::Zombie, 5},{}},
{{MobType::Spider, 1},{}}, {{MobType::Spider, 1},{}},
{{MobType::Spider, 2},{}}, {{MobType::Spider, 2},{}},
{{MobType::Spider, 3},{}}, {{MobType::Spider, 3},{}},
{{MobType::Spider, 4},{TowerType::Archer, TowerType::Artillery, TowerType::Leach, TowerType::Necromancer, TowerType::Poison, TowerType::Quake, TowerType::Sorcerer, TowerType::Turret, TowerType::Zeus}}, {{MobType::Spider, 4},{TowerType::Archer, TowerType::Artillery, TowerType::Leach, TowerType::Necromancer, TowerType::Poison, TowerType::Quake, TowerType::Sorcerer, TowerType::Turret, TowerType::Zeus}},
{{MobType::Spider, 5},{TowerType::Archer, TowerType::Artillery, TowerType::Leach, TowerType::Necromancer, TowerType::Poison, TowerType::Quake, TowerType::Sorcerer, TowerType::Turret, TowerType::Zeus}}, {{MobType::Spider, 5},{TowerType::Archer, TowerType::Artillery, TowerType::Leach, TowerType::Necromancer, TowerType::Poison, TowerType::Quake, TowerType::Sorcerer, TowerType::Turret, TowerType::Zeus}},
{{MobType::Skeleton, 1},{}}, {{MobType::Skeleton, 1},{}},
{{MobType::Skeleton, 2},{}}, {{MobType::Skeleton, 2},{}},
{{MobType::Skeleton, 3},{}}, {{MobType::Skeleton, 3},{}},
{{MobType::Skeleton, 4},{}}, {{MobType::Skeleton, 4},{}},
{{MobType::Skeleton, 5},{}}, {{MobType::Skeleton, 5},{}},
{{MobType::Pigman, 1},{TowerType::Zeus}}, {{MobType::Pigman, 1},{TowerType::Zeus}},
{{MobType::Pigman, 2},{TowerType::Zeus}}, {{MobType::Pigman, 2},{TowerType::Zeus}},
{{MobType::Pigman, 3},{TowerType::Zeus}}, {{MobType::Pigman, 3},{TowerType::Zeus}},
{{MobType::Pigman, 4},{TowerType::Zeus}}, {{MobType::Pigman, 4},{TowerType::Zeus}},
{{MobType::Pigman, 5},{TowerType::Zeus}}, {{MobType::Pigman, 5},{TowerType::Zeus}},
{{MobType::Creeper, 1},{}}, {{MobType::Creeper, 1},{}},
{{MobType::Creeper, 2},{}}, {{MobType::Creeper, 2},{}},
{{MobType::Creeper, 3},{}}, {{MobType::Creeper, 3},{}},
{{MobType::Creeper, 4},{}}, {{MobType::Creeper, 4},{}},
{{MobType::Creeper, 5},{}}, {{MobType::Creeper, 5},{}},
{{MobType::Silverfish, 1},{}}, {{MobType::Silverfish, 1},{}},
{{MobType::Silverfish, 2},{}}, {{MobType::Silverfish, 2},{}},
{{MobType::Silverfish, 3},{}}, {{MobType::Silverfish, 3},{}},
{{MobType::Silverfish, 4},{}}, {{MobType::Silverfish, 4},{}},
{{MobType::Silverfish, 5},{}}, {{MobType::Silverfish, 5},{}},
{{MobType::Blaze, 1},{}}, {{MobType::Blaze, 1},{}},
{{MobType::Blaze, 2},{}}, {{MobType::Blaze, 2},{}},
{{MobType::Blaze, 3},{}}, {{MobType::Blaze, 3},{}},
{{MobType::Blaze, 4},{}}, {{MobType::Blaze, 4},{}},
{{MobType::Blaze, 5},{}}, {{MobType::Blaze, 5},{}},
{{MobType::Witch, 1},{TowerType::Zeus, TowerType::Mage, TowerType::Poison}}, {{MobType::Witch, 1},{TowerType::Zeus, TowerType::Mage, TowerType::Poison}},
{{MobType::Witch, 2},{TowerType::Zeus, TowerType::Mage, TowerType::Poison}}, {{MobType::Witch, 2},{TowerType::Zeus, TowerType::Mage, TowerType::Poison}},
{{MobType::Witch, 3},{TowerType::Zeus, TowerType::Mage, TowerType::Poison}}, {{MobType::Witch, 3},{TowerType::Zeus, TowerType::Mage, TowerType::Poison}},
{{MobType::Witch, 4},{TowerType::Zeus, TowerType::Mage, TowerType::Poison}}, {{MobType::Witch, 4},{TowerType::Zeus, TowerType::Mage, TowerType::Poison}},
{{MobType::Witch, 5},{TowerType::Zeus, TowerType::Mage, TowerType::Poison}}, {{MobType::Witch, 5},{TowerType::Zeus, TowerType::Mage, TowerType::Poison}},
{{MobType::Slime, 1},{}}, {{MobType::Slime, 1},{}},
{{MobType::Slime, 2},{}}, {{MobType::Slime, 2},{}},
{{MobType::Slime, 3},{}}, {{MobType::Slime, 3},{}},
{{MobType::Slime, 4},{}}, {{MobType::Slime, 4},{}},
{{MobType::Slime, 5},{}}, {{MobType::Slime, 5},{}},
{{MobType::Giant, 1},{}}, {{MobType::Giant, 1},{}},
{{MobType::Giant, 2},{}}, {{MobType::Giant, 2},{}},
{{MobType::Giant, 3},{}}, {{MobType::Giant, 3},{}},
{{MobType::Giant, 4},{}}, {{MobType::Giant, 4},{}},
{{MobType::Giant, 5},{}}, {{MobType::Giant, 5},{}},
}; };
const TowerImmunities& getMobTowerImmunities(MobType type, std::uint8_t level) { const TowerImmunities& GetMobTowerImmunities(MobType type, std::uint8_t level) {
return MobsTowerImmunities.at({ type, level }); return MobsTowerImmunities.at({ type, level });
} }
const std::map<MobKey, EffectImmunities> MobsEffectImmunities = { static const std::map<MobKey, EffectImmunities> MobsEffectImmunities = {
{{MobType::Zombie, 1},{}}, {{MobType::Zombie, 1},{}},
{{MobType::Zombie, 2},{}}, {{MobType::Zombie, 2},{}},
{{MobType::Zombie, 3},{}}, {{MobType::Zombie, 3},{}},
{{MobType::Zombie, 4},{}}, {{MobType::Zombie, 4},{}},
{{MobType::Zombie, 5},{}}, {{MobType::Zombie, 5},{}},
{{MobType::Spider, 1},{}}, {{MobType::Spider, 1},{}},
{{MobType::Spider, 2},{}}, {{MobType::Spider, 2},{}},
{{MobType::Spider, 3},{}}, {{MobType::Spider, 3},{}},
{{MobType::Spider, 4},{}}, {{MobType::Spider, 4},{}},
{{MobType::Spider, 5},{}}, {{MobType::Spider, 5},{}},
{{MobType::Skeleton, 1},{}}, {{MobType::Skeleton, 1},{}},
{{MobType::Skeleton, 2},{}}, {{MobType::Skeleton, 2},{}},
{{MobType::Skeleton, 3},{}}, {{MobType::Skeleton, 3},{}},
{{MobType::Skeleton, 4},{EffectType::Fire}}, {{MobType::Skeleton, 4},{EffectType::Fire}},
{{MobType::Skeleton, 5},{EffectType::Fire}}, {{MobType::Skeleton, 5},{EffectType::Fire}},
{{MobType::Pigman, 1},{EffectType::Fire}}, {{MobType::Pigman, 1},{EffectType::Fire}},
{{MobType::Pigman, 2},{EffectType::Fire}}, {{MobType::Pigman, 2},{EffectType::Fire}},
{{MobType::Pigman, 3},{EffectType::Fire}}, {{MobType::Pigman, 3},{EffectType::Fire}},
{{MobType::Pigman, 4},{EffectType::Fire}}, {{MobType::Pigman, 4},{EffectType::Fire}},
{{MobType::Pigman, 5},{EffectType::Fire}}, {{MobType::Pigman, 5},{EffectType::Fire}},
{{MobType::Creeper, 1},{}}, {{MobType::Creeper, 1},{}},
{{MobType::Creeper, 2},{}}, {{MobType::Creeper, 2},{}},
{{MobType::Creeper, 3},{}}, {{MobType::Creeper, 3},{}},
{{MobType::Creeper, 4},{}}, {{MobType::Creeper, 4},{}},
{{MobType::Creeper, 5},{}}, {{MobType::Creeper, 5},{}},
{{MobType::Silverfish, 1},{}}, {{MobType::Silverfish, 1},{}},
{{MobType::Silverfish, 2},{}}, {{MobType::Silverfish, 2},{}},
{{MobType::Silverfish, 3},{}}, {{MobType::Silverfish, 3},{}},
{{MobType::Silverfish, 4},{EffectType::Fire}}, {{MobType::Silverfish, 4},{EffectType::Fire}},
{{MobType::Silverfish, 5},{EffectType::Fire}}, {{MobType::Silverfish, 5},{EffectType::Fire}},
{{MobType::Blaze, 1},{EffectType::Fire}}, {{MobType::Blaze, 1},{EffectType::Fire}},
{{MobType::Blaze, 2},{EffectType::Fire}}, {{MobType::Blaze, 2},{EffectType::Fire}},
{{MobType::Blaze, 3},{EffectType::Fire}}, {{MobType::Blaze, 3},{EffectType::Fire}},
{{MobType::Blaze, 4},{EffectType::Fire}}, {{MobType::Blaze, 4},{EffectType::Fire}},
{{MobType::Blaze, 5},{EffectType::Fire}}, {{MobType::Blaze, 5},{EffectType::Fire}},
{{MobType::Witch, 1},{}}, {{MobType::Witch, 1},{}},
{{MobType::Witch, 2},{}}, {{MobType::Witch, 2},{}},
{{MobType::Witch, 3},{}}, {{MobType::Witch, 3},{}},
{{MobType::Witch, 4},{}}, {{MobType::Witch, 4},{}},
{{MobType::Witch, 5},{}}, {{MobType::Witch, 5},{}},
{{MobType::Slime, 1},{}}, {{MobType::Slime, 1},{}},
{{MobType::Slime, 2},{}}, {{MobType::Slime, 2},{}},
{{MobType::Slime, 3},{}}, {{MobType::Slime, 3},{}},
{{MobType::Slime, 4},{EffectType::Fire}}, {{MobType::Slime, 4},{EffectType::Fire}},
{{MobType::Slime, 5},{EffectType::Fire}}, {{MobType::Slime, 5},{EffectType::Fire}},
{{MobType::Giant, 1},{EffectType::Stun}}, {{MobType::Giant, 1},{EffectType::Stun}},
{{MobType::Giant, 2},{EffectType::Stun}}, {{MobType::Giant, 2},{EffectType::Stun}},
{{MobType::Giant, 3},{EffectType::Stun}}, {{MobType::Giant, 3},{EffectType::Stun}},
{{MobType::Giant, 4},{EffectType::Stun}}, {{MobType::Giant, 4},{EffectType::Stun}},
{{MobType::Giant, 5},{EffectType::Stun}}, {{MobType::Giant, 5},{EffectType::Stun}},
}; };
const EffectImmunities& getMobEffectImmunities(MobType type, std::uint8_t level) { const EffectImmunities& GetMobEffectImmunities(MobType type, std::uint8_t level) {
return MobsEffectImmunities.at({ type, level }); return MobsEffectImmunities.at({ type, level });
} }
MobPtr MobFactory::createMob(MobID id, MobType type, std::uint8_t level, PlayerID sender) { MobPtr MobFactory::CreateMob(MobID mobId, MobType mobType, std::uint8_t mobLevel, PlayerID mobSender) {
using MobCreator = std::function<std::shared_ptr<Mob>(MobID, std::uint8_t, PlayerID)>; using MobCreator = std::function<std::shared_ptr<Mob>(MobID, std::uint8_t, PlayerID)>;
static std::map<MobType, MobCreator> mobFactory = { static const std::map<MobType, MobCreator> mobFactory = {
{MobType::Zombie, [](MobID id, std::uint8_t level, PlayerID sender) -> MobPtr {return std::make_shared<Zombie>(id, level, sender);} }, {MobType::Zombie, [](MobID id, std::uint8_t level, PlayerID sender) -> MobPtr {return std::make_shared<Zombie>(id, level, sender);} },
{MobType::Spider, [](MobID id, std::uint8_t level, PlayerID sender) -> MobPtr {return std::make_shared<Spider>(id, level, sender);} }, {MobType::Spider, [](MobID id, std::uint8_t level, PlayerID sender) -> MobPtr {return std::make_shared<Spider>(id, level, sender);} },
{MobType::Skeleton, [](MobID id, std::uint8_t level, PlayerID sender) -> MobPtr {return std::make_shared<Skeleton>(id, level, sender);} }, {MobType::Skeleton, [](MobID id, std::uint8_t level, PlayerID sender) -> MobPtr {return std::make_shared<Skeleton>(id, level, sender);} },
{MobType::Pigman, [](MobID id, std::uint8_t level, PlayerID sender) -> MobPtr {return std::make_shared<PigMan>(id, level, sender);} }, {MobType::Pigman, [](MobID id, std::uint8_t level, PlayerID sender) -> MobPtr {return std::make_shared<PigMan>(id, level, sender);} },
{MobType::Creeper, [](MobID id, std::uint8_t level, PlayerID sender) -> MobPtr {return std::make_shared<Creeper>(id, level, sender);} }, {MobType::Creeper, [](MobID id, std::uint8_t level, PlayerID sender) -> MobPtr {return std::make_shared<Creeper>(id, level, sender);} },
{MobType::Silverfish, [](MobID id, std::uint8_t level, PlayerID sender) -> MobPtr {return std::make_shared<Silverfish>(id, level, sender);} }, {MobType::Silverfish, [](MobID id, std::uint8_t level, PlayerID sender) -> MobPtr {return std::make_shared<Silverfish>(id, level, sender);} },
{MobType::Blaze, [](MobID id, std::uint8_t level, PlayerID sender) -> MobPtr {return std::make_shared<Blaze>(id, level, sender);} }, {MobType::Blaze, [](MobID id, std::uint8_t level, PlayerID sender) -> MobPtr {return std::make_shared<Blaze>(id, level, sender);} },
{MobType::Witch, [](MobID id, std::uint8_t level, PlayerID sender) -> MobPtr {return std::make_shared<Witch>(id, level, sender);} }, {MobType::Witch, [](MobID id, std::uint8_t level, PlayerID sender) -> MobPtr {return std::make_shared<Witch>(id, level, sender);} },
{MobType::Slime, [](MobID id, std::uint8_t level, PlayerID sender) -> MobPtr {return std::make_shared<Slime>(id, level, sender);} }, {MobType::Slime, [](MobID id, std::uint8_t level, PlayerID sender) -> MobPtr {return std::make_shared<Slime>(id, level, sender);} },
{MobType::Giant, [](MobID id, std::uint8_t level, PlayerID sender) -> MobPtr {return std::make_shared<Giant>(id, level, sender);} }, {MobType::Giant, [](MobID id, std::uint8_t level, PlayerID sender) -> MobPtr {return std::make_shared<Giant>(id, level, sender);} },
}; };
return mobFactory[type](id, level, sender); return mobFactory.at(mobType)(mobId, mobLevel, mobSender);
} }
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";
} }
} }
} // namespace game } // namespace game

View File

@@ -7,20 +7,20 @@ namespace game {
Team::Team(TeamColor color) : m_Color(color), m_TeamCastle(this) {} Team::Team(TeamColor color) : m_Color(color), m_TeamCastle(this) {}
void Team::addPlayer(Player* newPlayer) { void Team::AddPlayer(Player* newPlayer) {
m_Players.push_back(newPlayer); m_Players.push_back(newPlayer);
} }
void Team::removePlayer(const Player* player) { void Team::RemovePlayer(const Player* player) {
m_Players.erase(std::find(m_Players.begin(), m_Players.end(), player)); m_Players.erase(std::find(m_Players.begin(), m_Players.end(), player));
} }
TeamColor Team::getColor() const { TeamColor Team::GetColor() const {
return m_Color; return m_Color;
} }
std::uint8_t Team::getPlayerCount() const { std::uint8_t Team::GetPlayerCount() const {
return m_Players.size(); return m_Players.size();
} }

View File

@@ -6,119 +6,119 @@
namespace td { namespace td {
namespace game { namespace game {
bool Tower::isMobInRange(MobPtr mob) { bool Tower::IsMobInRange(MobPtr mob) {
if (mob->isDead()) if (mob->IsDead())
return false; return false;
return mob->collidesWith(*this); return mob->CollidesWith(*this);
} }
const std::map<std::pair<TowerType, TowerLevel>, TowerStats> TowerConstants = { const std::map<std::pair<TowerType, TowerLevel>, TowerStats> TowerConstants = {
// // rate damage range // // rate damage range
{{TowerType::Archer, {1, TowerPath::Base}}, {2, 5, 10}}, {{TowerType::Archer, {1, TowerPath::Base}}, {2, 5, 10}},
{{TowerType::Archer, {2, TowerPath::Top}}, {1, 0, 12}}, {{TowerType::Archer, {2, TowerPath::Top}}, {1, 0, 12}},
{{TowerType::Archer, {3, TowerPath::Top}}, {1, 0, 13}}, {{TowerType::Archer, {3, TowerPath::Top}}, {1, 0, 13}},
{{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, 10, 13}}, {{TowerType::Archer, {3, TowerPath::Bottom}}, {2, 10, 13}},
{{TowerType::Archer, {4, TowerPath::Bottom}}, {2, 10, 15}}, {{TowerType::Archer, {4, TowerPath::Bottom}}, {2, 10, 15}},
//----------------------------------------------------------------- //-----------------------------------------------------------------
{{TowerType::Ice, {1, TowerPath::Base}}, {1, 0, 10}}, {{TowerType::Ice, {1, TowerPath::Base}}, {1, 0, 10}},
{{TowerType::Ice, {2, TowerPath::Base}}, {1, 0, 12}}, {{TowerType::Ice, {2, TowerPath::Base}}, {1, 0, 12}},
{{TowerType::Ice, {3, TowerPath::Base}}, {1, 0, 13}}, {{TowerType::Ice, {3, TowerPath::Base}}, {1, 0, 13}},
{{TowerType::Ice, {4, TowerPath::Base}}, {1, 1, 15}}, {{TowerType::Ice, {4, TowerPath::Base}}, {1, 1, 15}},
//----------------------------------------------------------------- //-----------------------------------------------------------------
{{TowerType::Sorcerer, {1, TowerPath::Base}}, {5, 0, 10}}, {{TowerType::Sorcerer, {1, TowerPath::Base}}, {5, 0, 10}},
{{TowerType::Sorcerer, {2, TowerPath::Base}}, {4, 0, 12}}, {{TowerType::Sorcerer, {2, TowerPath::Base}}, {4, 0, 12}},
{{TowerType::Sorcerer, {3, TowerPath::Top}}, {4, 0, 14}}, {{TowerType::Sorcerer, {3, TowerPath::Top}}, {4, 0, 14}},
{{TowerType::Sorcerer, {4, TowerPath::Top}}, {4, 0, 15}}, {{TowerType::Sorcerer, {4, TowerPath::Top}}, {4, 0, 15}},
{{TowerType::Sorcerer, {3, TowerPath::Bottom}}, {4, 0, 14}}, {{TowerType::Sorcerer, {3, TowerPath::Bottom}}, {4, 0, 14}},
{{TowerType::Sorcerer, {4, TowerPath::Bottom}}, {4, 0, 15}}, {{TowerType::Sorcerer, {4, TowerPath::Bottom}}, {4, 0, 15}},
//----------------------------------------------------------------- //-----------------------------------------------------------------
{{TowerType::Zeus, {1, TowerPath::Base}}, {5, 0, 10}}, {{TowerType::Zeus, {1, TowerPath::Base}}, {5, 0, 10}},
{{TowerType::Zeus, {2, TowerPath::Base}}, {4, 0, 12}}, {{TowerType::Zeus, {2, TowerPath::Base}}, {4, 0, 12}},
{{TowerType::Zeus, {3, TowerPath::Top}}, {0, 0, 0}}, {{TowerType::Zeus, {3, TowerPath::Top}}, {0, 0, 0}},
{{TowerType::Zeus, {4, TowerPath::Top}}, {0, 0, 0}}, {{TowerType::Zeus, {4, TowerPath::Top}}, {0, 0, 0}},
{{TowerType::Zeus, {3, TowerPath::Bottom}}, {1.2, 0, 14}}, {{TowerType::Zeus, {3, TowerPath::Bottom}}, {1.2, 0, 14}},
{{TowerType::Zeus, {4, TowerPath::Bottom}}, {0.8, 0, 15}}, {{TowerType::Zeus, {4, TowerPath::Bottom}}, {0.8, 0, 15}},
//----------------------------------------------------------------- //-----------------------------------------------------------------
{{TowerType::Mage, {1, TowerPath::Base}}, {5, 0, 10}}, {{TowerType::Mage, {1, TowerPath::Base}}, {5, 0, 10}},
{{TowerType::Mage, {2, TowerPath::Base}}, {4, 0, 12}}, {{TowerType::Mage, {2, TowerPath::Base}}, {4, 0, 12}},
{{TowerType::Mage, {3, TowerPath::Base}}, {3, 0, 13}}, {{TowerType::Mage, {3, TowerPath::Base}}, {3, 0, 13}},
{{TowerType::Mage, {4, TowerPath::Base}}, {1, 30, 15}}, {{TowerType::Mage, {4, TowerPath::Base}}, {1, 30, 15}},
//----------------------------------------------------------------- //-----------------------------------------------------------------
{{TowerType::Artillery, {1, TowerPath::Base}}, {7, 0, 10}}, {{TowerType::Artillery, {1, TowerPath::Base}}, {7, 0, 10}},
{{TowerType::Artillery, {2, TowerPath::Base}}, {7, 0, 12}}, {{TowerType::Artillery, {2, TowerPath::Base}}, {7, 0, 12}},
{{TowerType::Artillery, {3, TowerPath::Top}}, {7, 0, 13}}, {{TowerType::Artillery, {3, TowerPath::Top}}, {7, 0, 13}},
{{TowerType::Artillery, {4, TowerPath::Top}}, {7, 0, 15}}, {{TowerType::Artillery, {4, TowerPath::Top}}, {7, 0, 15}},
{{TowerType::Artillery, {3, TowerPath::Bottom}}, {5, 0, 13}}, {{TowerType::Artillery, {3, TowerPath::Bottom}}, {5, 0, 13}},
{{TowerType::Artillery, {4, TowerPath::Bottom}}, {4, 0, 15}}, {{TowerType::Artillery, {4, TowerPath::Bottom}}, {4, 0, 15}},
//----------------------------------------------------------------- //-----------------------------------------------------------------
{{TowerType::Quake, {1, TowerPath::Base}}, {5, 5, 10}}, {{TowerType::Quake, {1, TowerPath::Base}}, {5, 5, 10}},
{{TowerType::Quake, {2, TowerPath::Base}}, {4, 7, 12}}, {{TowerType::Quake, {2, TowerPath::Base}}, {4, 7, 12}},
{{TowerType::Quake, {3, TowerPath::Base}}, {3, 9, 13}}, {{TowerType::Quake, {3, TowerPath::Base}}, {3, 9, 13}},
{{TowerType::Quake, {4, TowerPath::Base}}, {2, 11, 15}}, {{TowerType::Quake, {4, TowerPath::Base}}, {2, 11, 15}},
//----------------------------------------------------------------- //-----------------------------------------------------------------
{{TowerType::Poison, {1, TowerPath::Base}}, {5, 0, 10}}, {{TowerType::Poison, {1, TowerPath::Base}}, {5, 0, 10}},
{{TowerType::Poison, {2, TowerPath::Base}}, {5, 0, 12}}, {{TowerType::Poison, {2, TowerPath::Base}}, {5, 0, 12}},
{{TowerType::Poison, {3, TowerPath::Top}}, {6, 0, 13}}, {{TowerType::Poison, {3, TowerPath::Top}}, {6, 0, 13}},
{{TowerType::Poison, {4, TowerPath::Top}}, {5, 0, 15}}, {{TowerType::Poison, {4, TowerPath::Top}}, {5, 0, 15}},
{{TowerType::Poison, {3, TowerPath::Bottom}}, {5, 10, 13}}, {{TowerType::Poison, {3, TowerPath::Bottom}}, {5, 10, 13}},
{{TowerType::Poison, {4, TowerPath::Bottom}}, {6, 20, 15}}, {{TowerType::Poison, {4, TowerPath::Bottom}}, {6, 20, 15}},
//----------------------------------------------------------------- //-----------------------------------------------------------------
{{TowerType::Leach, {1, TowerPath::Base}}, {0, 0, 0}}, {{TowerType::Leach, {1, TowerPath::Base}}, {0, 0, 0}},
{{TowerType::Leach, {2, TowerPath::Base}}, {0, 0, 0}}, {{TowerType::Leach, {2, TowerPath::Base}}, {0, 0, 0}},
{{TowerType::Leach, {3, TowerPath::Base}}, {0, 0, 0}}, {{TowerType::Leach, {3, TowerPath::Base}}, {0, 0, 0}},
//----------------------------------------------------------------- //-----------------------------------------------------------------
{{TowerType::Turret, {1, TowerPath::Base}}, {0.5, 0, 0}}, {{TowerType::Turret, {1, TowerPath::Base}}, {0.5, 0, 0}},
{{TowerType::Turret, {2, TowerPath::Top}}, {0, 0, 0}}, {{TowerType::Turret, {2, TowerPath::Top}}, {0, 0, 0}},
{{TowerType::Turret, {3, TowerPath::Top}}, {0, 0, 0}}, {{TowerType::Turret, {3, TowerPath::Top}}, {0, 0, 0}},
{{TowerType::Turret, {2, TowerPath::Bottom}}, {0, 0, 0}}, {{TowerType::Turret, {2, TowerPath::Bottom}}, {0, 0, 0}},
{{TowerType::Turret, {3, TowerPath::Bottom}}, {0, 0, 0}}, {{TowerType::Turret, {3, TowerPath::Bottom}}, {0, 0, 0}},
//----------------------------------------------------------------- //-----------------------------------------------------------------
{{TowerType::Necromancer, {1, TowerPath::Base}}, {2, 0, 11}}, {{TowerType::Necromancer, {1, TowerPath::Base}}, {2, 0, 11}},
{{TowerType::Necromancer, {2, TowerPath::Base}}, {1, 0, 14}}, {{TowerType::Necromancer, {2, TowerPath::Base}}, {1, 0, 14}},
{{TowerType::Necromancer, {3, TowerPath::Top}}, {1, 0, 15}}, {{TowerType::Necromancer, {3, TowerPath::Top}}, {1, 0, 15}},
{{TowerType::Necromancer, {3, TowerPath::Bottom}}, {0, 30, 0}}, {{TowerType::Necromancer, {3, TowerPath::Bottom}}, {0, 30, 0}},
}; };
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;
} }
@@ -126,21 +126,21 @@ const TowerStats* getTowerStats(TowerType type, TowerLevel level) {
static const std::map<TowerType, TowerInfo> TowerInfoConstants = { static const std::map<TowerType, TowerInfo> TowerInfoConstants = {
{TowerType::Archer, {"Archer", "Shoot projectiles", false}}, {TowerType::Archer, {"Archer", "Shoot projectiles", false}},
{TowerType::Artillery, {"Artillery", "Explosion", false}}, {TowerType::Artillery, {"Artillery", "Explosion", false}},
{TowerType::Ice, {"Ice", "Slow down enemies", false}}, {TowerType::Ice, {"Ice", "Slow down enemies", false}},
{TowerType::Leach, {"Leach", "Shoot projectiles", true}}, {TowerType::Leach, {"Leach", "Shoot projectiles", true}},
{TowerType::Mage, {"Mage", "Set enemies on fire", false}}, {TowerType::Mage, {"Mage", "Set enemies on fire", false}},
{TowerType::Necromancer, {"Necromancer", "Summon troops", true}}, {TowerType::Necromancer, {"Necromancer", "Summon troops", true}},
{TowerType::Poison, {"Poison", "Poison enemies", false}}, {TowerType::Poison, {"Poison", "Poison enemies", false}},
{TowerType::Quake, {"Quake", "Shoot projectiles", false}}, {TowerType::Quake, {"Quake", "Shoot projectiles", false}},
{TowerType::Sorcerer, {"Sorcerer", "Summon friendly troops", false}}, {TowerType::Sorcerer, {"Sorcerer", "Summon friendly troops", false}},
{TowerType::Turret, {"Turret", "Shoot arrow very fast", true}}, {TowerType::Turret, {"Turret", "Shoot arrow very fast", true}},
{TowerType::Zeus, {"Zeus", "Strike lightning", false}}, {TowerType::Zeus, {"Zeus", "Strike lightning", false}},
}; };
const TowerInfo& getTowerInfo(TowerType type) { const TowerInfo& GetTowerInfo(TowerType type) {
return TowerInfoConstants.at(type); return TowerInfoConstants.at(type);
} }
@@ -152,168 +152,54 @@ namespace TowerFactory {
using TowerCreator = std::function<std::shared_ptr<Tower>(TowerID, std::int32_t, std::int32_t, PlayerID)>; using TowerCreator = std::function<std::shared_ptr<Tower>(TowerID, std::int32_t, std::int32_t, PlayerID)>;
static const std::map<TowerType, TowerCreator> towerFactory = { static const std::map<TowerType, TowerCreator> towerFactory = {
{TowerType::Archer, [](TowerID id, std::int32_t x, std::int32_t y, PlayerID builder) -> TowerPtr {return std::make_shared<ArcherTower>(id, x, y , builder);} }, {TowerType::Archer, [](TowerID id, std::int32_t x, std::int32_t y, PlayerID builder) -> TowerPtr {return std::make_shared<ArcherTower>(id, x, y , builder);} },
{TowerType::Artillery, [](TowerID id, std::int32_t x, std::int32_t y, PlayerID builder) -> TowerPtr {return std::make_shared<ArtilleryTower>(id, x, y , builder);} }, {TowerType::Artillery, [](TowerID id, std::int32_t x, std::int32_t y, PlayerID builder) -> TowerPtr {return std::make_shared<ArtilleryTower>(id, x, y , builder);} },
{TowerType::Ice, [](TowerID id, std::int32_t x, std::int32_t y, PlayerID builder) -> TowerPtr {return std::make_shared<IceTower>(id, x, y , builder);} }, {TowerType::Ice, [](TowerID id, std::int32_t x, std::int32_t y, PlayerID builder) -> TowerPtr {return std::make_shared<IceTower>(id, x, y , builder);} },
{TowerType::Mage, [](TowerID id, std::int32_t x, std::int32_t y, PlayerID builder) -> TowerPtr {return std::make_shared<MageTower>(id, x, y , builder);} }, {TowerType::Mage, [](TowerID id, std::int32_t x, std::int32_t y, PlayerID builder) -> TowerPtr {return std::make_shared<MageTower>(id, x, y , builder);} },
{TowerType::Poison, [](TowerID id, std::int32_t x, std::int32_t y, PlayerID builder) -> TowerPtr {return std::make_shared<PoisonTower>(id, x, y , builder);} }, {TowerType::Poison, [](TowerID id, std::int32_t x, std::int32_t y, PlayerID builder) -> TowerPtr {return std::make_shared<PoisonTower>(id, x, y , builder);} },
{TowerType::Quake, [](TowerID id, std::int32_t x, std::int32_t y, PlayerID builder) -> TowerPtr {return std::make_shared<QuakeTower>(id, x, y , builder);} }, {TowerType::Quake, [](TowerID id, std::int32_t x, std::int32_t y, PlayerID builder) -> TowerPtr {return std::make_shared<QuakeTower>(id, x, y , builder);} },
{TowerType::Sorcerer, [](TowerID id, std::int32_t x, std::int32_t y, PlayerID builder) -> TowerPtr {return std::make_shared<SorcererTower>(id, x, y , builder);} }, {TowerType::Sorcerer, [](TowerID id, std::int32_t x, std::int32_t y, PlayerID builder) -> TowerPtr {return std::make_shared<SorcererTower>(id, x, y , builder);} },
{TowerType::Zeus, [](TowerID id, std::int32_t x, std::int32_t y, PlayerID builder) -> TowerPtr {return std::make_shared<ZeusTower>(id, x, y , builder);} }, {TowerType::Zeus, [](TowerID id, std::int32_t x, std::int32_t y, PlayerID builder) -> TowerPtr {return std::make_shared<ZeusTower>(id, x, y , builder);} },
{TowerType::Leach, [](TowerID id, std::int32_t x, std::int32_t y, PlayerID builder) -> TowerPtr {return std::make_shared<LeachTower>(id, x, y , builder);} }, {TowerType::Leach, [](TowerID id, std::int32_t x, std::int32_t y, PlayerID builder) -> TowerPtr {return std::make_shared<LeachTower>(id, x, y , builder);} },
{TowerType::Necromancer, [](TowerID id, std::int32_t x, std::int32_t y, PlayerID builder) -> TowerPtr {return std::make_shared<NecromancerTower>(id, x, y , builder);} }, {TowerType::Necromancer, [](TowerID id, std::int32_t x, std::int32_t y, PlayerID builder) -> TowerPtr {return std::make_shared<NecromancerTower>(id, x, y , builder);} },
{TowerType::Turret, [](TowerID id, std::int32_t x, std::int32_t y, PlayerID builder) -> TowerPtr {return std::make_shared<TurretTower>(id, x, y , builder);} }, {TowerType::Turret, [](TowerID id, std::int32_t x, std::int32_t y, PlayerID builder) -> TowerPtr {return std::make_shared<TurretTower>(id, x, y , builder);} },
}; };
TowerPtr createTower(TowerType type, TowerID id, std::int32_t x, std::int32_t y, PlayerID builder) { TowerPtr CreateTower(TowerType type, TowerID id, std::int32_t x, std::int32_t y, PlayerID builder) {
return towerFactory.at(type)(id, x, y, builder); return towerFactory.at(type)(id, x, y, builder);
} }
std::string getTowerName(TowerType type) { std::string GetTowerName(TowerType type) {
switch (type) { switch (type) {
case TowerType::Archer: case TowerType::Archer:
return "Archer"; return "Archer";
case TowerType::Artillery: case TowerType::Artillery:
return "Artillery"; return "Artillery";
case TowerType::Ice: case TowerType::Ice:
return "Ice"; return "Ice";
case TowerType::Mage: case TowerType::Mage:
return "Mage"; return "Mage";
case TowerType::Poison: case TowerType::Poison:
return "Poison"; return "Poison";
case TowerType::Quake: case TowerType::Quake:
return "Quake"; return "Quake";
case TowerType::Sorcerer: case TowerType::Sorcerer:
return "Sorcerer"; return "Sorcerer";
case TowerType::Zeus: case TowerType::Zeus:
return "Zeus"; return "Zeus";
case TowerType::Leach: case TowerType::Leach:
return "Leach"; return "Leach";
case TowerType::Necromancer: case TowerType::Necromancer:
return "Necromancer"; return "Necromancer";
case TowerType::Turret: case TowerType::Turret:
return "Turret"; return "Turret";
default: default:
return "Unknow"; return "Unknow";
} }
} }
} // namespace TowerFactory } // namespace TowerFactory
void ArcherTower::tick(std::uint64_t delta, World* world) {
if (m_Timer.update(delta)) {
std::uint8_t arrowsShot = 0;
bool explosiveArrows = getLevel().getPath() == TowerPath::Bottom;
std::uint8_t arrows = explosiveArrows ? 2 : getLevel().getLevel();
for (MobPtr mob : world->getMobList()) {
if (isMobInRange(mob)) {
world->getWorldNotifier().notifyListeners(&WorldListener::OnArcherTowerShot, mob, this);
m_Timer.applyCooldown();
arrowsShot++;
if (arrowsShot >= arrows)
break;
}
}
}
}
void IceTower::tick(std::uint64_t delta, World* world) {
if (m_Timer.update(delta)) {
float damage = getStats()->getDamage();
for (MobPtr mob : world->getMobList()) {
if (isMobInRange(mob)) {
mob->addEffect(EffectType::Slowness, 1, this); // slowness for 1s every second
if (damage > 0)
world->getMobNotifier().notifyListeners(&MobListener::OnMobDamage, mob.get(), damage, this);
m_Timer.applyCooldown();
}
}
}
}
void MageTower::tick(std::uint64_t delta, World* world) {
if (m_Timer.update(delta)) {
for (MobPtr mob : world->getMobList()) {
if (isMobInRange(mob)) {
mob->addEffect(EffectType::Fire, getLevel().getLevel() * 3, this);
m_Timer.applyCooldown();
}
}
}
}
void PoisonTower::tick(std::uint64_t delta, World* world) {
if (m_Timer.update(delta)) {
for (MobPtr mob : world->getMobList()) {
if (isMobInRange(mob)) {
if (getLevel().getPath() == TowerPath::Bottom) {
world->getMobNotifier().notifyListeners(&MobListener::OnMobDamage, mob.get(), getStats()->getDamage(), this);
} else {
float durationSec;
switch (getLevel().getLevel()) {
case 1:
durationSec = 5;
break;
case 2:
durationSec = 15;
break;
case 3:
durationSec = 30;
break;
case 4:
durationSec = 1e10; // about 3 million hours. It should be enough
break;
default:
durationSec = 0; // how did we get there ?
break;
}
mob->addEffect(EffectType::Poison, durationSec, this);
}
m_Timer.applyCooldown();
}
}
}
}
void QuakeTower::tick(std::uint64_t delta, World* world) {
}
void ZeusTower::tick(std::uint64_t delta, World* world) {
}
void ArtilleryTower::tick(std::uint64_t delta, World* world) {
}
void SorcererTower::tick(std::uint64_t delta, World* world) {
}
void LeachTower::tick(std::uint64_t delta, World* world) {
}
void TurretTower::tick(std::uint64_t delta, World* world) {
}
void NecromancerTower::tick(std::uint64_t delta, World* world) {
}
} // namespace game } // namespace game
} // namespace td } // namespace td

View File

@@ -3,328 +3,321 @@
#include "protocol/Protocol.h" #include "protocol/Protocol.h"
#include "game/BaseGame.h" #include "game/BaseGame.h"
#include "misc/Random.h" #include "misc/Random.h"
#include "misc/Compression.h"
#include "misc/Format.h"
#include <cmath> #include <cmath>
#include "misc/Compression.h"
#include <iostream>
namespace td { namespace td {
namespace game { namespace game {
World::World(Game* game) : m_Game(game) { World::World(Game* game) : m_Game(game) {
getWorldNotifier().bindListener(this); GetWorldNotifier().BindListener(this);
getMobNotifier().bindListener(this); GetMobNotifier().BindListener(this);
} }
TilePtr World::getTile(std::int32_t x, std::int32_t y) const { TilePtr World::GetTile(std::int32_t x, std::int32_t y) const {
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 = std::abs(x % Chunk::ChunkWidth); std::uint16_t subChunkX = std::abs(x % Chunk::ChunkWidth);
std::uint16_t subChunkY = std::abs(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())
return nullptr; return nullptr;
ChunkPtr chunk = chunkIt->second; ChunkPtr chunk = chunkIt->second;
return getTilePtr(chunk->getTileIndex(subChunkY * Chunk::ChunkWidth + subChunkX)); return GetTilePtr(chunk->GetTileIndex(subChunkY * Chunk::ChunkWidth + subChunkX));
} }
bool World::loadMap(const protocol::WorldBeginDataPacket* worldHeader) { bool World::LoadMap(const protocol::WorldBeginDataPacket* worldHeader) {
m_TowerPlacePalette = worldHeader->getTowerTilePalette(); m_TowerPlacePalette = worldHeader->GetTowerTilePalette();
m_WalkablePalette = worldHeader->getWalkableTileColor(); m_WalkablePalette = worldHeader->GetWalkableTileColor();
m_DecorationPalette = worldHeader->getDecorationPalette(); m_DecorationPalette = worldHeader->GetDecorationPalette();
m_Background = worldHeader->getBackgroundColor(); m_Background = worldHeader->GetBackgroundColor();
getRedTeam().getSpawn() = worldHeader->getRedSpawn(); GetRedTeam().GetSpawn() = worldHeader->GetRedSpawn();
getBlueTeam().getSpawn() = worldHeader->getBlueSpawn(); GetBlueTeam().GetSpawn() = worldHeader->GetBlueSpawn();
m_SpawnColorPalette = worldHeader->getSpawnPalette(); m_SpawnColorPalette = worldHeader->GetSpawnPalette();
getRedTeam().getCastle() = worldHeader->getRedCastle(); GetRedTeam().GetCastle() = worldHeader->GetRedCastle();
getRedTeam().getCastle().setTeam(&getRedTeam()); GetRedTeam().GetCastle().SetTeam(&GetRedTeam());
getBlueTeam().getCastle() = worldHeader->getBlueCastle(); GetBlueTeam().GetCastle() = worldHeader->GetBlueCastle();
getBlueTeam().getCastle().setTeam(&getBlueTeam()); GetBlueTeam().GetCastle().SetTeam(&GetBlueTeam());
m_TilePalette = worldHeader->getTilePalette(); m_TilePalette = worldHeader->GetTilePalette();
return true; return true;
} }
bool World::loadMap(const protocol::WorldDataPacket* worldData) { bool World::LoadMap(const protocol::WorldDataPacket* worldData) {
m_Chunks = worldData->getChunks(); m_Chunks = worldData->GetChunks();
return true; return true;
} }
bool World::loadMapFromFile(const std::string& fileName) { bool World::LoadMapFromFile(const std::string& fileName) {
DataBuffer buffer; DataBuffer buffer;
if (!buffer.ReadFile(fileName)) { if (!buffer.ReadFile(fileName)) {
std::cerr << "Failed to load map from file " << fileName << " !\n"; utils::LOGE(utils::format("Failed to load map from file %s", fileName.c_str()));
return false; return false;
} }
std::cout << "Read file : " << fileName << " (File size : " << buffer.GetSize() << ")" << std::endl; utils::LOG(utils::format("Read file : %s (File size : %u)", fileName.c_str(), buffer.GetSize()));
DataBuffer mapHeaderPacketBuffer = utils::Decompress(buffer); DataBuffer mapHeaderPacketBuffer = utils::Decompress(buffer);
DataBuffer mapDataPacketBuffer = utils::Decompress(buffer); DataBuffer mapDataPacketBuffer = utils::Decompress(buffer);
protocol::PacketType packetType; protocol::WorldBeginDataPacket headerPacket;
headerPacket.Deserialize(mapHeaderPacketBuffer);
mapHeaderPacketBuffer >> packetType; protocol::WorldDataPacket dataPacket;
dataPacket.Deserialize(mapDataPacketBuffer);
protocol::WorldBeginDataPacket headerPacket; LoadMap(&headerPacket);
headerPacket.Deserialize(mapHeaderPacketBuffer); LoadMap(&dataPacket);
mapDataPacketBuffer >> packetType; return true;
protocol::WorldDataPacket dataPacket;
dataPacket.Deserialize(mapDataPacketBuffer);
loadMap(&headerPacket);
loadMap(&dataPacket);
return true;
} }
bool World::saveMap(const std::string& fileName) const { bool World::SaveMap(const std::string& fileName) const {
protocol::WorldBeginDataPacket headerPacket(this); protocol::WorldBeginDataPacket headerPacket(this);
protocol::WorldDataPacket dataPacket(this); protocol::WorldDataPacket dataPacket(this);
DataBuffer mapHeaderCompressed = utils::Compress(headerPacket.Serialize()); DataBuffer mapHeaderCompressed = utils::Compress(headerPacket.Serialize(false));
DataBuffer mapDataCompressed = utils::Compress(dataPacket.Serialize()); DataBuffer mapDataCompressed = utils::Compress(dataPacket.Serialize(false));
std::cout << "Header Packet Size : " << mapHeaderCompressed.GetSize() << std::endl; utils::LOG(utils::format("Header Packet Size : %u", mapHeaderCompressed.GetSize()));
std::cout << "World Data Packet Size : " << mapDataCompressed.GetSize() << std::endl; utils::LOG(utils::format("World Data Packet Size : %u", mapDataCompressed.GetSize()));
DataBuffer buffer = mapHeaderCompressed << mapDataCompressed; DataBuffer buffer = mapHeaderCompressed << mapDataCompressed;
std::cout << "Total Size : " << buffer.GetSize() << std::endl; utils::LOG(utils::format("Total Size : %u", buffer.GetSize()));
return buffer.WriteFile(fileName); return buffer.WriteFile(fileName);
} }
void World::tick(std::uint64_t delta) { void World::Tick(std::uint64_t delta) {
if (m_Game->getGameState() != GameState::Game) return; if (m_Game->GetGameState() != GameState::Game) return;
tickMobs(delta); TickMobs(delta);
for (TowerPtr tower : m_Towers) { for (TowerPtr tower : m_Towers) {
tower->tick(delta, this); tower->Tick(delta, this);
} }
cleanDeadMobs(); CleanDeadMobs();
} }
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->setCenter({ x, y }); mob->SetCenter({ x, y });
mob->setDirection(dir); mob->SetDirection(dir);
m_Mobs.push_back(mob); m_Mobs.push_back(mob);
getMobNotifier().notifyListeners(&MobListener::OnMobSpawn, mob.get()); GetMobNotifier().NotifyListeners(&MobListener::OnMobSpawn, mob.get());
} }
TowerPtr World::placeTowerAt(TowerID id, TowerType type, std::int32_t x, std::int32_t y, PlayerID builder) { TowerPtr World::PlaceTowerAt(TowerID id, TowerType type, std::int32_t x, std::int32_t y, PlayerID builder) {
TowerPtr tower = TowerFactory::createTower(type, id, x, y, builder); TowerPtr tower = TowerFactory::CreateTower(type, id, x, y, builder);
m_Towers.push_back(tower); m_Towers.push_back(tower);
return tower; return tower;
} }
TowerPtr World::removeTower(TowerID towerId) { TowerPtr World::RemoveTower(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;
TowerPtr tower = *it; TowerPtr tower = *it;
m_Towers.erase(it); m_Towers.erase(it);
return tower; 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, this); mob->Tick(delta, this);
} }
} }
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: {
TowerTile* towerTile = (TowerTile*)tile.get(); TowerTile* towerTile = dynamic_cast<TowerTile*>(tile.get());
return &m_TowerPlacePalette[towerTile->color_palette_ref]; return &m_TowerPlacePalette[towerTile->color_palette_ref];
} }
case TileType::Walk: { case TileType::Walk: {
return &m_WalkablePalette; return &m_WalkablePalette;
} }
case TileType::Decoration: { case TileType::Decoration: {
DecorationTile* towerTile = (DecorationTile*)tile.get(); DecorationTile* towerTile = dynamic_cast<DecorationTile*>(tile.get());
return &m_DecorationPalette[towerTile->color_palette_ref]; return &m_DecorationPalette[towerTile->color_palette_ref];
break; break;
} }
case TileType::None: { default: {
return nullptr; return nullptr;
} }
} }
return nullptr; return nullptr;
} }
bool World::CanPlaceLittleTower(const glm::vec2& worldPos, PlayerID playerID) const { bool World::CanPlaceLittleTower(const Vec2f& worldPos, PlayerID playerID) const {
TilePtr tile = getTile(worldPos.x, worldPos.y); TilePtr tile = GetTile(worldPos.x, worldPos.y);
const Player& player = m_Game->getPlayers()[playerID]; const Player& player = m_Game->GetPlayers()[playerID];
if (tile == nullptr) { if (tile == nullptr) {
return false; return false;
} }
if (tile->getType() == game::TileType::Tower) { if (tile->GetType() == game::TileType::Tower) {
const TowerTile* towerTile = (const TowerTile*)tile.get(); const TowerTile* towerTile = dynamic_cast<TowerTile*>(tile.get());
if (towerTile->team_owner != player.getTeamColor()) if (towerTile->team_owner != player.GetTeamColor())
return false; return false;
for (int x = -1; x < 2; x++) { for (int x = -1; x < 2; x++) {
for (int y = -1; y < 2; y++) { for (int y = -1; y < 2; y++) {
game::TilePtr adjacentTile = getTile(worldPos.x + x, worldPos.y + y); game::TilePtr adjacentTile = GetTile(worldPos.x + x, worldPos.y + y);
if (adjacentTile == nullptr || adjacentTile->getType() != game::TileType::Tower || getTower({ worldPos.x + x, worldPos.y + y }) != nullptr) { if (adjacentTile == nullptr || adjacentTile->GetType() != game::TileType::Tower || GetTower({ worldPos.x + x, worldPos.y + y }) != nullptr) {
return false; return false;
} }
} }
} }
return true; return true;
} }
return false; return false;
} }
bool World::CanPlaceBigTower(const glm::vec2& worldPos, PlayerID playerID) const { bool World::CanPlaceBigTower(const Vec2f& worldPos, PlayerID playerID) const {
if (!CanPlaceLittleTower(worldPos, playerID)) return false; if (!CanPlaceLittleTower(worldPos, playerID)) return false;
TilePtr tile = getTile(worldPos.x, worldPos.y); TilePtr tile = GetTile(worldPos.x, worldPos.y);
const Player& player = m_Game->getPlayers()[playerID]; const Player& player = m_Game->GetPlayers()[playerID];
if (tile == nullptr) { if (tile == nullptr) {
return false; return false;
} }
if (tile->getType() == game::TileType::Tower) { if (tile->GetType() == game::TileType::Tower) {
const TowerTile* towerTile = (const TowerTile*)tile.get(); const TowerTile* towerTile = dynamic_cast<const TowerTile*>(tile.get());
if (towerTile->team_owner != player.getTeamColor()) if (towerTile->team_owner != player.GetTeamColor())
return false; return false;
for (int x = -2; x < 3; x++) { for (int x = -2; x < 3; x++) {
for (int y = -2; y < 3; y++) { for (int y = -2; y < 3; y++) {
game::TilePtr adjacentTile = getTile(worldPos.x + x, worldPos.y + y); game::TilePtr adjacentTile = GetTile(worldPos.x + x, worldPos.y + y);
if (adjacentTile == nullptr || adjacentTile->getType() != game::TileType::Tower || getTower({ worldPos.x + x, worldPos.y + y }) != nullptr) { if (adjacentTile == nullptr || adjacentTile->GetType() != game::TileType::Tower || GetTower({ worldPos.x + x, worldPos.y + y }) != nullptr) {
return false; return false;
} }
} }
} }
return true; return true;
} }
return false; return false;
} }
void World::cleanDeadMobs() { void World::CleanDeadMobs() {
// safely remove mobs when unused // safely remove mobs when unused
for (std::size_t i = 0; i < m_Mobs.size(); i++) { for (std::size_t i = 0; i < m_Mobs.size(); i++) {
MobPtr mob = m_Mobs[i]; MobPtr mob = m_Mobs[i];
if (mob->isDead()) { if (mob->IsDead()) {
m_Mobs.erase(m_Mobs.begin() + i); m_Mobs.erase(m_Mobs.begin() + static_cast<int>(i));
} }
} }
} }
TowerPtr World::getTower(const glm::vec2& position) const { TowerPtr World::GetTower(const Vec2f& position) const {
for (TowerPtr tower : m_Towers) { for (TowerPtr tower : m_Towers) {
if (tower->getSize() == TowerSize::Big) { if (tower->GetSize() == TowerSize::Big) {
if (tower->getCenterX() - 2.5f < position.x && tower->getCenterX() + 2.5f > position.x && if (tower->GetCenterX() - 2.5f < position.x && tower->GetCenterX() + 2.5f > position.x &&
tower->getCenterY() - 2.5f < position.y && tower->getCenterY() + 2.5f > position.y) { tower->GetCenterY() - 2.5f < position.y && tower->GetCenterY() + 2.5f > position.y) {
return tower; return tower;
} }
} else { // little tower } else { // little tower
if (tower->getCenterX() - 1.5f < position.x && tower->getCenterX() + 1.5f > position.x && if (tower->GetCenterX() - 1.5f < position.x && tower->GetCenterX() + 1.5f > position.x &&
tower->getCenterY() - 1.5f < position.y && tower->getCenterY() + 1.5f > position.y) { tower->GetCenterY() - 1.5f < position.y && tower->GetCenterY() + 1.5f > position.y) {
return tower; return tower;
} }
} }
} }
return nullptr; return nullptr;
} }
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::OnArcherTowerShot(MobPtr target, ArcherTower* shooter) { void World::OnArcherTowerShot(MobPtr tarGet, ArcherTower* shooter) {
bool fireArrows = shooter->getLevel().getPath() == TowerPath::Bottom; bool fireArrows = shooter->GetLevel().GetPath() == TowerPath::Bottom;
bool explosiveArrows = shooter->getLevel().getLevel() == 4 && fireArrows; bool explosiveArrows = shooter->GetLevel().GetLevel() == 4 && fireArrows;
getWorldNotifier().notifyListeners(&WorldListener::OnArrowShot, target, fireArrows, shooter); GetWorldNotifier().NotifyListeners(&WorldListener::OnArrowShot, tarGet, fireArrows, shooter);
if (explosiveArrows) { if (explosiveArrows) {
getWorldNotifier().notifyListeners(&WorldListener::OnExplosion, utils::shape::Circle{ target->getCenterX(), target->getCenterY(), ArcherTower::ExplosionRadius }, shooter->getStats()->getDamage(), shooter); GetWorldNotifier().NotifyListeners(&WorldListener::OnExplosion, utils::shape::Circle{ tarGet->GetCenterX(), tarGet->GetCenterY(), ArcherTower::ExplosionRadius }, shooter->GetStats()->GetDamage(), shooter);
} }
} }
void World::OnArrowShot(MobPtr target, bool fireArrow, Tower* shooter) { void World::OnArrowShot(MobPtr tarGet, bool fireArrow, Tower* shooter) {
getMobNotifier().notifyListeners(&MobListener::OnMobDamage, target.get(), shooter->getStats()->getDamage(), shooter); GetMobNotifier().NotifyListeners(&MobListener::OnMobDamage, tarGet.get(), shooter->GetStats()->GetDamage(), shooter);
if (fireArrow) { if (fireArrow) {
target->addEffect(EffectType::Fire, ArcherTower::FireDurationSec, shooter); tarGet->AddEffect(EffectType::Fire, ArcherTower::FireDurationSec, shooter);
} }
} }
void World::OnExplosion(utils::shape::Circle explosion, float centerDamage, Tower* shooter) { void World::OnExplosion(utils::shape::Circle explosion, float centerDamage, Tower* shooter) {
for (MobPtr mob : m_Mobs) { for (MobPtr mob : m_Mobs) {
if (mob->isAlive() && mob->collidesWith(explosion)) { if (mob->IsAlive() && mob->CollidesWith(explosion)) {
// linear distance damage reduction // linear distance damage reduction
float explosionDamage = mob->distance(explosion) / explosion.getRadius() * centerDamage; float explosionDamage = mob->Distance(explosion) / explosion.GetRadius() * centerDamage;
getMobNotifier().notifyListeners(&MobListener::OnMobDamage, mob.get(), explosionDamage, shooter); GetMobNotifier().NotifyListeners(&MobListener::OnMobDamage, mob.get(), explosionDamage, shooter);
} }
} }
} }
void World::OnMobCastleDamage(Mob* damager, TeamCastle* enemyCastle, float damage) { void World::OnMobCastleDamage(Mob* damager, TeamCastle* enemyCastle, float damage) {
enemyCastle->damage(damage); enemyCastle->Damage(damage);
if (enemyCastle->getLife() <= 0) { if (enemyCastle->GetLife() <= 0) {
m_Game->notifyListeners(&GameListener::OnGameEnd); m_Game->NotifyListeners(&GameListener::OnGameEnd);
} }
} }
void World::OnMobDamage(Mob* target, float damage, Tower* source) { void World::OnMobDamage(Mob* tarGet, float damage, Tower* source) {
target->damage(damage, source); tarGet->Damage(damage, source);
if (target->isDead()) { if (tarGet->IsDead()) {
getMobNotifier().notifyListeners(&MobListener::OnMobDie, target); GetMobNotifier().NotifyListeners(&MobListener::OnMobDie, tarGet);
} }
} }
Team& World::getRedTeam() { Team& World::GetRedTeam() {
return m_Game->getRedTeam(); return m_Game->GetRedTeam();
} }
const Team& World::getRedTeam() const { const Team& World::GetRedTeam() const {
return m_Game->getRedTeam(); return m_Game->GetRedTeam();
} }
Team& World::getBlueTeam() { Team& World::GetBlueTeam() {
return m_Game->getBlueTeam(); return m_Game->GetBlueTeam();
} }
const Team& World::getBlueTeam() const { const Team& World::GetBlueTeam() const {
return m_Game->getBlueTeam(); return m_Game->GetBlueTeam();
} }
Team& World::getTeam(TeamColor team) { Team& World::GetTeam(TeamColor team) {
return m_Game->getTeam(team); return m_Game->GetTeam(team);
} }
const Team& World::getTeam(TeamColor team) const { const Team& World::GetTeam(TeamColor team) const {
return m_Game->getTeam(team); return m_Game->GetTeam(team);
} }
const Player* World::getPlayerById(PlayerID id) const { const Player* World::GetPlayerById(PlayerID id) const {
return m_Game->getPlayerById(id); return m_Game->GetPlayerById(id);
} }
const TeamList& World::getTeams() const { const TeamList& World::GetTeams() const {
return m_Game->getTeams(); return m_Game->GetTeams();
} }
} // namespace game } // namespace game

View File

@@ -1,78 +1,77 @@
#include "game/client/Client.h" #include "game/client/Client.h"
#include "misc/Format.h"
#include <iostream>
namespace td { namespace td {
namespace client { namespace client {
bool Client::connect(const network::IPAddresses& addresses, std::uint16_t port) { bool Client::Connect(const network::IPAddresses& addresses, std::uint16_t port) {
for (const network::IPAddress& address : addresses) { for (const network::IPAddress& address : addresses) {
if (address.IsValid() && m_Connexion.connect(address.ToString(), port)) { if (address.IsValid() && m_Connexion.Connect(address.ToString(), port)) {
m_Connected = true; m_Connected = true;
return true; return true;
} }
} }
std::cout << "Failed to connect !\n"; utils::LOGE("Failed to connect !");
return false; return false;
} }
void Client::selectTeam(game::TeamColor team) { void Client::SelectTeam(game::TeamColor team) {
if (!m_Connected) if (!m_Connected)
return; return;
protocol::SelectTeamPacket packet(team); protocol::SelectTeamPacket packet(team);
m_Connexion.sendPacket(&packet); m_Connexion.SendPacket(&packet);
} }
void Client::closeConnection() { void Client::CloseConnection() {
if (!m_Connected) if (!m_Connected)
return; return;
m_Connected = false; m_Connected = false;
protocol::DisconnectPacket packet; protocol::DisconnectPacket packet;
m_Connexion.sendPacket(&packet); m_Connexion.SendPacket(&packet);
} }
void Client::tick(std::uint64_t delta) { void Client::Tick(std::uint64_t delta) {
if (!m_Connected) if (!m_Connected)
return; return;
m_Connected = m_Connexion.updateSocket(); m_Connected = m_Connexion.UpdateSocket();
if (!m_Connected) { if (!m_Connected) {
std::cout << "Disconnected ! (Reason : " << m_Connexion.getDisconnectReason() << ")\n"; utils::LOG(utils::format("Disconnected ! (Reason : %s)", m_Connexion.GetDisconnectReason().c_str()));
reset(); Reset();
} else { } else {
m_Game->tick(delta); m_Game->Tick(delta);
} }
} }
void Client::render() { void Client::Render() {
m_Game->renderWorld(); m_Game->RenderWorld();
} }
void Client::reset() { void Client::Reset() {
m_Game.reset(0); m_Game.reset(0);
m_Game = std::make_unique<ClientGame>(this); m_Game = std::make_unique<ClientGame>(this);
} }
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);
} }
void Client::placeTower(game::TowerType type, const glm::vec2& position) { void Client::PlaceTower(game::TowerType type, const Vec2f& position) {
protocol::PlaceTowerPacket packet(position.x, position.y, type); protocol::PlaceTowerPacket packet(position.x, position.y, type);
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) { void Client::RemoveTower(game::TowerID tower) {
protocol::RemoveTowerPacket packet(tower); protocol::RemoveTowerPacket packet(tower);
m_Connexion.sendPacket(&packet); m_Connexion.SendPacket(&packet);
} }
} // namespace client } // namespace client

View File

@@ -5,43 +5,44 @@ namespace td {
namespace client { namespace client {
ClientConnexion::ClientConnexion() : Connexion(&m_Dispatcher), m_ServerTPS(0) { ClientConnexion::ClientConnexion() : Connexion(&m_Dispatcher), m_ServerTPS(0) {
registerHandlers(); RegisterHandlers();
} }
void ClientConnexion::registerHandlers() { void ClientConnexion::RegisterHandlers() {
GetDispatcher()->RegisterHandler(protocol::PacketType::KeepAlive, this); GetDispatcher()->RegisterHandler(protocol::PacketType::KeepAlive, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::ConnectionInfo, this); GetDispatcher()->RegisterHandler(protocol::PacketType::ConnectionInfo, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::Disconnect, this); GetDispatcher()->RegisterHandler(protocol::PacketType::Disconnect, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::ServerTps, this); GetDispatcher()->RegisterHandler(protocol::PacketType::ServerTps, this);
} }
void ClientConnexion::HandlePacket(const protocol::KeepAlivePacket* packet) { void ClientConnexion::HandlePacket(const protocol::KeepAlivePacket* packet) {
protocol::KeepAlivePacket keepAlivePacket(packet->getAliveID()); protocol::KeepAlivePacket keepAlivePacket(packet->GetAliveID());
sendPacket(&keepAlivePacket); SendPacket(&keepAlivePacket);
} }
void ClientConnexion::HandlePacket(const protocol::ConnexionInfoPacket* packet) { void ClientConnexion::HandlePacket(const protocol::ConnexionInfoPacket* packet) {
m_ConnectionID = packet->getConnectionID(); m_ConnectionID = packet->GetConnectionID();
login(); Login();
} }
void ClientConnexion::HandlePacket(const protocol::ServerTpsPacket* packet) { void ClientConnexion::HandlePacket(const protocol::ServerTpsPacket* packet) {
m_ServerTPS = packet->getTPS(); m_ServerTPS = packet->GetTPS();
m_Ping = utils::getTime() - packet->getPacketSendTime(); m_ServerMSPT = packet->GetMSPT();
m_Ping = utils::GetTime() - packet->GetPacketSendTime();
} }
void ClientConnexion::login() { void ClientConnexion::Login() {
td::protocol::PlayerLoginPacket loginPacket("Persson" + std::to_string(m_ConnectionID)); td::protocol::PlayerLoginPacket loginPacket("Persson" + std::to_string(m_ConnectionID));
sendPacket(&loginPacket); SendPacket(&loginPacket);
} }
bool ClientConnexion::updateSocket() { bool ClientConnexion::UpdateSocket() {
return Connexion::updateSocket(); return Connexion::UpdateSocket();
} }
void ClientConnexion::HandlePacket(const protocol::DisconnectPacket* packet) { void ClientConnexion::HandlePacket(const protocol::DisconnectPacket* packet) {
m_DisconnectReason = packet->getReason(); m_DisconnectReason = packet->GetReason();
closeConnection(); CloseConnection();
} }
} // namespace client } // namespace client

View File

@@ -5,108 +5,113 @@
namespace td { namespace td {
namespace client { namespace client {
ClientGame::ClientGame(Client* client) : protocol::PacketHandler(client->getConnexion().GetDispatcher()), ClientGame::ClientGame(Client* client) : protocol::PacketHandler(client->GetConnexion().GetDispatcher()),
game::Game(&m_WorldClient), m_Client(client), m_Renderer(client->getRenderer()), m_WorldClient(this), game::Game(&m_WorldClient), m_Client(client), m_Renderer(client->GetRenderer()), m_WorldClient(this),
m_WorldRenderer(&m_WorldClient, this) { m_WorldRenderer(&m_WorldClient, this) {
GetDispatcher()->RegisterHandler(protocol::PacketType::ConnectionInfo, this); GetDispatcher()->RegisterHandler(protocol::PacketType::ConnectionInfo, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::PlayerJoin, this); GetDispatcher()->RegisterHandler(protocol::PacketType::PlayerJoin, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::PlayerList, this); GetDispatcher()->RegisterHandler(protocol::PacketType::PlayerList, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::PlayerLeave, this); GetDispatcher()->RegisterHandler(protocol::PacketType::PlayerLeave, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::UpdatePlayerTeam, this); GetDispatcher()->RegisterHandler(protocol::PacketType::UpdatePlayerTeam, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::UpdateLobbyTime, this); GetDispatcher()->RegisterHandler(protocol::PacketType::UpdateLobbyTime, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::UpdateGameState, this); GetDispatcher()->RegisterHandler(protocol::PacketType::UpdateGameState, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::UpdateMoney, this); GetDispatcher()->RegisterHandler(protocol::PacketType::UpdateMoney, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::Disconnect, this); GetDispatcher()->RegisterHandler(protocol::PacketType::UpdateEXP, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::WorldData, this); GetDispatcher()->RegisterHandler(protocol::PacketType::Disconnect, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::WorldData, this);
} }
ClientGame::~ClientGame() { ClientGame::~ClientGame() {
GetDispatcher()->UnregisterHandler(this); GetDispatcher()->UnregisterHandler(this);
} }
void ClientGame::tick(std::uint64_t delta) { void ClientGame::Tick(std::uint64_t delta) {
game::Game::tick(delta); game::Game::Tick(delta);
m_WorldRenderer.update(); m_WorldRenderer.Update();
if (m_GameState == game::GameState::Lobby && m_LobbyTime > 0) { if (m_GameState == game::GameState::Lobby && m_LobbyTime > 0) {
m_LobbyTime -= delta; m_LobbyTime -= delta;
} }
} }
void ClientGame::HandlePacket(const protocol::PlayerJoinPacket* packet) { void ClientGame::HandlePacket(const protocol::PlayerJoinPacket* packet) {
game::Player player(packet->getPlayerID()); game::Player player(packet->GetPlayerID());
player.setName(packet->getPlayerName()); player.SetName(packet->GetPlayerName());
m_Players.insert({ player.getID(), player }); m_Players.insert({ player.GetID(), player });
} }
void ClientGame::HandlePacket(const protocol::PlayerLeavePacket* packet) { void ClientGame::HandlePacket(const protocol::PlayerLeavePacket* packet) {
game::Player* player = &m_Players[packet->getPlayerID()]; game::Player* player = &m_Players[packet->GetPlayerID()];
if (player->getTeamColor() != game::TeamColor::None) { if (player->GetTeamColor() != game::TeamColor::None) {
m_Teams[(std::size_t)player->getTeamColor()].removePlayer(player); m_Teams[(std::size_t)player->GetTeamColor()].RemovePlayer(player);
} }
m_Players.erase(player->getID()); m_Players.erase(player->GetID());
} }
void ClientGame::HandlePacket(const protocol::PlayerListPacket* packet) { void ClientGame::HandlePacket(const protocol::PlayerListPacket* packet) {
for (auto pair : packet->getPlayers()) { for (auto pair : packet->GetPlayers()) {
std::uint8_t playerID = pair.first; std::uint8_t playerID = pair.first;
protocol::PlayerInfo playerInfo = pair.second; protocol::PlayerInfo playerInfo = pair.second;
game::Player player(playerID); game::Player player(playerID);
player.setName(playerInfo.name); player.SetName(playerInfo.name);
player.setTeamColor(playerInfo.team); player.SetTeamColor(playerInfo.team);
m_Players.insert({ playerID, player }); m_Players.insert({ playerID, player });
if (player.getTeamColor() != game::TeamColor::None) { if (player.GetTeamColor() != game::TeamColor::None) {
m_Teams[(std::size_t)player.getTeamColor()].addPlayer(&m_Players[playerID]); m_Teams[(std::size_t)player.GetTeamColor()].AddPlayer(&m_Players[playerID]);
} }
} }
m_Player = &m_Players[m_ConnexionID]; m_Player = &m_Players[m_ConnexionID];
} }
void ClientGame::HandlePacket(const protocol::UpdatePlayerTeamPacket* packet) { void ClientGame::HandlePacket(const protocol::UpdatePlayerTeamPacket* packet) {
game::Player* player = &m_Players[packet->getPlayerID()]; game::Player* player = &m_Players[packet->GetPlayerID()];
if (player->getTeamColor() == game::TeamColor::None) { //join a team if (player->GetTeamColor() == game::TeamColor::None) { //join a team
getTeam(packet->getSelectedTeam()).addPlayer(player); GetTeam(packet->GetSelectedTeam()).AddPlayer(player);
} else if (packet->getSelectedTeam() == game::TeamColor::None) { // leave a team } else if (packet->GetSelectedTeam() == game::TeamColor::None) { // leave a team
getTeam(player->getTeamColor()).removePlayer(player); GetTeam(player->GetTeamColor()).RemovePlayer(player);
} else { // change team } else { // change team
getTeam(player->getTeamColor()).removePlayer(player); GetTeam(player->GetTeamColor()).RemovePlayer(player);
getTeam(packet->getSelectedTeam()).addPlayer(player); GetTeam(packet->GetSelectedTeam()).AddPlayer(player);
} }
player->setTeamColor(packet->getSelectedTeam()); player->SetTeamColor(packet->GetSelectedTeam());
} }
void ClientGame::HandlePacket(const protocol::UpdateGameStatePacket* packet) { void ClientGame::HandlePacket(const protocol::UpdateGameStatePacket* packet) {
setGameState(packet->getGameState()); SetGameState(packet->GetGameState());
} }
void ClientGame::HandlePacket(const protocol::ConnexionInfoPacket* packet) { void ClientGame::HandlePacket(const protocol::ConnexionInfoPacket* packet) {
m_ConnexionID = packet->getConnectionID(); m_ConnexionID = packet->GetConnectionID();
} }
void ClientGame::HandlePacket(const protocol::UpdateLobbyTimePacket* packet) { void ClientGame::HandlePacket(const protocol::UpdateLobbyTimePacket* packet) {
m_LobbyTime = packet->getRemainingTime(); m_LobbyTime = packet->GetRemainingTime();
} }
void ClientGame::HandlePacket(const protocol::UpdateMoneyPacket* packet) { void ClientGame::HandlePacket(const protocol::UpdateMoneyPacket* packet) {
m_Player->setGold(packet->getGold()); m_Player->SetGold(packet->GetGold());
}
void ClientGame::HandlePacket(const protocol::UpdateExpPacket* packet) {
m_Player->SetExp(packet->GetExp());
} }
void ClientGame::HandlePacket(const protocol::DisconnectPacket* packet) { void ClientGame::HandlePacket(const protocol::DisconnectPacket* packet) {
m_GameState = game::GameState::Disconnected; m_GameState = game::GameState::Disconnected;
m_Renderer->setBackgroundColor({ 0, 0, 0 }); m_Renderer->SetBackgroundColor({ 0, 0, 0 });
} }
void ClientGame::HandlePacket(const protocol::WorldDataPacket* packet) { 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.getCenterX(), spawn.getCenterY()); m_WorldRenderer.SetCamPos(spawn.GetCenterX(), spawn.GetCenterY());
} }
void ClientGame::renderWorld() { void ClientGame::RenderWorld() {
if (m_GameState == game::GameState::Game || m_GameState == game::GameState::EndGame) { if (m_GameState == game::GameState::Game || m_GameState == game::GameState::EndGame) {
m_WorldRenderer.render(); m_WorldRenderer.Render();
} }
} }
} // namespace client } // namespace client

View File

@@ -7,69 +7,69 @@ 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::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); GetDispatcher()->RegisterHandler(protocol::PacketType::RemoveTower, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::UpdateCastleLife, this); GetDispatcher()->RegisterHandler(protocol::PacketType::UpdateCastleLife, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::UpdateMobStates, this); GetDispatcher()->RegisterHandler(protocol::PacketType::UpdateMobStates, this);
} }
void WorldClient::HandlePacket(const protocol::WorldBeginDataPacket* packet) { void WorldClient::HandlePacket(const protocol::WorldBeginDataPacket* packet) {
loadMap(packet); LoadMap(packet);
if (m_Game->getGameState() == game::GameState::Game) { if (m_Game->GetGameState() == game::GameState::Game) {
const game::Color& backgroundColor = getBackgroundColor(); const Color& backgroundColor = GetBackgroundColor();
m_Game->getRenderer()->setBackgroundColor({ static_cast<float>(backgroundColor.r / 255.0f), static_cast<float>(backgroundColor.g / 255.0f), m_Game->GetRenderer()->SetBackgroundColor({ static_cast<float>(backgroundColor.r / 255.0f), static_cast<float>(backgroundColor.g / 255.0f),
static_cast<float>(backgroundColor.b / 255.0f) }); static_cast<float>(backgroundColor.b / 255.0f) });
} }
} }
void WorldClient::HandlePacket(const protocol::WorldDataPacket* packet) { void WorldClient::HandlePacket(const protocol::WorldDataPacket* packet) {
loadMap(packet); LoadMap(packet);
} }
void WorldClient::HandlePacket(const protocol::SpawnMobPacket* packet) { void WorldClient::HandlePacket(const protocol::SpawnMobPacket* packet) {
spawnMobAt(packet->getMobID(), packet->getMobType(), packet->getMobLevel(), packet->getSender(), SpawnMobAt(packet->GetMobID(), packet->GetMobType(), packet->GetMobLevel(), packet->GetSender(),
packet->getMobX(), packet->getMobY(), packet->getMobDirection()); packet->GetMobX(), packet->GetMobY(), packet->GetMobDirection());
} }
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::HandlePacket(const protocol::WorldAddTowerPacket* packet) { void WorldClient::HandlePacket(const protocol::WorldAddTowerPacket* packet) {
game::TowerPtr newTower = placeTowerAt(packet->getTowerID(), packet->getTowerType(), packet->getTowerX(), packet->getTowerY(), packet->getBuilder()); game::TowerPtr newTower = PlaceTowerAt(packet->GetTowerID(), packet->GetTowerType(), packet->GetTowerX(), packet->GetTowerY(), packet->GetBuilder());
getWorldNotifier().notifyListeners(&WorldListener::OnTowerAdd, newTower); GetWorldNotifier().NotifyListeners(&WorldListener::OnTowerAdd, newTower);
} }
void WorldClient::HandlePacket(const protocol::RemoveTowerPacket* packet) { void WorldClient::HandlePacket(const protocol::RemoveTowerPacket* packet) {
game::TowerPtr tower = removeTower(packet->getTowerID()); game::TowerPtr tower = RemoveTower(packet->GetTowerID());
if (tower != nullptr) { if (tower != nullptr) {
getWorldNotifier().notifyListeners(&WorldListener::OnTowerRemove, tower); GetWorldNotifier().NotifyListeners(&WorldListener::OnTowerRemove, tower);
} }
} }
void WorldClient::HandlePacket(const protocol::UpdateMobStatesPacket* packet) { void WorldClient::HandlePacket(const protocol::UpdateMobStatesPacket* packet) {
for (auto mobState : packet->getMobStates()) { for (auto mobState : packet->GetMobStates()) {
game::MobID mobId = mobState.getMobId(); game::MobID mobId = mobState.GetMobId();
auto it = std::find_if(getMobList().begin(), getMobList().end(), [mobId](game::MobPtr mob) { return mob->getMobID() == mobId; }); auto it = std::find_if(GetMobList().begin(), GetMobList().end(), [mobId](game::MobPtr mob) { return mob->GetMobID() == mobId; });
if (it != getMobList().end()) { if (it != GetMobList().end()) {
game::MobPtr& mob = *it; game::MobPtr& mob = *it;
mob->setCenter(mobState.getMobPosition()); mob->SetCenter(mobState.GetMobPosition());
mob->setDirection(mobState.getMobDirection()); mob->SetDirection(mobState.GetMobDirection());
mob->setHealth(mobState.getMobLife()); mob->SetHealth(mobState.GetMobLife());
} }
} }
} }
void WorldClient::HandlePacket(const protocol::UpdateCastleLifePacket* packet) { void WorldClient::HandlePacket(const protocol::UpdateCastleLifePacket* packet) {
getTeam(packet->getTeamColor()).getCastle().setLife(packet->getCastleLife()); GetTeam(packet->GetTeamColor()).GetCastle().SetLife(packet->GetCastleLife());
} }
} // namespace client } // namespace client

View File

@@ -3,8 +3,6 @@
#include "misc/Time.h" #include "misc/Time.h"
#include <iostream>
#ifdef NDEBUG #ifdef NDEBUG
#define MIN_PLAYER_WAITING 2 #define MIN_PLAYER_WAITING 2
#else #else
@@ -15,66 +13,68 @@ namespace td {
namespace server { namespace server {
/*static constexpr std::uint8_t timeNotifications[] = { /*static constexpr std::uint8_t timeNotifications[] = {
2 * 60, // 2 min 2 * 60, // 2 min
60 + 30, // 1 min 30 s 60 + 30, // 1 min 30 s
60, // 1 min 60, // 1 min
30, // 30 s 30, // 30 s
15, // 15 s 15, // 15 s
10, // 10 s 10, // 10 s
5, // 5 s 5, // 5 s
4, // 4 s 4, // 4 s
3, // 3 s 3, // 3 s
2, // 2 s 2, // 2 s
1, // 1 s 1, // 1 s
};*/ };*/
Lobby::Lobby(Server* server) : m_Server(server), m_Timer(1000, std::bind(&Lobby::sendTimeRemaining, this)) { Lobby::Lobby(Server* server) : m_Server(server), m_Timer(1000, std::bind(&Lobby::SendTimeRemaining, this)) {
} }
void Lobby::tick() { void Lobby::Tick() {
if (m_GameStarted || m_StartTimerTime == 0) if (m_GameStarted || m_StartTimerTime == 0)
return; return;
if (utils::getTime() - m_StartTimerTime >= LobbyWaitingTime) { if (utils::GetTime() - m_StartTimerTime >= LobbyWaitingTime) {
m_Server->getGame().notifyListeners(&game::GameListener::OnGameBegin); m_Server->GetGame().NotifyListeners(&game::GameListener::OnGameBegin);
m_GameStarted = true; m_GameStarted = true;
return; return;
} }
m_Timer.update(); m_Timer.Update();
} }
void Lobby::sendTimeRemaining() { void Lobby::SendTimeRemaining() {
protocol::UpdateLobbyTimePacket packet(LobbyWaitingTime - (utils::getTime() - m_StartTimerTime)); // converting second to millis protocol::UpdateLobbyTimePacket packet(LobbyWaitingTime - (utils::GetTime() - m_StartTimerTime)); // converting second to millis
m_Server->broadcastPacket(&packet); m_Server->BroadcastPacket(&packet);
} }
void Lobby::OnPlayerJoin(std::uint8_t playerID) { void Lobby::OnPlayerJoin(std::uint8_t playerID) {
if (m_GameStarted) if (m_GameStarted)
return; return;
std::cout << "(Server) Player Joined Lobby !\n"; utils::LOG("(Server) Player Joined Lobby !");
m_Players.push_back(playerID); m_Players.push_back(playerID);
if (m_Players.size() == MIN_PLAYER_WAITING) { // start timer if a second player join the match if (m_Players.size() == MIN_PLAYER_WAITING) { // start timer if a second player join the match
m_StartTimerTime = utils::getTime(); m_StartTimerTime = utils::GetTime();
m_Timer.reset(); m_Timer.Reset();
sendTimeRemaining(); SendTimeRemaining();
} }
} }
void Lobby::OnPlayerLeave(std::uint8_t playerID) { void Lobby::OnPlayerLeave(std::uint8_t playerID) {
if (m_GameStarted) if (m_GameStarted)
return; return;
std::cout << "(Server) Player Leaved Lobby !\n"; utils::LOG("(Server) Player Leaved Lobby !");
auto it = std::find(m_Players.begin(), m_Players.end(), playerID);
if (it == m_Players.end()) auto it = std::find(m_Players.begin(), m_Players.end(), playerID);
return; if (it == m_Players.end())
m_Players.erase(it); return;
if (m_Players.size() == 1) { m_Players.erase(it);
protocol::UpdateLobbyTimePacket packet(0);
m_Server->broadcastPacket(&packet); if (m_Players.size() == 1) {
m_StartTimerTime = 0; // reset timer if there is only one player left protocol::UpdateLobbyTimePacket packet(0);
} m_Server->BroadcastPacket(&packet);
m_StartTimerTime = 0; // reset timer if there is only one player left
}
} }
} // namespace server } // namespace server

View File

@@ -1,144 +1,146 @@
#include "game/server/Server.h" #include "game/server/Server.h"
#include <iostream>
#include "protocol/PacketFactory.h" #include "protocol/PacketFactory.h"
#include "misc/Format.h"
namespace td { namespace td {
namespace server { namespace server {
Server::Server(const std::string& worldFilePath) : m_ServerRunning(false) { Server::Server(const std::string& worldFilePath) : m_ServerRunning(false) {
m_Game.getWorld()->loadMapFromFile(worldFilePath); m_Game.GetWorld()->LoadMapFromFile(worldFilePath);
} }
Server::~Server() { Server::~Server() {
if (m_Thread.joinable()) if (m_Thread.joinable())
m_Thread.join(); m_Thread.join();
} }
void Server::startThread() { void Server::StartThread() {
m_Thread = std::thread([this]() { m_Thread = std::thread([this]() {
std::uint64_t lastTime = td::utils::getTime(); std::uint64_t lastTime = td::utils::GetTime();
while (m_ServerRunning) { while (m_ServerRunning) {
std::uint64_t time = td::utils::getTime(); std::uint64_t time = td::utils::GetTime();
std::uint64_t delta = time - lastTime; std::uint64_t delta = time - lastTime;
if (delta >= SERVER_TICK) { if (delta >= SERVER_TICK) {
tick(delta); Tick(delta);
lastTime = td::utils::getTime(); lastTime = td::utils::GetTime();
std::uint64_t sleepTime = SERVER_TICK - (delta - SERVER_TICK); m_TickCounter.SetMSPT(lastTime - time);
std::this_thread::sleep_for(std::chrono::milliseconds(sleepTime)); std::uint64_t sleepTime = SERVER_TICK - (delta - SERVER_TICK);
} std::this_thread::sleep_for(std::chrono::milliseconds(sleepTime));
}
} }
clean(); Clean();
}); });
} }
void Server::close() { void Server::Close() {
stopThread(); StopThread();
} }
void Server::stopThread() { void Server::StopThread() {
m_ServerRunning = false; m_ServerRunning = false;
} }
bool Server::start(std::uint16_t port) { bool Server::Start(std::uint16_t port) {
if (!m_Listener.listen(port, 10)) { if (!m_Listener.Listen(port, 10)) {
std::cout << "Failed to bind port " << port << " !\n"; utils::LOGE(utils::format("Failed to bind port %u !", port));
return false; return false;
} }
if (!m_Listener.setBlocking(false)) { if (!m_Listener.SetBlocking(false)) {
std::cout << "Failed to block server socket !\n"; utils::LOGE("Failed to block server socket !");
return false; return false;
} }
std::cout << "Server started at port " << port << " !\n"; utils::LOG(utils::format("Server started at port %u !", port));
m_TickCounter.reset(); m_TickCounter.Reset();
m_ServerRunning = true; m_ServerRunning = true;
startThread(); StartThread();
return true; return true;
} }
void Server::clean() { void Server::Clean() {
m_Listener.close(); m_Listener.Close();
m_Listener.destroy(); m_Listener.Destroy();
m_Connections.clear(); m_Connections.clear();
getPlayers().clear(); GetPlayers().clear();
std::cout << "Server successfully stopped !\n"; utils::LOG("Server successfully stopped !");
} }
void Server::stop() { void Server::Stop() {
if (!m_ServerRunning) if (!m_ServerRunning)
return; return;
protocol::DisconnectPacket packet("Server closed"); protocol::DisconnectPacket packet("Server closed");
broadcastPacket(&packet); BroadcastPacket(&packet);
stopThread(); StopThread();
} }
void Server::tick(std::uint64_t delta) { void Server::Tick(std::uint64_t delta) {
accept(); Accept();
updateSockets(); UpdateSockets();
m_Lobby.tick(); m_Lobby.Tick();
m_Game.tick(delta); m_Game.Tick(delta);
if (m_TickCounter.update()) { if (m_TickCounter.Update()) {
protocol::ServerTpsPacket packet(m_TickCounter.getTPS(), utils::getTime()); protocol::ServerTpsPacket packet(m_TickCounter.GetTPS(), m_TickCounter.GetMSPT(), utils::GetTime());
broadcastPacket(&packet); BroadcastPacket(&packet);
} }
} }
void Server::accept() { void Server::Accept() {
static std::uint8_t newPlayerID = 0; static std::uint8_t newPlayerID = 0;
network::TCPSocket newSocket; network::TCPSocket newSocket;
if (m_Listener.accept(newSocket)) { if (m_Listener.Accept(newSocket)) {
ServerConnexion con(newSocket, newPlayerID); ServerConnexion con(newSocket, newPlayerID);
m_Connections.insert(std::move(ConnexionMap::value_type{ newPlayerID, std::move(con) })); m_Connections.insert(std::move(ConnexionMap::value_type{ newPlayerID, std::move(con) }));
OnPlayerJoin(newPlayerID); OnPlayerJoin(newPlayerID);
m_Connections[newPlayerID].setServer(this); m_Connections[newPlayerID].SetServer(this);
newPlayerID++; newPlayerID++;
} }
} }
void Server::updateSockets() { void Server::UpdateSockets() {
std::int16_t closedConnexionID = -1; std::int16_t closedConnexionID = -1;
for (auto& connection : m_Connections) { for (auto& connection : m_Connections) {
ServerConnexion& con = connection.second; ServerConnexion& con = connection.second;
if (con.getSocketStatus() != network::Socket::Status::Connected) { if (con.GetSocketStatus() != network::Socket::Status::Connected) {
closedConnexionID = connection.first; closedConnexionID = connection.first;
} else { } else {
con.updateSocket(); con.UpdateSocket();
} }
} }
if (closedConnexionID != -1) { if (closedConnexionID != -1) {
removeConnexion(closedConnexionID); RemoveConnexion(closedConnexionID);
} }
} }
void Server::broadcastPacket(const protocol::Packet* packet) { void Server::BroadcastPacket(const protocol::Packet* packet) {
for (auto& connection : m_Connections) { for (auto& connection : m_Connections) {
ServerConnexion& con = connection.second; ServerConnexion& con = connection.second;
con.sendPacket(packet); con.SendPacket(packet);
} }
} }
void Server::removeConnexion(std::uint8_t connexionID) { void Server::RemoveConnexion(std::uint8_t connexionID) {
getPlayers().erase(getPlayers().find(connexionID)); GetPlayers().erase(GetPlayers().find(connexionID));
m_Connections.erase(connexionID); m_Connections.erase(connexionID);
m_Lobby.OnPlayerLeave(connexionID); m_Lobby.OnPlayerLeave(connexionID);
OnPlayerLeave(connexionID); OnPlayerLeave(connexionID);
} }
void Server::OnPlayerJoin(std::uint8_t id) { void Server::OnPlayerJoin(std::uint8_t id) {
m_Lobby.OnPlayerJoin(id); m_Lobby.OnPlayerJoin(id);
getPlayers().insert({ id, game::Player{id} }); GetPlayers().insert({ id, game::Player{id} });
} }
void Server::OnPlayerLeave(std::uint8_t id) { void Server::OnPlayerLeave(std::uint8_t id) {
protocol::PlayerLeavePacket packet(id); protocol::PlayerLeavePacket packet(id);
broadcastPacket(&packet); BroadcastPacket(&packet);
} }
} // namespace server } // namespace server

View File

@@ -10,11 +10,13 @@
#define KEEP_ALIVE_TIMEOUT 10 * 1000 // 10s #define KEEP_ALIVE_TIMEOUT 10 * 1000 // 10s
#define SAFE_CHECK(expr) if(expr) return
namespace td { namespace td {
namespace server { namespace server {
/* /*
NEVER TRUST USER INPUT NEVER TRUST USER INPUT
*/ */
@@ -23,174 +25,174 @@ ServerConnexion::ServerConnexion() : m_Player(0) {
} }
ServerConnexion::ServerConnexion(network::TCPSocket& socket, std::uint8_t id) : Connexion::Connexion(&m_Dispatcher, socket), m_ID(id), m_Player(0) { ServerConnexion::ServerConnexion(network::TCPSocket& socket, std::uint8_t id) : Connexion::Connexion(&m_Dispatcher, socket), m_ID(id), m_Player(0) {
Connexion::updateSocket(); Connexion::UpdateSocket();
} }
ServerConnexion::ServerConnexion(ServerConnexion&& move) : Connexion::Connexion(std::move(move)), m_Server(move.m_Server), ServerConnexion::ServerConnexion(ServerConnexion&& move) : Connexion::Connexion(std::move(move)), m_Server(move.m_Server),
m_ID(move.m_ID), m_KeepAlive(move.m_KeepAlive), m_Player(move.m_Player) { m_ID(move.m_ID), m_KeepAlive(move.m_KeepAlive), m_Player(move.m_Player) {
move.m_Server = nullptr; move.m_Server = nullptr;
registerHandlers(); RegisterHandlers();
} }
void ServerConnexion::registerHandlers() { void ServerConnexion::RegisterHandlers() {
GetDispatcher()->RegisterHandler(protocol::PacketType::PlayerLogin, this); GetDispatcher()->RegisterHandler(protocol::PacketType::PlayerLogin, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::KeepAlive, this); GetDispatcher()->RegisterHandler(protocol::PacketType::KeepAlive, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::SelectTeam, this); GetDispatcher()->RegisterHandler(protocol::PacketType::SelectTeam, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::Disconnect, this); GetDispatcher()->RegisterHandler(protocol::PacketType::Disconnect, this);
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); GetDispatcher()->RegisterHandler(protocol::PacketType::RemoveTower, this);
} }
bool ServerConnexion::updateSocket() { bool ServerConnexion::UpdateSocket() {
checkKeepAlive(); CheckKeepAlive();
return Connexion::updateSocket(); return Connexion::UpdateSocket();
} }
void ServerConnexion::checkKeepAlive() { void ServerConnexion::CheckKeepAlive() {
std::uint64_t time = utils::getTime(); std::uint64_t time = utils::GetTime();
if (time - m_KeepAlive.sendTime > KEEP_ALIVE_TIMEOUT) { if (time - m_KeepAlive.sendTime > KEEP_ALIVE_TIMEOUT) {
if (m_KeepAlive.recievedResponse) { if (m_KeepAlive.recievedResponse) {
sendKeepAlive(); SendKeepAlive();
} else { } else {
protocol::DisconnectPacket packet("Time out"); protocol::DisconnectPacket packet("Time out");
sendPacket(&packet); SendPacket(&packet);
closeConnection(); CloseConnection();
} }
} }
} }
void ServerConnexion::sendKeepAlive() { void ServerConnexion::SendKeepAlive() {
m_KeepAlive.keepAliveID = utils::getRandomInt<std::uint64_t>(0, RAND_MAX); m_KeepAlive.keepAliveID = utils::GetRandomInt<std::uint64_t>(0, RAND_MAX);
m_KeepAlive.recievedResponse = false; m_KeepAlive.recievedResponse = false;
protocol::KeepAlivePacket keepAlivePacket(m_KeepAlive.keepAliveID); protocol::KeepAlivePacket keepAlivePacket(m_KeepAlive.keepAliveID);
sendPacket(&keepAlivePacket); SendPacket(&keepAlivePacket);
std::uint64_t time = utils::getTime(); std::uint64_t time = utils::GetTime();
m_KeepAlive.sendTime = time; m_KeepAlive.sendTime = time;
} }
void ServerConnexion::HandlePacket(const protocol::PlayerLoginPacket* packet) { void ServerConnexion::HandlePacket(const protocol::PlayerLoginPacket* packet) {
if (m_Player->getName().empty() && !packet->getPlayerName().empty()) { if (m_Player->GetName().empty() && !packet->GetPlayerName().empty()) {
m_Player->setName(packet->getPlayerName()); m_Player->SetName(packet->GetPlayerName());
protocol::PlayerJoinPacket joinPacket(m_ID, m_Player->getName()); protocol::PlayerJoinPacket joinPacket(m_ID, m_Player->GetName());
m_Server->broadcastPacket(&joinPacket); m_Server->BroadcastPacket(&joinPacket);
std::map<std::uint8_t, protocol::PlayerInfo> playerNames; std::map<std::uint8_t, protocol::PlayerInfo> playerNames;
for (const auto& pair : m_Server->getPlayers()) { for (const auto& pair : m_Server->GetPlayers()) {
const game::Player& player = pair.second; const game::Player& player = pair.second;
if (!player.getName().empty()) { if (!player.GetName().empty()) {
protocol::PlayerInfo playerInfo; protocol::PlayerInfo playerInfo;
playerInfo.name = player.getName(); playerInfo.name = player.GetName();
playerInfo.team = player.getTeamColor(); playerInfo.team = player.GetTeamColor();
playerNames.insert({ player.getID(), playerInfo }); playerNames.insert({ player.GetID(), playerInfo });
} }
} }
protocol::PlayerListPacket listPacket(playerNames); protocol::PlayerListPacket listPacket(playerNames);
sendPacket(&listPacket); SendPacket(&listPacket);
} }
} }
void ServerConnexion::HandlePacket(const protocol::SelectTeamPacket* packet) { void ServerConnexion::HandlePacket(const protocol::SelectTeamPacket* packet) {
if (m_Server->getGame().getGameState() != game::GameState::Lobby) SAFE_CHECK(m_Server->GetGame().GetGameState() != game::GameState::Lobby);
return;
if ((std::int8_t)packet->getSelectedTeam() >= -1 || (std::int8_t)packet->getSelectedTeam() <= 1) { if (static_cast<std::int8_t>(packet->GetSelectedTeam()) >= -1 || static_cast<std::int8_t>(packet->GetSelectedTeam()) <= 1) {
if (m_Player->getTeamColor() == game::TeamColor::None) { // join a team if (m_Player->GetTeamColor() == game::TeamColor::None) { // join a team
m_Server->getGame().getTeam(packet->getSelectedTeam()).addPlayer(m_Player); m_Server->GetGame().GetTeam(packet->GetSelectedTeam()).AddPlayer(m_Player);
} else if (packet->getSelectedTeam() == game::TeamColor::None) { // leave a team } else if (packet->GetSelectedTeam() == game::TeamColor::None) { // leave a team
m_Server->getGame().getTeam(m_Player->getTeamColor()).removePlayer(m_Player); m_Server->GetGame().GetTeam(m_Player->GetTeamColor()).RemovePlayer(m_Player);
m_Player->setTeamColor(game::TeamColor::None); m_Player->SetTeamColor(game::TeamColor::None);
} else { // change team } else { // change team
m_Server->getGame().getTeam(m_Player->getTeamColor()).removePlayer(m_Player); m_Server->GetGame().GetTeam(m_Player->GetTeamColor()).RemovePlayer(m_Player);
m_Server->getGame().getTeam(packet->getSelectedTeam()).addPlayer(m_Player); m_Server->GetGame().GetTeam(packet->GetSelectedTeam()).AddPlayer(m_Player);
} }
m_Player->setTeamColor(packet->getSelectedTeam()); m_Player->SetTeamColor(packet->GetSelectedTeam());
protocol::UpdatePlayerTeamPacket updateTeamPacket(m_ID, packet->getSelectedTeam()); protocol::UpdatePlayerTeamPacket updateTeamPacket(m_ID, packet->GetSelectedTeam());
m_Server->broadcastPacket(&updateTeamPacket); m_Server->BroadcastPacket(&updateTeamPacket);
} }
} }
void ServerConnexion::HandlePacket(const protocol::KeepAlivePacket* packet) { void ServerConnexion::HandlePacket(const protocol::KeepAlivePacket* packet) {
if (packet->getAliveID() == m_KeepAlive.keepAliveID) if (packet->GetAliveID() == m_KeepAlive.keepAliveID)
m_KeepAlive.recievedResponse = true; m_KeepAlive.recievedResponse = true;
} }
void ServerConnexion::HandlePacket(const protocol::DisconnectPacket* packet) { void ServerConnexion::HandlePacket(const protocol::DisconnectPacket* packet) {
closeConnection(); CloseConnection();
} }
void ServerConnexion::setServer(Server* server) { void ServerConnexion::SetServer(Server* server) {
m_Server = server; m_Server = server;
m_Player = &m_Server->getPlayers().at(m_ID); m_Player = &m_Server->GetPlayers().at(m_ID);
initConnection(); InitConnection();
sendKeepAlive(); SendKeepAlive();
} }
void ServerConnexion::initConnection() { void ServerConnexion::InitConnection() {
protocol::UpdateGameStatePacket statePacket(m_Server->getGame().getGameState()); protocol::UpdateGameStatePacket statePacket(m_Server->GetGame().GetGameState());
sendPacket(&statePacket); SendPacket(&statePacket);
protocol::ConnexionInfoPacket conPacket(m_ID); protocol::ConnexionInfoPacket conPacket(m_ID);
sendPacket(&conPacket); SendPacket(&conPacket);
if (m_Server->getGame().getGameState() == game::GameState::Game) { SAFE_CHECK(m_Server->GetGame().GetGameState() != game::GameState::Game);
protocol::WorldBeginDataPacket headerDataPacket(m_Server->getGame().getWorld());
protocol::WorldBeginDataPacket dataPacket(m_Server->getGame().getWorld()); protocol::WorldBeginDataPacket headerDataPacket(m_Server->GetGame().GetWorld());
sendPacket(&headerDataPacket); protocol::WorldBeginDataPacket dataPacket(m_Server->GetGame().GetWorld());
sendPacket(&dataPacket); SendPacket(&headerDataPacket);
} SendPacket(&dataPacket);
} }
void ServerConnexion::HandlePacket(const protocol::PlaceTowerPacket* packet) { void ServerConnexion::HandlePacket(const protocol::PlaceTowerPacket* packet) {
game::TowerType towerType = packet->getTowerType(); game::TowerType towerType = packet->GetTowerType();
const game::TowerInfo& towerInfo = game::getTowerInfo(towerType); const game::TowerInfo& towerInfo = game::GetTowerInfo(towerType);
server::ServerWorld* world = m_Server->getGame().getServerWorld(); server::ServerWorld* world = m_Server->GetGame().GetServerWorld();
if (!world->CanPlaceLittleTower({ packet->getTowerX(), packet->getTowerY() }, m_ID)) Vec2f towerPos = { static_cast<float>(packet->GetTowerX()), static_cast<float>(packet->GetTowerY()) };
return;
if (towerInfo.isBigTower()) SAFE_CHECK(!world->CanPlaceLittleTower(towerPos, m_ID));
if (!world->CanPlaceBigTower({ packet->getTowerX(), packet->getTowerY() }, m_ID))
return;
game::TowerPtr tower = world->placeTowerAt(towerType, packet->getTowerX(), packet->getTowerY(), m_ID); if (towerInfo.IsBigTower())
SAFE_CHECK(!world->CanPlaceBigTower(towerPos, m_ID));
world->getWorldNotifier().notifyListeners(&game::WorldListener::OnTowerAdd, tower); game::TowerPtr tower = world->PlaceTowerAt(towerType, packet->GetTowerX(), packet->GetTowerY(), m_ID);
protocol::WorldAddTowerPacket addTowerPacket(tower->getID(), packet->getTowerX(), packet->getTowerY(), packet->getTowerType(), m_ID); world->GetWorldNotifier().NotifyListeners(&game::WorldListener::OnTowerAdd, tower);
m_Server->broadcastPacket(&addTowerPacket);
protocol::WorldAddTowerPacket addTowerPacket(tower->GetID(), packet->GetTowerX(), packet->GetTowerY(), packet->GetTowerType(), m_ID);
m_Server->BroadcastPacket(&addTowerPacket);
} }
void ServerConnexion::HandlePacket(const protocol::SendMobsPacket* packet) { void ServerConnexion::HandlePacket(const protocol::SendMobsPacket* packet) {
const std::vector<protocol::MobSend>& mobSent = packet->getMobSends(); const std::vector<protocol::MobSend>& mobSent = packet->GetMobSends();
//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 //TODO: verify the packet
m_Server->broadcastPacket(packet); m_Server->BroadcastPacket(packet);
} }
void ServerConnexion::HandlePacket(const protocol::RemoveTowerPacket* packet) { void ServerConnexion::HandlePacket(const protocol::RemoveTowerPacket* packet) {
//TODO: verify the packet //TODO: verify the packet
m_Server->broadcastPacket(packet); m_Server->BroadcastPacket(packet);
} }
ServerConnexion::~ServerConnexion() { ServerConnexion::~ServerConnexion() {
if (GetDispatcher() != nullptr) if (GetDispatcher() != nullptr)
GetDispatcher()->UnregisterHandler(this); GetDispatcher()->UnregisterHandler(this);
} }
} // namespace server } // namespace server

View File

@@ -5,111 +5,116 @@ namespace td {
namespace server { namespace server {
ServerGame::ServerGame(server::Server* server) : game::Game(&m_ServerWorld), m_Server(server), m_ServerWorld(server, this), ServerGame::ServerGame(server::Server* server) : game::Game(&m_ServerWorld), m_Server(server), m_ServerWorld(server, this),
m_GoldMineTimer{ 1000, std::bind(&ServerGame::updateGoldMines, this) }, m_GoldMineTimer{ 1000, std::bind(&ServerGame::UpdateGoldMines, this) },
m_MobStatesTimer{ 5000, std::bind(&ServerGame::updateMobStates, this) }, m_MobStatesTimer{ 5000, std::bind(&ServerGame::UpdateMobStates, this) },
m_EndGameCooldown{ 1000 * 10 } { m_EndGameCooldown{ 1000 * 10 } {
bindListener(this); BindListener(this);
} }
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);
m_MobStatesTimer.update(delta); m_MobStatesTimer.Update(delta);
updatePlayerStats(); UpdatePlayerStats();
} else if (m_GameState == game::GameState::EndGame) { } else if (m_GameState == game::GameState::EndGame) {
if (m_EndGameCooldown.update(delta)) { if (m_EndGameCooldown.Update(delta)) {
notifyListeners(&game::GameListener::OnGameClose); NotifyListeners(&game::GameListener::OnGameClose);
} }
} }
} }
void ServerGame::startGame() { void ServerGame::StartGame() {
balanceTeams(); BalanceTeams();
protocol::WorldBeginDataPacket headerMapData(m_World); protocol::WorldBeginDataPacket headerMapData(m_World);
m_Server->broadcastPacket(&headerMapData); m_Server->BroadcastPacket(&headerMapData);
protocol::WorldDataPacket mapData(m_World); protocol::WorldDataPacket mapData(m_World);
m_Server->broadcastPacket(&mapData); m_Server->BroadcastPacket(&mapData);
m_GameState = game::GameState::Game; InitPlayerStats();
m_GameState = game::GameState::Game;
} }
void ServerGame::updatePlayerStats() { void ServerGame::InitPlayerStats() {
m_GoldMineTimer.update(); static const unsigned int START_GOLD = 100;
for (auto& pair : m_Server->getPlayers()) { static const unsigned int START_EXP = 0;
game::Player& player = pair.second; for (auto& [id, player] : m_Server->GetPlayers()) {
if (player.hasGoldChanged()) { player.SetGold(START_GOLD);
protocol::UpdateMoneyPacket packet(player.getGold()); player.SetExp(START_EXP);
m_Server->getConnexions()[player.getID()].sendPacket(&packet); player.getUpgrades().SetGoldPerSecond(5);
player.updateGold(); }
}
if (player.hasExpChanged()) {
protocol::UpdateExpPacket packet(player.getExp());
m_Server->getConnexions()[player.getID()].sendPacket(&packet);
player.updateExp();
}
}
} }
void ServerGame::updateGoldMines() { void ServerGame::UpdatePlayerStats() {
for (auto& pair : m_Server->getPlayers()) { m_GoldMineTimer.Update();
game::Player* player = &pair.second;
player->addGold(player->getGoldPerSecond());
}
} }
void ServerGame::updateMobStates() { void ServerGame::UpdateGoldMines() {
protocol::UpdateMobStatesPacket packet; for (auto& [id, player] : m_Server->GetPlayers()) {
for (auto mob : m_World->getMobList()) { player.AddGold(player.getUpgrades().GetGoldPerSecond());
packet.addMobState({ mob->getMobID(), mob->getCenter(), mob->getHealth(), mob->getDirection() });
} // Update player money and exp every second
m_Server->broadcastPacket(&packet); protocol::UpdateMoneyPacket moneyPacket(player.GetGold());
m_Server->GetConnexions()[player.GetID()].SendPacket(&moneyPacket);
protocol::UpdateExpPacket expPacket(player.GetExp());
m_Server->GetConnexions()[player.GetID()].SendPacket(&expPacket);
}
} }
void ServerGame::balanceTeams() { void ServerGame::UpdateMobStates() {
for (auto& playerInfo : Game::m_Players) { protocol::UpdateMobStatesPacket packet;
game::Player& player = playerInfo.second; for (auto mob : m_World->GetMobList()) {
if (player.getTeamColor() == game::TeamColor::None) { packet.addMobState({ mob->GetMobID(), mob->GetCenter(), mob->GetHealth(), mob->GetDirection() });
game::Team& redTeam = getRedTeam(); }
game::Team& blueTeam = getBlueTeam(); m_Server->BroadcastPacket(&packet);
if (blueTeam.getPlayerCount() > redTeam.getPlayerCount()) { }
player.setTeamColor(game::TeamColor::Red);
redTeam.addPlayer(&player); void ServerGame::BalanceTeams() {
} else { for (auto& playerInfo : Game::m_Players) {
player.setTeamColor(game::TeamColor::Blue); game::Player& player = playerInfo.second;
blueTeam.addPlayer(&player); if (player.GetTeamColor() == game::TeamColor::None) {
} game::Team& redTeam = GetRedTeam();
protocol::UpdatePlayerTeamPacket packet(player.getID(), player.getTeamColor()); game::Team& blueTeam = GetBlueTeam();
m_Server->broadcastPacket(&packet); if (blueTeam.GetPlayerCount() > redTeam.GetPlayerCount()) {
} player.SetTeamColor(game::TeamColor::Red);
} redTeam.AddPlayer(&player);
} else {
player.SetTeamColor(game::TeamColor::Blue);
blueTeam.AddPlayer(&player);
}
protocol::UpdatePlayerTeamPacket packet(player.GetID(), player.GetTeamColor());
m_Server->BroadcastPacket(&packet);
}
}
} }
void ServerGame::OnGameStateUpdate(game::GameState newState) { void ServerGame::OnGameStateUpdate(game::GameState newState) {
setGameState(newState); SetGameState(newState);
protocol::UpdateGameStatePacket packet(newState); protocol::UpdateGameStatePacket packet(newState);
m_Server->broadcastPacket(&packet); m_Server->BroadcastPacket(&packet);
} }
void ServerGame::OnGameBegin() { void ServerGame::OnGameBegin() {
notifyListeners(&game::GameListener::OnGameStateUpdate, game::GameState::Game); NotifyListeners(&game::GameListener::OnGameStateUpdate, game::GameState::Game);
startGame(); StartGame();
} }
void ServerGame::OnGameEnd() { void ServerGame::OnGameEnd() {
notifyListeners(&game::GameListener::OnGameStateUpdate, game::GameState::EndGame); NotifyListeners(&game::GameListener::OnGameStateUpdate, game::GameState::EndGame);
m_EndGameCooldown.applyCooldown(); m_EndGameCooldown.ApplyCooldown();
} }
void ServerGame::OnGameClose() { void ServerGame::OnGameClose() {
notifyListeners(&game::GameListener::OnGameStateUpdate, game::GameState::Closed); NotifyListeners(&game::GameListener::OnGameStateUpdate, game::GameState::Closed);
// Disconnect clients // Disconnect clients
protocol::DisconnectPacket packet("Game finished"); protocol::DisconnectPacket packet("Game finished");
m_Server->broadcastPacket(&packet); m_Server->BroadcastPacket(&packet);
// Closing server // Closing server
m_Server->close(); m_Server->Close();
} }
} // namespace game } // namespace game

View File

@@ -11,67 +11,67 @@ ServerWorld::ServerWorld(Server* server, ServerGame* game) : game::World(game),
} }
void ServerWorld::spawnMobs(game::MobType type, std::uint8_t level, game::PlayerID sender, std::uint8_t count) { void ServerWorld::SpawnMobs(game::MobType type, std::uint8_t level, game::PlayerID sender, std::uint8_t count) {
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
game::TeamColor senderTeam = m_Game->getPlayers().at(sender).getTeamColor(); game::TeamColor senderTeam = m_Game->GetPlayers().at(sender).GetTeamColor();
game::Spawn* enemyMobSpawn; game::Spawn* enemyMobSpawn;
if (senderTeam == game::TeamColor::Red) { if (senderTeam == game::TeamColor::Red) {
enemyMobSpawn = &getTeam(game::TeamColor::Blue).getSpawn(); enemyMobSpawn = &GetTeam(game::TeamColor::Blue).GetSpawn();
} else { } else {
enemyMobSpawn = &getTeam(game::TeamColor::Red).getSpawn(); enemyMobSpawn = &GetTeam(game::TeamColor::Red).GetSpawn();
} }
float spawnWidth = enemyMobSpawn->getWidth(); float spawnWidth = enemyMobSpawn->GetWidth();
float spawnHeight = enemyMobSpawn->getHeight(); float spawnHeight = enemyMobSpawn->GetHeight();
float spawnCenterX = enemyMobSpawn->getCenterX(); float spawnCenterX = enemyMobSpawn->GetCenterX();
float spawnCenterY = enemyMobSpawn->getCenterY(); float spawnCenterY = enemyMobSpawn->GetCenterY();
auto mobStats = getMobStats(type, level); auto mobStats = GetMobStats(type, level);
auto mobSize = mobStats->getSize(); auto mobSize = mobStats->GetSize();
float minSpawnX = spawnCenterX - spawnWidth / 2.0f + mobSize.x / 2.0f; float minSpawnX = spawnCenterX - spawnWidth / 2.0f + mobSize.x / 2.0f;
float maxSpawnX = 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 minSpawnY = spawnCenterY - spawnHeight / 2.0f + mobSize.y / 2.0f;
float maxSpawnY = spawnCenterY + spawnHeight / 2.0f - mobSize.y / 2.0f; float maxSpawnY = spawnCenterY + spawnHeight / 2.0f - mobSize.y / 2.0f;
float mobX = utils::getRandomReal<float>(minSpawnX + MobSpawnBorder, maxSpawnX - MobSpawnBorder); float mobX = utils::GetRandomReal<float>(minSpawnX + MobSpawnBorder, maxSpawnX - MobSpawnBorder);
float mobY = utils::getRandomReal<float>(minSpawnY + MobSpawnBorder, maxSpawnY - MobSpawnBorder); float mobY = utils::GetRandomReal<float>(minSpawnY + MobSpawnBorder, maxSpawnY - MobSpawnBorder);
spawnMobAt(m_CurrentMobID, type, level, sender, mobX, mobY, enemyMobSpawn->getDirection()); SpawnMobAt(m_CurrentMobID, type, level, sender, mobX, mobY, enemyMobSpawn->GetDirection());
protocol::SpawnMobPacket packet(m_CurrentMobID, type, level, sender, mobX, mobY, enemyMobSpawn->getDirection()); protocol::SpawnMobPacket packet(m_CurrentMobID, type, level, sender, mobX, mobY, enemyMobSpawn->GetDirection());
m_Server->broadcastPacket(&packet); m_Server->BroadcastPacket(&packet);
m_CurrentMobID++; m_CurrentMobID++;
} }
} }
game::TowerPtr ServerWorld::placeTowerAt(game::TowerType type, std::int32_t x, std::int32_t y, game::PlayerID builder) { game::TowerPtr ServerWorld::PlaceTowerAt(game::TowerType type, std::int32_t x, std::int32_t y, game::PlayerID builder) {
game::TowerPtr tower = World::placeTowerAt(m_CurrentTowerID, type, x, y, builder); game::TowerPtr tower = World::PlaceTowerAt(m_CurrentTowerID, type, x, y, builder);
m_CurrentTowerID++; m_CurrentTowerID++;
return tower; return tower;
} }
void ServerWorld::OnMobDie(game::Mob* mob) { void ServerWorld::OnMobDie(game::Mob* mob) {
if (mob->OnDeath(this)) { // check if the mob is actually dead (slimes ...) if (mob->OnDeath(this)) { // check if the mob is actually dead (slimes ...)
//reward players //reward players
game::Player* sender = m_Game->getPlayerById(mob->getSender()); game::Player* sender = m_Game->GetPlayerById(mob->GetSender());
sender->addExp(mob->getStats()->getExpReward()); sender->AddExp(mob->GetStats()->GetExpReward());
game::Player* killer = m_Game->getPlayerById(mob->getLastDamageTower()->getBuilder()); game::Player* killer = m_Game->GetPlayerById(mob->GetLastDamageTower()->GetBuilder());
killer->addGold(mob->getStats()->getMoneyCost()); killer->AddGold(mob->GetStats()->GetMoneyCost());
} }
} }
void ServerWorld::OnMobCastleDamage(game::Mob* damager, game::TeamCastle* enemyCastle, float damage) { void ServerWorld::OnMobCastleDamage(game::Mob* damager, game::TeamCastle* enemyCastle, float damage) {
// calling base class event // calling base class event
World::OnMobCastleDamage(damager, enemyCastle, damage); World::OnMobCastleDamage(damager, enemyCastle, damage);
protocol::UpdateCastleLifePacket packet(enemyCastle->getLife(), enemyCastle->getTeam()->getColor()); protocol::UpdateCastleLifePacket packet(enemyCastle->GetLife(), enemyCastle->GetTeam()->GetColor());
m_Server->broadcastPacket(&packet); m_Server->BroadcastPacket(&packet);
} }
} // namespace server } // namespace server

View File

@@ -0,0 +1,25 @@
#include "game/Towers.h"
#include "game/World.h"
namespace td {
namespace game {
void ArcherTower::Tick(std::uint64_t delta, World* world) {
if (m_Timer.Update(delta)) {
std::uint8_t arrowsShot = 0;
bool explosiveArrows = GetLevel().GetPath() == TowerPath::Bottom;
std::uint8_t arrows = explosiveArrows ? 2 : GetLevel().GetLevel();
for (MobPtr mob : world->GetMobList()) {
if (IsMobInRange(mob)) {
world->GetWorldNotifier().NotifyListeners(&WorldListener::OnArcherTowerShot, mob, this);
m_Timer.ApplyCooldown();
arrowsShot++;
if (arrowsShot >= arrows)
break;
}
}
}
}
} // namespace game
} // namespace td

View File

@@ -0,0 +1,12 @@
#include "game/Towers.h"
#include "game/World.h"
namespace td {
namespace game {
void ArtilleryTower::Tick(std::uint64_t delta, World* world) {
}
} // namespace game
} // namespace td

View File

@@ -0,0 +1,22 @@
#include "game/Towers.h"
#include "game/World.h"
namespace td {
namespace game {
void IceTower::Tick(std::uint64_t delta, World* world) {
if (m_Timer.Update(delta)) {
float damage = GetStats()->GetDamage();
for (MobPtr mob : world->GetMobList()) {
if (IsMobInRange(mob)) {
mob->AddEffect(EffectType::Slowness, 1, this); // slowness for 1s every second
if (damage > 0)
world->GetMobNotifier().NotifyListeners(&MobListener::OnMobDamage, mob.get(), damage, this);
m_Timer.ApplyCooldown();
}
}
}
}
} // namespace game
} // namespace td

View File

@@ -0,0 +1,12 @@
#include "game/Towers.h"
#include "game/World.h"
namespace td {
namespace game {
void LeachTower::Tick(std::uint64_t delta, World* world) {
}
} // namespace game
} // namespace td

View File

@@ -0,0 +1,19 @@
#include "game/Towers.h"
#include "game/World.h"
namespace td {
namespace game {
void MageTower::Tick(std::uint64_t delta, World* world) {
if (m_Timer.Update(delta)) {
for (MobPtr mob : world->GetMobList()) {
if (IsMobInRange(mob)) {
mob->AddEffect(EffectType::Fire, GetLevel().GetLevel() * 3, this);
m_Timer.ApplyCooldown();
}
}
}
}
} // namespace game
} // namespace td

View File

@@ -0,0 +1,12 @@
#include "game/Towers.h"
#include "game/World.h"
namespace td {
namespace game {
void NecromancerTower::Tick(std::uint64_t delta, World* world) {
}
} // namespace game
} // namespace td

View File

@@ -0,0 +1,45 @@
#include "game/Towers.h"
#include "game/World.h"
namespace td {
namespace game {
void PoisonTower::Tick(std::uint64_t delta, World* world) {
if (m_Timer.Update(delta)) {
for (MobPtr mob : world->GetMobList()) {
if (IsMobInRange(mob)) {
if (GetLevel().GetPath() == TowerPath::Bottom) {
world->GetMobNotifier().NotifyListeners(&MobListener::OnMobDamage, mob.get(), GetStats()->GetDamage(), this);
} else {
float durationSec;
switch (GetLevel().GetLevel()) {
case 1:
durationSec = 5;
break;
case 2:
durationSec = 15;
break;
case 3:
durationSec = 30;
break;
case 4:
durationSec = 1e10; // about 3 million hours. It should be enough
break;
default:
durationSec = 0; // how did we get there ?
break;
}
mob->AddEffect(EffectType::Poison, durationSec, this);
}
m_Timer.ApplyCooldown();
}
}
}
}
} // namespace game
} // namespace td

View File

@@ -0,0 +1,12 @@
#include "game/Towers.h"
#include "game/World.h"
namespace td {
namespace game {
void QuakeTower::Tick(std::uint64_t delta, World* world) {
}
} // namespace game
} // namespace td

View File

@@ -0,0 +1,12 @@
#include "game/Towers.h"
#include "game/World.h"
namespace td {
namespace game {
void SorcererTower::Tick(std::uint64_t delta, World* world) {
}
} // namespace game
} // namespace td

View File

@@ -0,0 +1,12 @@
#include "game/Towers.h"
#include "game/World.h"
namespace td {
namespace game {
void TurretTower::Tick(std::uint64_t delta, World* world) {
}
} // namespace game
} // namespace td

View File

@@ -0,0 +1,12 @@
#include "game/Towers.h"
#include "game/World.h"
namespace td {
namespace game {
void ZeusTower::Tick(std::uint64_t delta, World* world) {
}
} // namespace game
} // namespace td

View File

@@ -8,81 +8,80 @@
namespace td { namespace td {
namespace utils { namespace utils {
unsigned long inflate(const std::string& source, std::string& dest) { std::uint64_t Inflate(const std::string& source, std::string& dest) {
unsigned long size = dest.size(); uLongf size = dest.size();
uncompress((Bytef*)&dest[0], &size, (const Bytef*)source.c_str(), source.length()); uncompress(reinterpret_cast<Bytef*>(dest.data()), reinterpret_cast<uLongf*>(&size), reinterpret_cast<const Bytef*>(source.c_str()), source.length());
return size; return size;
} }
unsigned long deflate(const std::string& source, std::string& dest) { std::uint64_t Deflate(const std::string& source, std::string& dest) {
unsigned long size = source.length(); uLongf size = source.length();
dest.resize(size); dest.resize(source.size()); // Resize for the compressed data to fit into
compress(reinterpret_cast<Bytef*>(dest.data()), reinterpret_cast<uLongf*>(&size), reinterpret_cast<const Bytef*>(source.c_str()), source.length());
compress((Bytef*)&dest[0], &size, (const Bytef*)source.c_str(), source.length()); dest.resize(size); // Resize to cut useless data
dest.resize(size); return size;
return size;
} }
DataBuffer Compress(const DataBuffer& buffer) { DataBuffer Compress(const DataBuffer& buffer) {
std::string compressedData; std::string compressedData;
DataBuffer packet; DataBuffer packet;
if (buffer.GetSize() < COMPRESSION_THRESHOLD) { if (buffer.GetSize() < COMPRESSION_THRESHOLD) {
// Don't compress since it's a small packet // Don't compress since it's a small packet
std::uint64_t dataLength = 0; std::uint64_t dataLength = 0;
std::uint64_t packetLength = buffer.GetSize() + sizeof(dataLength); std::uint64_t packetLength = buffer.GetSize() + sizeof(dataLength);
packet << packetLength; packet << packetLength;
packet << dataLength; packet << dataLength;
packet << buffer; packet << buffer;
return packet; return packet;
} }
deflate(buffer.ToString(), compressedData); Deflate(buffer.ToString(), compressedData);
std::uint64_t dataLength = buffer.GetSize(); std::uint64_t dataLength = buffer.GetSize();
std::uint64_t packetLength = compressedData.length() + sizeof(dataLength); std::uint64_t packetLength = compressedData.length() + sizeof(dataLength);
packet << packetLength; packet << packetLength;
packet << dataLength; packet << dataLength;
packet << compressedData; packet << compressedData;
return packet; return packet;
} }
DataBuffer Decompress(DataBuffer& buffer, std::uint64_t packetLength) { DataBuffer Decompress(DataBuffer& buffer, std::uint64_t packetLength) {
std::uint64_t uncompressedLength; std::uint64_t uncompressedLength;
buffer >> uncompressedLength; buffer >> uncompressedLength;
std::uint64_t compressedLength = packetLength - sizeof(uncompressedLength); std::uint64_t compressedLength = packetLength - sizeof(uncompressedLength);
if (uncompressedLength == 0) { if (uncompressedLength == 0) {
// Uncompressed // Uncompressed
DataBuffer ret; DataBuffer ret;
buffer.ReadSome(ret, compressedLength); buffer.ReadSome(ret, compressedLength);
return ret; return ret;
} }
assert(buffer.GetReadOffset() + compressedLength <= buffer.GetSize()); assert(buffer.GetReadOffset() + compressedLength <= buffer.GetSize());
std::string deflatedData; std::string deflatedData;
buffer.ReadSome(deflatedData, compressedLength); buffer.ReadSome(deflatedData, compressedLength);
std::string inflated; std::string inflated;
inflated.resize(uncompressedLength); inflated.resize(uncompressedLength);
inflate(deflatedData, inflated); Inflate(deflatedData, inflated);
assert(inflated.length() == uncompressedLength); assert(inflated.length() == uncompressedLength);
return DataBuffer(inflated); return DataBuffer(inflated);
} }
DataBuffer Decompress(DataBuffer& buffer) { DataBuffer Decompress(DataBuffer& buffer) {
std::uint64_t packetLength; std::uint64_t packetLength;
buffer >> packetLength; buffer >> packetLength;
return Decompress(buffer, packetLength); return Decompress(buffer, packetLength);
} }
} // namespace utils } // namespace utils

View File

@@ -7,87 +7,88 @@
namespace td { namespace td {
DataBuffer::DataBuffer() { } DataBuffer::DataBuffer() : m_ReadOffset(0) {}
DataBuffer::DataBuffer(const DataBuffer& other) : m_Buffer(other.m_Buffer), m_ReadOffset(other.m_ReadOffset) { } DataBuffer::DataBuffer(const DataBuffer& other) : m_Buffer(other.m_Buffer), m_ReadOffset(other.m_ReadOffset) {}
DataBuffer::DataBuffer(DataBuffer&& other) : m_Buffer(std::move(other.m_Buffer)), m_ReadOffset(std::move(other.m_ReadOffset)) { } DataBuffer::DataBuffer(DataBuffer&& other) : m_Buffer(std::move(other.m_Buffer)), m_ReadOffset(std::move(other.m_ReadOffset)) {}
DataBuffer::DataBuffer(const std::string& str) : m_Buffer(str.begin(), str.end()) { } DataBuffer::DataBuffer(const std::string& str) : m_Buffer(str.begin(), str.end()), m_ReadOffset(0) {}
DataBuffer::DataBuffer(const DataBuffer& other, std::size_t offset) {
m_Buffer.reserve(other.GetSize() - offset); DataBuffer::DataBuffer(const DataBuffer& other, Data::difference_type offset) : m_ReadOffset(0) {
std::copy(other.m_Buffer.begin() + offset, other.m_Buffer.end(), std::back_inserter(m_Buffer)); m_Buffer.reserve(other.GetSize() - static_cast<std::size_t>(offset));
std::copy(other.m_Buffer.begin() + offset, other.m_Buffer.end(), std::back_inserter(m_Buffer));
} }
DataBuffer& DataBuffer::operator=(const DataBuffer& other) { DataBuffer& DataBuffer::operator=(const DataBuffer& other) {
m_Buffer = other.m_Buffer; m_Buffer = other.m_Buffer;
m_ReadOffset = other.m_ReadOffset; m_ReadOffset = other.m_ReadOffset;
return *this; return *this;
} }
DataBuffer& DataBuffer::operator=(DataBuffer&& other) { DataBuffer& DataBuffer::operator=(DataBuffer&& other) {
m_Buffer = std::move(other.m_Buffer); m_Buffer = std::move(other.m_Buffer);
m_ReadOffset = std::move(other.m_ReadOffset); m_ReadOffset = std::move(other.m_ReadOffset);
return *this; return *this;
} }
void DataBuffer::SetReadOffset(std::size_t pos) { void DataBuffer::SetReadOffset(std::size_t pos) {
assert(pos <= GetSize()); assert(pos <= GetSize());
m_ReadOffset = pos; m_ReadOffset = pos;
} }
std::string DataBuffer::ToString() const { std::string DataBuffer::ToString() const {
return std::string(m_Buffer.begin(), m_Buffer.end()); return std::string(m_Buffer.begin(), m_Buffer.end());
} }
std::size_t DataBuffer::GetSize() const { return m_Buffer.size(); } std::size_t DataBuffer::GetSize() const { return m_Buffer.size(); }
bool DataBuffer::IsEmpty() const { return m_Buffer.empty(); } bool DataBuffer::IsEmpty() const { return m_Buffer.empty(); }
std::size_t DataBuffer::GetRemaining() const { std::size_t DataBuffer::GetRemaining() const {
return m_Buffer.size() - m_ReadOffset; return m_Buffer.size() - m_ReadOffset;
} }
DataBuffer::iterator DataBuffer::begin() { DataBuffer::iterator DataBuffer::begin() {
return m_Buffer.begin(); return m_Buffer.begin();
} }
DataBuffer::iterator DataBuffer::end() { DataBuffer::iterator DataBuffer::end() {
return m_Buffer.end(); return m_Buffer.end();
} }
DataBuffer::const_iterator DataBuffer::begin() const { DataBuffer::const_iterator DataBuffer::begin() const {
return m_Buffer.begin(); return m_Buffer.begin();
} }
DataBuffer::const_iterator DataBuffer::end() const { DataBuffer::const_iterator DataBuffer::end() const {
return m_Buffer.end(); return m_Buffer.end();
} }
std::ostream& operator<<(std::ostream& os, const DataBuffer& buffer) { std::ostream& operator<<(std::ostream& os, const DataBuffer& buffer) {
for (unsigned char u : buffer) for (unsigned char u : buffer)
os << std::hex << std::setfill('0') << std::setw(2) << (int)u << " "; os << std::hex << std::setfill('0') << std::setw(2) << static_cast<int>(u) << " ";
os << std::dec; os << std::dec;
return os; return os;
} }
bool DataBuffer::ReadFile(const std::string& fileName) { bool DataBuffer::ReadFile(const std::string& fileName) {
try { try {
std::ifstream file(fileName, std::istream::binary); std::ifstream file(fileName, std::istream::binary);
std::ostringstream ss; std::ostringstream ss;
ss << file.rdbuf(); ss << file.rdbuf();
const std::string& s = ss.str(); const std::string& s = ss.str();
m_Buffer = DataBuffer::Data(s.begin(), s.end()); m_Buffer = DataBuffer::Data(s.begin(), s.end());
m_ReadOffset = 0; m_ReadOffset = 0;
} catch (std::exception& e) { } catch (std::exception& e) {
std::cerr << "Failed to read file \"" << fileName << "\" reason : " << e.what() << std::endl; std::cerr << "Failed to read file \"" << fileName << "\" reason : " << e.what() << std::endl;
return false; return false;
} }
return m_Buffer.size() > 0; return m_Buffer.size() > 0;
} }
bool DataBuffer::WriteFile(const std::string& fileName) { bool DataBuffer::WriteFile(const std::string& fileName) {
try { try {
std::ofstream file(fileName, std::ostream::binary); std::ofstream file(fileName, std::ostream::binary);
file.write((const char*)m_Buffer.data(), m_Buffer.size()); file.write(reinterpret_cast<const char*>(m_Buffer.data()), static_cast<std::streamsize>(m_Buffer.size()));
file.flush(); file.flush();
} catch (std::exception& e) { } catch (std::exception& e) {
std::cerr << "Failed to write file \"" << fileName << "\" reason : " << e.what() << std::endl; std::cerr << "Failed to write file \"" << fileName << "\" reason : " << e.what() << std::endl;
return false; return false;
} }
return true; return true;
} }
} // td } // td

View File

@@ -5,198 +5,200 @@
namespace td { namespace td {
namespace utils { namespace utils {
// Found at https://easings.net/
/* Sine functions */ /* Sine functions */
float easeInSine(float x) { float EaseInSine(float x) {
return 1.0f - std::cos((x * PI) / 2.0f); return 1.0f - std::cos((x * PI) / 2.0f);
} }
float easeOutSine(float x) { float EaseOutSine(float x) {
return std::sin((x * PI) / 2.0f); return std::sin((x * PI) / 2.0f);
} }
float easeInOutSine(float x) { float EaseInOutSine(float x) {
return -(std::cos(PI * x) - 1.0f) / 2.0f; return -(std::cos(PI * x) - 1.0f) / 2.0f;
} }
/* Cubic functions */ /* Cubic functions */
float easeInCubic(float x) { float EaseInCubic(float x) {
return x * easeInQuad(x); return x * EaseInQuad(x);
} }
float easeOutCubic(float x) { float EaseOutCubic(float x) {
return 1 - std::pow(1 - x, 3); return 1 - std::pow(1 - x, 3);
} }
float easeInOutCubic(float x) { float EaseInOutCubic(float x) {
return x < 0.5 ? 4 * easeInCubic(x) : 1 - std::pow(-2 * x + 2, 3) / 2.0f; return x < 0.5 ? 4 * EaseInCubic(x) : 1 - std::pow(-2 * x + 2, 3) / 2.0f;
} }
/* Quint functions */ /* Quint functions */
float easeInQuint(float x) { float EaseInQuint(float x) {
return x * easeInQuart(x); return x * EaseInQuart(x);
} }
float easeOutQuint(float x) { float EaseOutQuint(float x) {
return 1 - std::pow(1 - x, 5); return 1 - std::pow(1 - x, 5);
} }
float easeInOutQuint(float x) { float EaseInOutQuint(float x) {
return x < 0.5 ? 16 * easeInQuint(x) : 1 - std::pow(-2 * x + 2, 5) / 2.0f; return x < 0.5 ? 16 * EaseInQuint(x) : 1 - std::pow(-2 * x + 2, 5) / 2.0f;
} }
/* Circ functions */ /* Circ functions */
float easeInCirc(float x) { float EaseInCirc(float x) {
return 1 - std::sqrt(1 - std::pow(x, 2)); return 1 - std::sqrt(1 - std::pow(x, 2));
} }
float easeOutCirc(float x) { float EaseOutCirc(float x) {
return std::sqrt(1 - std::pow(x - 1, 2)); return std::sqrt(1 - std::pow(x - 1, 2));
} }
float easeInOutCirc(float x) { float EaseInOutCirc(float x) {
return x < 0.5 return x < 0.5
? (1 - std::sqrt(1 - std::pow(2 * x, 2))) / 2.0f ? (1 - std::sqrt(1 - std::pow(2 * x, 2))) / 2.0f
: (std::sqrt(1 - std::pow(-2 * x + 2, 2)) + 1) / 2.0f; : (std::sqrt(1 - std::pow(-2 * x + 2, 2)) + 1) / 2.0f;
} }
/* Elastic functions */ /* Elastic functions */
float easeInElastic(float x) { float EaseInElastic(float x) {
const float c4 = (2 * PI) / 3.0f; const float c4 = (2 * PI) / 3.0f;
return x == 0 return x == 0
? 0 ? 0
: x == 1 : x == 1
? 1 ? 1
: -std::pow(2, 10 * x - 10) * std::sin((x * 10 - 10.75) * c4); : -std::pow(2, 10 * x - 10) * std::sin((x * 10 - 10.75) * c4);
} }
float easeOutElastic(float x) { float EaseOutElastic(float x) {
const float c4 = (2 * PI) / 3.0f; const float c4 = (2 * PI) / 3.0f;
return x == 0 return x == 0
? 0 ? 0
: x == 1 : x == 1
? 1 ? 1
: std::pow(2, -10 * x) * std::sin((x * 10 - 0.75) * c4) + 1; : std::pow(2, -10 * x) * std::sin((x * 10 - 0.75) * c4) + 1;
} }
float easeInOutElastic(float x) { float EaseInOutElastic(float x) {
const float c5 = (2 * PI) / 4.5; const float c5 = (2 * PI) / 4.5;
return x == 0 return x == 0
? 0 ? 0
: x == 1 : x == 1
? 1 ? 1
: x < 0.5 : x < 0.5
? -(std::pow(2, 20 * x - 10) * std::sin((20 * x - 11.125) * c5)) / 2.0f ? -(std::pow(2, 20 * x - 10) * std::sin((20 * x - 11.125) * c5)) / 2.0f
: (std::pow(2, -20 * x + 10) * std::sin((20 * x - 11.125) * c5)) / 2.0f + 1; : (std::pow(2, -20 * x + 10) * std::sin((20 * x - 11.125) * c5)) / 2.0f + 1;
} }
/* Quad functions */ /* Quad functions */
float easeInQuad(float x) { float EaseInQuad(float x) {
return x * x; return x * x;
} }
float easeOutQuad(float x) { float EaseOutQuad(float x) {
return 1 - (1 - x) * (1 - x); return 1 - (1 - x) * (1 - x);
} }
float easeInOutQuad(float x) { float EaseInOutQuad(float x) {
return x < 0.5 ? 2 * x * x : 1 - std::pow(-2 * x + 2, 2) / 2.0f; return x < 0.5 ? 2 * x * x : 1 - std::pow(-2 * x + 2, 2) / 2.0f;
} }
/* Quart functions */ /* Quart functions */
float easeInQuart(float x) { float EaseInQuart(float x) {
return x * easeInCubic(x); return x * EaseInCubic(x);
} }
float easeOutQuart(float x) { float EaseOutQuart(float x) {
return 1 - std::pow(1 - x, 4); return 1 - std::pow(1 - x, 4);
} }
float easeInOutQuart(float x) { float EaseInOutQuart(float x) {
return x < 0.5 ? 8 * easeInQuart(x) : 1 - std::pow(-2 * x + 2, 4) / 2.0f; return x < 0.5 ? 8 * EaseInQuart(x) : 1 - std::pow(-2 * x + 2, 4) / 2.0f;
} }
/* Expo functions */ /* Expo functions */
float easeInExpo(float x) { float EaseInExpo(float x) {
return x == 0 ? 0 : std::pow(2, 10 * x - 10); return x == 0 ? 0 : std::pow(2, 10 * x - 10);
} }
float easeOutExpo(float x) { float EaseOutExpo(float x) {
return x == 1 ? 1 : 1 - std::pow(2, -10 * x); return x == 1 ? 1 : 1 - std::pow(2, -10 * x);
} }
float easeInOutExpo(float x) { float EaseInOutExpo(float x) {
return x == 0 return x == 0
? 0 ? 0
: x == 1 : x == 1
? 1 ? 1
: x < 0.5 ? std::pow(2, 20 * x - 10) / 2.0f : x < 0.5 ? std::pow(2, 20 * x - 10) / 2.0f
: (2 - std::pow(2, -20 * x + 10)) / 2.0f; : (2 - std::pow(2, -20 * x + 10)) / 2.0f;
} }
/* Back functions */ /* Back functions */
float easeInBack(float x) { float EaseInBack(float x) {
const float c1 = 1.70158; const float c1 = 1.70158;
const float c3 = c1 + 1; const float c3 = c1 + 1;
return c3 * easeInCubic(x) - c1 * easeInQuad(x); return c3 * EaseInCubic(x) - c1 * EaseInQuad(x);
} }
float easeOutBack(float x) { float EaseOutBack(float x) {
const float c1 = 1.70158; const float c1 = 1.70158;
const float c3 = c1 + 1; const float c3 = c1 + 1;
return 1 + c3 * std::pow(x - 1, 3) + c1 * std::pow(x - 1, 2); return 1 + c3 * std::pow(x - 1, 3) + c1 * std::pow(x - 1, 2);
} }
float easeInOutBack(float x) { float EaseInOutBack(float x) {
const float c1 = 1.70158; const float c1 = 1.70158;
const float c2 = c1 * 1.525; const float c2 = c1 * 1.525;
return x < 0.5 return x < 0.5
? (std::pow(2 * x, 2) * ((c2 + 1) * 2 * x - c2)) / 2.0f ? (std::pow(2 * x, 2) * ((c2 + 1) * 2 * x - c2)) / 2.0f
: (std::pow(2 * x - 2, 2) * ((c2 + 1) * (x * 2 - 2) + c2) + 2) / 2.0f; : (std::pow(2 * x - 2, 2) * ((c2 + 1) * (x * 2 - 2) + c2) + 2) / 2.0f;
} }
/* Bounce functions */ /* Bounce functions */
float easeInBounce(float x) { float EaseInBounce(float x) {
return 1 - easeOutBounce(1 - x); return 1 - EaseOutBounce(1 - x);
} }
float easeOutBounce(float x) { float EaseOutBounce(float x) {
const float n1 = 7.5625; const float n1 = 7.5625;
const float d1 = 2.75; const float d1 = 2.75;
if (x < 1 / d1) { if (x < 1 / d1) {
return n1 * easeInQuad(x); return n1 * EaseInQuad(x);
} else if (x < 2 / d1) { } else if (x < 2 / d1) {
x -= 1.5; x -= 1.5;
return n1 * (x / d1) * x + 0.75; return n1 * (x / d1) * x + 0.75;
} else if (x < 2.5 / d1) { } else if (x < 2.5 / d1) {
x -= 2.25; x -= 2.25;
return n1 * (x / d1) * x + 0.9375; return n1 * (x / d1) * x + 0.9375;
} else { } else {
x -= 2.625; x -= 2.625;
return n1 * (x / d1) * x + 0.984375; return n1 * (x / d1) * x + 0.984375;
} }
} }
float easeInOutBounce(float x) { float EaseInOutBounce(float x) {
return x < 0.5 return x < 0.5
? (1 - easeOutBounce(1 - 2 * x)) / 2.0f ? (1 - EaseOutBounce(1 - 2 * x)) / 2.0f
: (1 + easeOutBounce(2 * x - 1)) / 2.0f; : (1 + EaseOutBounce(2 * x - 1)) / 2.0f;
} }
} // namespace utils } // namespace utils

35
src/misc/Log.cpp Normal file
View File

@@ -0,0 +1,35 @@
#include "misc/Log.h"
#ifdef __ANDROID__
#include <android/log.h>
#else
#include <iostream>
#endif
namespace td {
namespace utils {
void LOG(const std::string& msg) {
#ifdef __ANDROID__
__android_log_print(ANDROID_LOG_INFO, "TRACKERS", "%s", msg.c_str());
#else
std::cout << msg << "\n";
#endif
}
void LOGD(const std::string& msg) {
#if !defined(NDEBUG)
LOG(msg);
#endif
}
void LOGE(const std::string& err) {
#ifdef __ANDROID__
__android_log_print(ANDROID_LOG_ERROR, "TRACKERS", "%s", err.c_str());
#else
std::cerr << err << "\n";
#endif
}
}
} // namespace td

90
src/misc/Maths.cpp Normal file
View File

@@ -0,0 +1,90 @@
#include "misc/Maths.h"
#include <cassert>
namespace td {
namespace maths {
Mat4f Perspective(float fovY, float aspectRatio, float zNear, float zFar) {
const float tanHalfFovy = std::tan(fovY / 2.0f);
Mat4f result{};
result.x0 = 1.0f / (aspectRatio * tanHalfFovy);
result.y1 = 1.0f / (tanHalfFovy);
result.z2 = -(zFar + zNear) / (zFar - zNear);
result.z3 = -1.0f;
result.w2 = -(2.0f * zFar * zNear) / (zFar - zNear);
return result;
}
Mat4f Look(const Vec3f& eye, const Vec3f& front, const Vec3f& up) {
const Vec3f f = Normalize(front);
const Vec3f s = Normalize(Cross(f, up));
const Vec3f u = Cross(s, f);
Mat4f result = Identity<float>();
result.x0 = s.x;
result.y0 = s.y;
result.z0 = s.z;
result.x1 = u.x;
result.y1 = u.y;
result.z1 = u.z;
result.x2 = -f.x;
result.y2 = -f.y;
result.z2 = -f.z;
result.w0 = -Dot(s, eye);
result.w1 = -Dot(u, eye);
result.w2 = Dot(f, eye);
return result;
}
Mat4f Inverse(const Mat4f& mat) {
float s0 = mat.at(0, 0) * mat.at(1, 1) - mat.at(1, 0) * mat.at(0, 1);
float s1 = mat.at(0, 0) * mat.at(1, 2) - mat.at(1, 0) * mat.at(0, 2);
float s2 = mat.at(0, 0) * mat.at(1, 3) - mat.at(1, 0) * mat.at(0, 3);
float s3 = mat.at(0, 1) * mat.at(1, 2) - mat.at(1, 1) * mat.at(0, 2);
float s4 = mat.at(0, 1) * mat.at(1, 3) - mat.at(1, 1) * mat.at(0, 3);
float s5 = mat.at(0, 2) * mat.at(1, 3) - mat.at(1, 2) * mat.at(0, 3);
float c5 = mat.at(2, 2) * mat.at(3, 3) - mat.at(3, 2) * mat.at(2, 3);
float c4 = mat.at(2, 1) * mat.at(3, 3) - mat.at(3, 1) * mat.at(2, 3);
float c3 = mat.at(2, 1) * mat.at(3, 2) - mat.at(3, 1) * mat.at(2, 2);
float c2 = mat.at(2, 0) * mat.at(3, 3) - mat.at(3, 0) * mat.at(2, 3);
float c1 = mat.at(2, 0) * mat.at(3, 2) - mat.at(3, 0) * mat.at(2, 2);
float c0 = mat.at(2, 0) * mat.at(3, 1) - mat.at(3, 0) * mat.at(2, 1);
float det = s0 * c5 - s1 * c4 + s2 * c3 + s3 * c2 - s4 * c1 + s5 * c0;
assert(det != 0 && "Determinant equals 0 !");
float invdet = 1.0 / det;
Mat4f result;
result.at(0, 0) = ( mat.at(1, 1) * c5 - mat.at(1, 2) * c4 + mat.at(1, 3) * c3) * invdet;
result.at(0, 1) = (-mat.at(0, 1) * c5 + mat.at(0, 2) * c4 - mat.at(0, 3) * c3) * invdet;
result.at(0, 2) = ( mat.at(3, 1) * s5 - mat.at(3, 2) * s4 + mat.at(3, 3) * s3) * invdet;
result.at(0, 3) = (-mat.at(2, 1) * s5 + mat.at(2, 2) * s4 - mat.at(2, 3) * s3) * invdet;
result.at(1, 0) = (-mat.at(1, 0) * c5 + mat.at(1, 2) * c2 - mat.at(1, 3) * c1) * invdet;
result.at(1, 1) = ( mat.at(0, 0) * c5 - mat.at(0, 2) * c2 + mat.at(0, 3) * c1) * invdet;
result.at(1, 2) = (-mat.at(3, 0) * s5 + mat.at(3, 2) * s2 - mat.at(3, 3) * s1) * invdet;
result.at(1, 3) = ( mat.at(2, 0) * s5 - mat.at(2, 2) * s2 + mat.at(2, 3) * s1) * invdet;
result.at(2, 0) = ( mat.at(1, 0) * c4 - mat.at(1, 1) * c2 + mat.at(1, 3) * c0) * invdet;
result.at(2, 1) = (-mat.at(0, 0) * c4 + mat.at(0, 1) * c2 - mat.at(0, 3) * c0) * invdet;
result.at(2, 2) = ( mat.at(3, 0) * s4 - mat.at(3, 1) * s2 + mat.at(3, 3) * s0) * invdet;
result.at(2, 3) = (-mat.at(2, 0) * s4 + mat.at(2, 1) * s2 - mat.at(2, 3) * s0) * invdet;
result.at(3, 0) = (-mat.at(1, 0) * c3 + mat.at(1, 1) * c1 - mat.at(1, 2) * c0) * invdet;
result.at(3, 1) = ( mat.at(0, 0) * c3 - mat.at(0, 1) * c1 + mat.at(0, 2) * c0) * invdet;
result.at(3, 2) = (-mat.at(3, 0) * s3 + mat.at(3, 1) * s1 - mat.at(3, 2) * s0) * invdet;
result.at(3, 3) = ( mat.at(2, 0) * s3 - mat.at(2, 1) * s1 + mat.at(2, 2) * s0) * invdet;
return result;
}
} // namespace maths
} // namespace td

View File

@@ -7,76 +7,77 @@ namespace td {
namespace utils { namespace utils {
namespace shape { namespace shape {
float Point::distance(const Point& point) const { float Point::Distance(const Point& point) const {
return std::sqrt(distanceSquared(point)); return std::sqrt(DistanceSquared(point));
} }
float Point::distanceSquared(const Point& point) const { float Point::DistanceSquared(const Point& point) const {
return (m_X - point.getX()) * (m_X - point.getX()) + (m_Y - point.getY()) * (m_Y - point.getY()); return (m_X - point.GetX()) * (m_X - point.GetX()) + (m_Y - point.GetY()) * (m_Y - point.GetY());
} }
bool Rectangle::collidesWith(const Point& point) const { bool Rectangle::CollidesWith(const Point& point) const {
return point.getX() > getTopLeft().getX() && point.getX() < getBottomRight().getX() && return point.GetX() > GetTopLeft().GetX() && point.GetX() < GetBottomRight().GetX() &&
point.getY() > getTopLeft().getY() && point.getY() < getBottomRight().getY(); point.GetY() > GetTopLeft().GetY() && point.GetY() < GetBottomRight().GetY();
} }
bool Rectangle::collidesWith(const Rectangle& rect) const { 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; Point point1{ rect.GetTopLeft().GetX(), rect.GetTopLeft().GetY() };
if (collidesWith(point2)) return true; Point point2{ rect.GetTopLeft().GetX(), rect.GetBottomRight().GetY() };
if (collidesWith(point3)) return true; Point point3{ rect.GetBottomRight().GetX(), rect.GetTopLeft().GetY() };
if (collidesWith(point4)) return true; Point point4{ rect.GetBottomRight().GetX(), rect.GetBottomRight().GetY() };
return false; 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 { bool Rectangle::CollidesWith(const Circle& circle) const {
return circle.collidesWith(*this); return circle.CollidesWith(*this);
} }
float Rectangle::distance(const Circle& circle) const { float Rectangle::Distance(const Circle& circle) const {
return circle.distance(*this); return circle.Distance(*this);
} }
float Rectangle::distanceSquared(const Circle& circle) const { float Rectangle::DistanceSquared(const Circle& circle) const {
return circle.distanceSquared(*this); return circle.DistanceSquared(*this);
} }
bool Circle::collidesWith(const Point& point) const { bool Circle::CollidesWith(const Point& point) const {
return m_Radius * m_Radius > m_Center.distanceSquared(point); return m_Radius * m_Radius > m_Center.DistanceSquared(point);
} }
bool Circle::collidesWith(const Rectangle& rect) const { bool Circle::CollidesWith(const Rectangle& rect) const {
float distanceSquared_ = distanceSquared(rect); float DistanceSquared_ = DistanceSquared(rect);
return distanceSquared_ < m_Radius* m_Radius; return DistanceSquared_ < m_Radius* m_Radius;
} }
bool Circle::collidesWith(const Circle& circle) const { bool Circle::CollidesWith(const Circle& circle) const {
return m_Radius + circle.getRadius() > m_Center.distanceSquared(circle.getCenter()); return m_Radius + circle.GetRadius() > m_Center.DistanceSquared(circle.GetCenter());
} }
float Circle::distance(const Rectangle& rect) const { float Circle::Distance(const Rectangle& rect) const {
return std::sqrt(distanceSquared(rect)); return std::sqrt(DistanceSquared(rect));
} }
float Circle::distanceSquared(const Rectangle& rect) const { float Circle::DistanceSquared(const Rectangle& rect) const {
float closestX = std::clamp(m_Center.getX(), rect.getTopLeft().getX(), rect.getBottomRight().getX()); 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 closestY = std::clamp(m_Center.GetY(), rect.GetTopLeft().GetY(), rect.GetBottomRight().GetY());
float distanceX = m_Center.getX() - closestX; float DistanceX = m_Center.GetX() - closestX;
float distanceY = m_Center.getY() - closestY; float DistanceY = m_Center.GetY() - closestY;
return (distanceX * distanceX) + (distanceY * distanceY); return (DistanceX * DistanceX) + (DistanceY * DistanceY);
} }
} // namespace shape } // namespace shape

Some files were not shown because too many files have changed in this diff Show More