154 Commits

Author SHA1 Message Date
4b732c2fe9 add ressources 2023-06-28 22:54:22 +02:00
66b39e1855 multiple mobs render 2023-06-28 22:51:36 +02:00
b985cc7ade make use of TexturedModel 2023-06-28 22:19:18 +02:00
385dcf11d0 load basic 3d model 2023-06-28 21:23:42 +02:00
385626d42b debug spawning 2023-06-28 21:18:02 +02:00
6b9528c2ae add face culling 2023-06-26 09:59:08 +02:00
c9ee8216be add depth 2023-06-26 09:37:23 +02:00
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
784c558840 chore: bump version to "alpha-0.2.0" 2021-12-19 18:40:44 +01:00
5d366b6f6c feat: sync game 2021-12-19 18:40:14 +01:00
f70661694b chore: bump version to "alpha-0.1.2" 2021-12-19 11:58:36 +01:00
36a1ab0572 feat: close server when game finished 2021-12-19 11:57:47 +01:00
409268b604 refactor: use of GuiManager 2021-12-19 11:56:41 +01:00
174d144d26 refactor: add default server tps 2021-12-19 11:38:54 +01:00
360258e4cf feat: add end game disconnect 2021-12-13 20:05:20 +01:00
2148c0050c refactor: add game listener 2021-12-13 19:45:01 +01:00
61166023df feat: don't show tile select when tooltip 2021-12-12 16:59:57 +01:00
e7bf22cea6 feat: add pseudo end game 2021-12-12 16:59:35 +01:00
f09f79198d fix: windows build 2021-12-12 16:41:48 +01:00
8c19d3cc3c refactor: removed unused constant 2021-12-12 16:27:59 +01:00
208892d266 chore: update to alpha-0.1.1 2021-12-12 16:17:53 +01:00
4384806cf0 refactor: removed unused comment 2021-12-12 16:14:24 +01:00
1a091baeaf feat: add map background color 2021-12-12 16:13:05 +01:00
43f21ffd44 chore: bump verssion to alpha-0.1.0 2021-12-12 13:33:12 +01:00
24617c539f feat: add castle tooltip 2021-12-12 13:32:39 +01:00
4611a198c9 fix: add mob spawn border 2021-12-12 13:31:01 +01:00
d40ffe8f6c refactor: removed unused include 2021-12-12 11:36:56 +01:00
384b7ad51e chore: bump version to alpha-0.0.5 2021-12-11 20:07:26 +01:00
fd9b448fa4 feat: mob castle damage 2021-12-11 20:06:52 +01:00
c4a2b08416 feat: add mob spawn notification 2021-12-11 19:56:03 +01:00
a241d7691b refactor: mob die event 2021-12-11 19:51:45 +01:00
0af4cd506c refactor: moved mob functions 2021-12-11 19:30:31 +01:00
6b5c56b37d feat: notify when mob touches castle 2021-12-11 18:46:47 +01:00
1474220a77 refactor: separate mob ans world listener 2021-12-11 18:43:49 +01:00
a802b5cef5 fix: windows compilation 2021-12-08 17:24:29 +01:00
7e91b863da bump version to alpha-0.0.4 2021-12-08 15:39:26 +01:00
129bb47286 feat: debug library 2021-12-08 15:38:20 +01:00
e4a9c5f763 feat: remove tower 2021-12-08 15:34:20 +01:00
78cf2d0f18 Merge branch 'master' of 192.168.0.5:repos/Tower-Defense 2021-12-05 12:01:50 +01:00
00d2b5394f refactor: removed unused include 2021-12-05 12:01:17 +01:00
00414abe61 refactor: comment main 2021-12-04 19:09:26 +01:00
cb847d0edd refactor: removed unused declarations 2021-12-04 13:49:50 +01:00
2da0bd9b79 refactor: tower add event processing 2021-12-04 13:44:34 +01:00
cf9633c061 fix: mob spawning repartition 2021-12-03 18:47:55 +01:00
7a6fdc30b6 add fire arrow and fix world events 2021-12-03 18:30:45 +01:00
159 changed files with 16429 additions and 5337 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,46 +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
}; };
typedef std::map<std::uint8_t, Player> PlayerList; typedef std::map<std::uint8_t, Player> PlayerList;
class Game { class GameListener {
protected:
World* m_World;
std::array<Team, 2> m_Teams = { Team{TeamColor::Red}, Team{TeamColor::Blue} };
GameState m_GameState = GameState::Lobby;
PlayerList m_Players;
public: public:
Game(World* world); virtual void OnPlayerJoin(PlayerID player) {}
virtual ~Game(); virtual void OnPlayerLeave(PlayerID player) {}
virtual void tick(std::uint64_t delta); virtual void OnGameStateUpdate(GameState newState) {}
virtual void OnGameBegin() {}
virtual void OnGameEnd() {}
virtual void OnGameClose() {}
};
Team& getRedTeam() { return m_Teams[(std::uint8_t)TeamColor::Red]; } typedef utils::ObjectNotifier<GameListener> GameNotifier;
const Team& getRedTeam() const { return m_Teams[(std::uint8_t)TeamColor::Red]; }
Team& getBlueTeam() { return m_Teams[(std::uint8_t)TeamColor::Blue]; } class Game : public GameNotifier {
const Team& getBlueTeam() const { return m_Teams[(std::uint8_t)TeamColor::Blue]; } protected:
World* m_World;
TeamList m_Teams = { Team{TeamColor::Red}, Team{TeamColor::Blue} };
GameState m_GameState = GameState::Lobby;
PlayerList m_Players;
public:
Game(World* world);
virtual ~Game();
Team& getTeam(TeamColor team) { return m_Teams[(std::uint8_t)team]; } virtual void Tick(std::uint64_t delta);
const Team& getTeam(TeamColor team) const { return m_Teams[(std::uint8_t)team]; }
GameState getGameState() const { return m_GameState; } Team& GetRedTeam() { return m_Teams[static_cast<std::uint8_t>(TeamColor::Red)]; }
void setGameState(GameState gameState) { m_GameState = gameState; }; const Team& GetRedTeam() const { return m_Teams[static_cast<std::uint8_t>(TeamColor::Red)]; }
const World* getWorld() const { return m_World; } Team& GetBlueTeam() { return m_Teams[static_cast<std::uint8_t>(TeamColor::Blue)]; }
World* getWorld() { return m_World; } const Team& GetBlueTeam() const { return m_Teams[static_cast<std::uint8_t>(TeamColor::Red)]; }
const PlayerList& getPlayers() const { return m_Players; } Team& GetTeam(TeamColor team) { return m_Teams[static_cast<std::uint8_t>(team)]; }
PlayerList& getPlayers() { return m_Players; } const Team& GetTeam(TeamColor team) const { return m_Teams[static_cast<std::uint8_t>(team)]; }
const Player& getPlayerById(PlayerID id) const { return m_Players.find(id)->second; } GameState GetGameState() const { return m_GameState; }
Player& getPlayerById(PlayerID id) { return m_Players.find(id)->second; } void SetGameState(GameState gameState) { m_GameState = gameState; };
const World* GetWorld() const { return m_World; }
World* GetWorld() { return m_World; }
const PlayerList& GetPlayers() const { return m_Players; }
PlayerList& GetPlayers() { return m_Players; }
const Player* GetPlayerById(PlayerID id) const;
Player* GetPlayerById(PlayerID id);
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,38 +1,41 @@
#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"
#include "misc/ObjectNotifier.h"
#include <vector> #include <vector>
#include <memory> #include <memory>
#include <glm/glm.hpp>
namespace td { namespace td {
namespace game { namespace game {
struct WalkableTile;
enum class EffectType : std::uint8_t { enum class EffectType : std::uint8_t {
Slowness = 0, Slowness = 0,
Stun, Stun,
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;
@@ -42,182 +45,217 @@ 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
const Tower* tower; // the tower that gived the effect Tower* tower; // the tower that gived the effect
}; };
const MobStats* getMobStats(MobType type, std::uint8_t level); const MobStats* GetMobStats(MobType type, std::uint8_t level);
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
bool m_HasReachedCastle; // if true, no need to walk anymore 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;
utils::CooldownTimer m_AttackTimer;
public: public:
Mob(MobID id, MobLevel level, PlayerID sender) : m_Sender(sender), m_Level(level), Mob(MobID id, MobLevel level, PlayerID sender) : m_Sender(sender), m_Level(level),
m_HasReachedCastle(false), m_EffectFireTimer(1000), m_EffectPoisonTimer(1000), m_HitCooldown(0), m_EffectFireTimer(1000), m_EffectPoisonTimer(1000),
m_EffectHealTimer(1000) { m_EffectHealTimer(1000), m_CastleTarget(nullptr), m_AttackTimer(1000) {
} }
virtual MobType getType() const = 0; virtual MobType GetType() const = 0;
virtual void tick(std::uint64_t delta); virtual void Tick(std::uint64_t delta, World* world);
virtual bool OnDeath(World* world) { return true; } virtual bool OnDeath(World* world) { return true; }
const TowerImmunities& getTowerImmunities() const { return getMobTowerImmunities(getType(), m_Level); } MobID GetMobID() const { return m_ID; }
const EffectImmunities& getEffectImmunities() const { return getMobEffectImmunities(getType(), m_Level); } const TowerImmunities& GetTowerImmunities() const { return GetMobTowerImmunities(GetType(), m_Level); }
PlayerID getSender() const { return m_Sender; } const EffectImmunities& GetEffectImmunities() const { return GetMobEffectImmunities(GetType(), m_Level); }
MobLevel getLevel() const { return m_Level; } PlayerID GetSender() const { return m_Sender; }
const MobStats* getStats() const { return getMobStats(getType(), m_Level); } MobLevel GetLevel() const { return m_Level; }
float getHealth() const { return m_Health; } const MobStats* GetStats() const { return GetMobStats(GetType(), m_Level); }
bool isDead() const { return m_Health <= 0; } void SetHealth(float newHealth) { m_Health = newHealth; }
bool isAlive() const { return m_Health > 0; } float GetHealth() const { return m_Health; }
const Tower* getLastDamageTower() { return m_LastDamage; } bool IsDead() const { return m_Health <= 0; }
bool hasReachedEnemyCastle() { return m_HasReachedCastle; } bool IsAlive() const { return m_Health > 0; }
const Tower* GetLastDamageTower() { return m_LastDamage; }
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() { m_HasReachedCastle = true; } // 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, const 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); void UpdateEffects(std::uint64_t delta, World* world);
EffectDuration& getEffect(EffectType type); void AttackCastle(std::uint64_t delta, World* world);
void Move(std::uint64_t delta, World* world);
void Walk(std::uint64_t delta, World* world);
void MoveBack(const TeamCastle& castle, World* world);
void ChangeDirection(const WalkableTile& tile, World* world);
bool IsTouchingCastle(const TeamCastle& castle) const;
EffectDuration& GetEffect(EffectType type);
}; };
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 {
public:
virtual void OnMobSpawn(Mob* mob) {}
virtual void OnMobDie(Mob* mob) {}
virtual void OnMobDamage(Mob* target, float damage, Tower* damager) {}
virtual void OnMobTouchCastle(Mob* damager, TeamCastle* enemyCastle) {}
virtual void OnMobCastleDamage(Mob* damager, TeamCastle* enemyCastle, float damage) {}
};
typedef utils::ObjectNotifier<MobListener> MobNotifier;
} // namespace game } // namespace game
} // namespace td } // namespace td

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,62 +14,79 @@ 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; }
}; };
struct TeamCastle : public utils::shape::Rectangle{ class Team;
class TeamCastle : public utils::shape::Rectangle {
private: private:
float m_Life; const Team* m_Team;
float m_Life;
public: public:
TeamCastle() : m_Life(1000) { static constexpr int CastleMaxLife = 1000;
setWidth(5);
setHeight(5);
}
float getLife() const { return m_Life; } TeamCastle(const Team* team) : m_Team(team), m_Life(CastleMaxLife) {
SetWidth(5);
SetHeight(5);
}
void setLife(float life) { m_Life = life; } TeamCastle() : TeamCastle(nullptr) {}
void damage(float damage) { m_Life = std::max(0.0f, m_Life - damage); }
float GetLife() const { return m_Life; }
const Team* GetTeam() const { return m_Team; }
void SetTeam(const Team* team) { m_Team = team; }
void SetLife(float life) { m_Life = life; }
void Damage(float damage) { m_Life = std::max(0.0f, m_Life - damage); }
void SetShape(utils::shape::Rectangle rect) {
SetCenter(rect.GetCenter());
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;
} // namespace game } // namespace game
} // namespace td } // namespace td

View File

@@ -1,6 +1,5 @@
#pragma once #pragma once
#include <cstdint>
#include <string> #include <string>
#include <memory> #include <memory>
@@ -18,247 +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;
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,33 +4,37 @@
#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"
#include "Team.h" #include "Team.h"
#include "misc/ObjectNotifier.h"
namespace td { namespace td {
namespace game { namespace game {
typedef std::pair<std::int16_t, std::int16_t> ChunkCoord;
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;
@@ -43,42 +47,45 @@ 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 { static constexpr Color BLACK{ 0, 0, 0 };
std::uint8_t r, g, b; static constexpr Color WHITE{ 255, 255, 255 };
};
static constexpr Color RED{ 255, 0, 0 };
static constexpr Color GREEN{ 0, 255, 0 };
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;
@@ -86,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;
@@ -118,111 +126,119 @@ typedef std::vector<TowerPtr> TowerList;
class WorldListener { class WorldListener {
public: public:
WorldListener(){} WorldListener() {}
virtual void OnArcherTowerShot(MobPtr target, ArcherTower* shooter){} virtual void OnTowerAdd(TowerPtr tower) {}
virtual void OnTowerRemove(TowerPtr tower) {}
virtual void OnArrowShot(MobPtr target, Tower* shooter){} virtual void OnArcherTowerShot(MobPtr target, ArcherTower* shooter) {}
virtual void OnExplosion(utils::shape::Circle explosion, float centerDamage, Tower* shooter){}
virtual void OnMobDamage(MobPtr target, float damage, Tower* damager){} virtual void OnArrowShot(MobPtr target, bool fire, Tower* shooter) {}
virtual void OnExplosion(utils::shape::Circle explosion, float centerDamage, Tower* shooter) {}
virtual void OnMobDead(MobPtr mob){}
}; };
typedef utils::ObjectNotifier<WorldListener> WorldNotifier; typedef utils::ObjectNotifier<WorldListener> WorldNotifier;
class World : public WorldNotifier, public WorldListener{ class World : public WorldListener, public MobListener {
protected: protected:
TowerTileColorPalette m_TowerPlacePalette; TowerTileColorPalette m_TowerPlacePalette;
Color m_WalkablePalette; Color m_WalkablePalette;
std::vector<Color> m_DecorationPalette; std::vector<Color> m_DecorationPalette;
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;
MobNotifier m_MobNotifier;
public: public:
World(Game* game); World(Game* game);
static constexpr std::uint8_t CastleWidth = 5, CastleHeight = 5; bool LoadMap(const protocol::WorldBeginDataPacket* worldHeader);
bool LoadMap(const protocol::WorldDataPacket* worldData);
bool loadMap(const protocol::WorldBeginDataPacket* worldHeader); bool LoadMapFromFile(const std::string& fileName);
bool loadMap(const protocol::WorldDataPacket* worldData); bool SaveMap(const std::string& fileName) const;
bool loadMapFromFile(const std::string& fileName); void Tick(std::uint64_t delta);
bool saveMap(const std::string& fileName) const;
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 RemoveTower(TowerID id);
TowerPtr placeTowerAt(TowerID id, TowerType type, std::int32_t x, std::int32_t y, PlayerID builder); 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 Color& GetWalkableTileColor() const { return m_WalkablePalette; }
const std::vector<Color>& GetDecorationPalette() const { return m_DecorationPalette; }
const Color& GetBackgroundColor() const { return m_Background; }
const TowerTileColorPalette& getTowerTileColorPalette() const { return m_TowerPlacePalette; } const TilePalette& GetTilePalette() const { return m_TilePalette; }
const Color& getWalkableTileColor() const { return m_WalkablePalette; }
const std::vector<Color>& getDecorationPalette() const { return m_DecorationPalette; }
const TilePalette& getTilePalette() const { return m_TilePalette; } TilePtr GetTilePtr(TileIndex index) const {
if (index == 0)
return nullptr;
return m_TilePalette.at(index - 1);
}
TilePtr getTilePtr(TileIndex index) const { bool CanPlaceLittleTower(const Vec2f& worldPos, PlayerID player) const;
if (index == 0) bool CanPlaceBigTower(const Vec2f& worldPos, PlayerID player) const;
return nullptr;
return m_TilePalette.at(index - 1);
}
bool CanPlaceLittleTower(const glm::vec2& worldPos, PlayerID player) const; TowerPtr GetTower(const Vec2f& position) const; // returns null if no tower is here
bool CanPlaceBigTower(const glm::vec2& worldPos, PlayerID player) const;
TowerPtr getTower(const glm::vec2& 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[static_cast<std::size_t>(color)]; }
const SpawnColorPalette& GetSpawnColors() const { return m_SpawnColorPalette; }
const Color& getSpawnColor(TeamColor color) const { return m_SpawnColorPalette[(std::size_t)color]; } const MobList& GetMobList() const { return m_Mobs; }
const SpawnColorPalette& getSpawnColors() const { return m_SpawnColorPalette; } MobList& GetMobList() { return m_Mobs; }
const MobList& getMobList() const { return m_Mobs; } const Color* GetTileColor(TilePtr tile) const;
MobList& getMobList() { return m_Mobs; }
const Color* getTileColor(TilePtr tile) const; Team& GetRedTeam();
const Team& GetRedTeam() const;
Team& getRedTeam(); Team& GetBlueTeam();
const Team& getRedTeam() const; const Team& GetBlueTeam() const;
Team& getBlueTeam(); Team& GetTeam(TeamColor team);
const Team& getBlueTeam() const; const Team& GetTeam(TeamColor team) const;
Team& getTeam(TeamColor team); const TeamList& GetTeams() const;
const Team& getTeam(TeamColor team) const;
const TowerList& getTowers() const { return m_Towers; }; const TowerList& GetTowers() const { return m_Towers; }
TowerPtr getTowerById(TowerID tower); TowerPtr GetTowerById(TowerID tower);
// WorldListener const Player* GetPlayerById(PlayerID id) const;
virtual void OnArcherTowerShot(MobPtr target, ArcherTower* shooter); WorldNotifier& GetWorldNotifier() { return m_WorldNotifier; }
MobNotifier& GetMobNotifier() { return m_MobNotifier; }
virtual void OnArrowShot(MobPtr target, Tower* shooter); // WorldListener
virtual void OnExplosion(utils::shape::Circle explosion, float centerDamage, Tower* 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;
// MobListener
virtual void OnMobDamage(Mob* target, float damage, Tower* source) override;
virtual void OnMobCastleDamage(Mob* damager, TeamCastle* enemyCastle, float damage) override;
virtual void OnMobDamage(MobPtr target, float damage, Tower* source);
private: private:
void moveMobs(std::uint64_t delta); void TickMobs(std::uint64_t delta);
void moveMob(MobPtr mob, std::uint64_t delta); void CleanDeadMobs();
void moveBackMob(MobPtr mob, const TeamCastle& castle);
void changeMobDirection(MobPtr mob, WalkableTilePtr tile);
bool isMobTouchingCastle(MobPtr mob, const TeamCastle& castle) const;
void tickMobs(std::uint64_t delta);
void cleanDeadMobs();
}; };
} // namespace game } // namespace game

View File

@@ -17,33 +17,38 @@ namespace client {
class Client { class Client {
private: private:
render::Renderer* m_Renderer; render::Renderer* m_Renderer;
ClientConnexion m_Connexion; ClientConnexion m_Connexion;
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(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 PlaceTower(game::TowerType type, const Vec2f& position);
void UpgradeTower(game::TowerID tower, game::TowerLevel level);
void RemoveTower(game::TowerID tower);
private:
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,41 @@ 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; }
virtual void HandlePacket(const protocol::ConnexionInfoPacket* packet) override;
virtual void HandlePacket(const protocol::PlayerJoinPacket* packet) override;
virtual void HandlePacket(const protocol::PlayerLeavePacket* packet) override;
virtual void HandlePacket(const protocol::PlayerListPacket* packet) override;
virtual void HandlePacket(const protocol::UpdatePlayerTeamPacket* packet) override;
virtual void HandlePacket(const protocol::UpdateGameStatePacket* packet) override;
virtual void HandlePacket(const protocol::UpdateLobbyTimePacket* packet) override;
virtual void HandlePacket(const protocol::UpdateMoneyPacket* packet) override;
virtual void HandlePacket(const protocol::UpdateExpPacket* packet) override;
virtual void HandlePacket(const protocol::DisconnectPacket* packet) override;
virtual void HandlePacket(const protocol::WorldDataPacket* packet) override;
virtual void HandlePacket(const protocol::ConnexionInfoPacket* packet);
virtual void HandlePacket(const protocol::PlayerJoinPacket* packet);
virtual void HandlePacket(const protocol::PlayerLeavePacket* packet);
virtual void HandlePacket(const protocol::PlayerListPacket* packet);
virtual void HandlePacket(const protocol::UpdatePlayerTeamPacket* packet);
virtual void HandlePacket(const protocol::UpdateGameStatePacket* packet);
virtual void HandlePacket(const protocol::UpdateLobbyTimePacket* packet);
virtual void HandlePacket(const protocol::UpdateMoneyPacket* packet);
virtual void HandlePacket(const protocol::DisconnectPacket* packet);
virtual void HandlePacket(const protocol::WorldDataPacket* packet);
virtual void HandlePacket(const protocol::WorldAddTowerPacket* packet);
}; };
} // namespace client } // namespace client

View File

@@ -10,16 +10,19 @@ 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) override; virtual void HandlePacket(const protocol::WorldBeginDataPacket* packet) override;
virtual void HandlePacket(const protocol::WorldDataPacket* packet) override; virtual void HandlePacket(const protocol::WorldDataPacket* packet) override;
virtual void HandlePacket(const protocol::SpawnMobPacket* packet) override; virtual void HandlePacket(const protocol::SpawnMobPacket* packet) override;
virtual void HandlePacket(const protocol::UpgradeTowerPacket* packet) override; virtual void HandlePacket(const protocol::UpgradeTowerPacket* packet) override;
virtual void HandlePacket(const protocol::WorldAddTowerPacket* packet) override;
virtual void HandlePacket(const protocol::RemoveTowerPacket* packet) override;
virtual void HandlePacket(const protocol::UpdateMobStatesPacket* packet) override;
virtual void HandlePacket(const protocol::UpdateCastleLifePacket* packet) override;
virtual void OnArrowShot(game::MobPtr target, game::Tower* shooter) override;
}; };
} // namespace client } // namespace client

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,78 +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(); void Stop(); // force the server to stop
void Close(); // at the end of a game
void lauchGame(); 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; }
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 startThread(); void Clean();
void stopThread(); void StartThread();
void tick(std::uint64_t delta); void StopThread();
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,48 +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) 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

@@ -9,23 +9,34 @@ namespace server {
class Server; class Server;
class ServerGame : public game::Game { 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{ 1000, std::bind(&ServerGame::updateGoldMines, this) }; utils::AutoTimer m_GoldMineTimer;
utils::AutoTimer m_MobStatesTimer;
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
virtual void OnGameStateUpdate(game::GameState newState) override;
virtual void OnGameBegin() override;
virtual void OnGameEnd() override;
virtual void OnGameClose() override;
private: private:
void balanceTeams(); void BalanceTeams();
void updateGoldMines(); void InitPlayerStats();
void updatePlayerStats(); void UpdateMobStates();
void UpdateGoldMines();
void UpdatePlayerStats();
}; };
} // namespace game } // namespace game

View File

@@ -10,16 +10,20 @@ 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:
ServerWorld(Server* server, ServerGame* game); static constexpr float MobSpawnBorder = 0.01f;
void spawnMobs(game::MobType type, std::uint8_t level, game::PlayerID sender, std::uint8_t count); ServerWorld(Server* server, ServerGame* game);
game::TowerPtr placeTowerAt(game::TowerType type, std::int32_t x, std::int32_t y, game::PlayerID builder);
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);
virtual void OnMobDie(game::Mob* mob) override;
virtual void OnMobCastleDamage(game::Mob* damager, game::TeamCastle* enemyCastle, float damage) override;
virtual void OnArrowShot(game::MobPtr target, game::Tower* shooter) override;
}; };
} // namespace server } // namespace server

4465
include/misc/Backward.hpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -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,84 +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 setWidth(float width) { m_Width = width; } void SetSize(Point size) { SetSize(size.GetX(), size.GetY()); }
void setHeight(float height) { m_Height = height; } Point GetSize() { return { m_Width, m_Height }; }
bool collidesWith(const Point& point) const; void SetWidth(float width) { m_Width = width; }
bool collidesWith(const Rectangle& rect) const; void SetHeight(float height) { m_Height = height; }
bool collidesWith(const Circle& circle) const;
// distance from the closest side of the rectangle bool CollidesWith(const Point& point) const;
float distance(const Circle& circle) const; bool CollidesWith(const Rectangle& rect) const;
float distanceSquared(const Circle& circle) const; bool CollidesWith(const Circle& circle) const;
// distance from the closest side of the rectangle
float Distance(const Circle& circle) const;
float DistanceSquared(const Circle& circle) const;
}; };
class Circle { 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) // 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,35 +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 WorldRemoveTowerPacket* 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 UpgradeTowerPacket* 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,506 +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,
WorldRemoveTower, UpdateMobStates,
UpdateCastleLife,
// client <--> server // client <--> server
KeepAlive, KeepAlive,
Disconnect, Disconnect,
UpgradeTower, UpgradeTower,
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;
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 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 WorldRemoveTowerPacket : public Packet { class RemoveTowerPacket : public Packet {
private: private:
game::TowerID m_TowerID; game::TowerID m_TowerID;
public: public:
WorldRemoveTowerPacket() {} RemoveTowerPacket() {}
WorldRemoveTowerPacket(game::TowerID id) : m_TowerID(id) {} RemoveTowerPacket(game::TowerID id) : m_TowerID(id) {}
virtual ~WorldRemoveTowerPacket() {} virtual ~RemoveTowerPacket() {}
virtual DataBuffer Serialize() const; virtual DataBuffer Serialize(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::WorldRemoveTower; } 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 {
} using Point = utils::shape::Point;
private:
game::MobID m_MobID;
Point m_MobPosition;
float m_MobLife;
game::Direction m_MobDirection;
public:
MobState() {}
MobState(game::MobID id, const Point& position, float life, game::Direction direction) :
m_MobID(id), m_MobPosition(position), m_MobLife(life), m_MobDirection(direction) {
}
game::MobID GetMobId() const { return m_MobID; }
Point GetMobPosition() const { return m_MobPosition; }
float GetMobLife() const { return m_MobLife; }
game::Direction GetMobDirection() const { return m_MobDirection; }
};
class UpdateMobStatesPacket : public Packet {
private:
std::vector<MobState> m_MobStates;
public:
UpdateMobStatesPacket() {}
virtual ~UpdateMobStatesPacket() {}
virtual DataBuffer Serialize(bool packetID = true) const;
virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const;
void addMobState(MobState mobState) { m_MobStates.push_back(mobState); }
const std::vector<MobState>& GetMobStates() const { return m_MobStates; }
virtual PacketType GetType() const { return PacketType::UpdateMobStates; }
};
class UpdateCastleLifePacket : public Packet {
private:
std::uint16_t m_CastleLife;
game::TeamColor m_Team;
public:
UpdateCastleLifePacket() {}
UpdateCastleLifePacket(std::uint16_t life, game::TeamColor team) : m_CastleLife(life), m_Team(team) {}
virtual ~UpdateCastleLifePacket() {}
virtual DataBuffer Serialize(bool packetID = true) const;
virtual void Deserialize(DataBuffer& data);
virtual void Dispatch(PacketHandler* handler) const;
std::uint16_t GetCastleLife() const { return m_CastleLife; }
game::TeamColor GetTeamColor() const { return m_Team; }
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,46 +9,89 @@
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;
};
struct Model {
std::unique_ptr<GL::VertexArray> vao;
Vec3f positon;
Vec3f color = { 1, 1, 1 };
};
class TexturedModel {
private:
std::unique_ptr<GL::VertexArray> m_Vao;
std::unique_ptr<GL::Texture> m_Texture;
Vec3f m_Positon;
Vec3f m_Color = { 1, 1, 1 };
public:
REMOVE_COPY(TexturedModel);
TexturedModel(GL::VertexArray&& vao, GL::Texture&& texture);
TexturedModel(TexturedModel&& other);
~TexturedModel() {}
const GL::VertexArray& GetVao() const { return *m_Vao; }
const GL::Texture& GetTexture() const { return *m_Texture; }
Vec3f GetPosition() const { return m_Positon; }
Vec3f GetColor() const { return m_Color; }
void SetPosition(Vec3f newPos) { m_Positon = newPos; }
void SetColor(Vec3f newColor) { m_Color = newColor; }
};
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 {
GL::VertexArray* vao;
glm::vec2 positon;
};
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;
bool m_IsometricView = true; Vec2i m_WindowSize;
float m_IsometricShade = m_IsometricView;
glm::vec2 m_CamPos{}; Vec3f m_BackgroundColor;
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 RenderModel(const TexturedModel& 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);
glm::vec2 getCursorWorldPos(const glm::vec2& cursorPos, float aspectRatio, float zoom, float windowWidth, float windowHeight); void SetBackgroundColor(const Vec3f& color) { m_BackgroundColor = color; }
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,23 +11,27 @@ namespace render {
class VertexCache { class VertexCache {
typedef std::vector<float> Vector; typedef std::vector<float> Vector;
typedef std::pair<Vector::iterator, Vector::iterator> ElementsIndex;
typedef std::pair<ElementsIndex, ElementsIndex> DataIndex; struct DataIndex {
Vector position;
Vector color;
};
private: private:
Vector m_Positions; std::size_t m_VertexCount;
Vector m_Colors; std::unordered_map<std::uint64_t, DataIndex> m_Indexes;
std::unordered_map<std::uint64_t, DataIndex> m_Indexes; std::unique_ptr<GL::VertexArray> m_VertexArray;
std::unique_ptr<GL::VertexArray> m_VertexArray;
public: public:
void addData(std::uint64_t index, std::vector<float> positions, std::vector<float> colors); VertexCache() : m_VertexCount(0) {}
void removeData(std::uint64_t index);
void clear();
void updateVertexArray();
const GL::VertexArray& getVertexArray() const { return *m_VertexArray; } void AddData(std::uint64_t index, std::vector<float> positions, std::vector<float> colors);
bool isEmpty() const { return m_VertexArray == nullptr; } void RemoveData(std::uint64_t index);
void Clear();
void UpdateVertexArray();
const GL::VertexArray& GetVertexArray() const { return *m_VertexArray; }
bool IsEmpty() const { return m_VertexArray == nullptr; }
}; };
} // namespace render } // namespace render

View File

@@ -6,12 +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/imgui/imgui.h" #include "render/gui/imgui/imgui.h"
#include <glm/glm.hpp>
namespace td { namespace td {
namespace client { namespace client {
@@ -23,56 +23,65 @@ class ClientGame;
namespace render { namespace render {
class WorldRenderer { class WorldRenderer : public game::WorldListener {
private: private:
client::ClientGame* m_Client; client::ClientGame* m_Client;
Renderer* m_Renderer; Renderer* m_Renderer;
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;
glm::vec2 m_CamPos; std::unique_ptr<Model> m_SelectTileModel;
glm::vec2 m_CursorPos; std::vector<TexturedModel> m_MobModels;
glm::vec2 m_HoldCursorPos; Vec2f m_CamPos;
glm::vec2 m_LastClicked; Vec2f m_CursorPos;
float m_Zoom; Vec2f m_HoldCursorPos;
float m_CamSensibility = 1; Vec2f m_LastClicked;
bool m_PopupOpened = false; float m_Zoom;
VertexCache m_TowersCache; float m_CamSensibility = 1;
bool m_PopupOpened = false;
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::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();
void addTower(game::TowerPtr tower); static ImVec4 GetImGuiTeamColor(game::TeamColor color);
void removeTower(game::TowerPtr tower);
static ImVec4 getImGuiTeamColor(game::TeamColor color); void Update();
void Render();
void update(); void SetCamPos(float camX, float camY);
void render();
void setCamPos(float camX, float camY); void MoveCam(float relativeX, float relativeY);
void ChangeZoom(float zoom);
void moveCam(float relativeX, float relativeY, float aspectRatio); // WorldListener
void changeZoom(float zoom);
virtual void OnTowerAdd(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();
void renderTileSelect() const; void RenderTileSelect() const;
void renderPopups(); void RenderPopups();
void renderTowerUpgradePopup(); void RenderMobTooltip() const;
void renderMobTooltip() const; void RenderCastleTooltip() const;
void detectClick(); void DetectClick();
void detectMobHovering() const; void DetectMobHovering() const;
glm::vec2 getCursorWorldPos() const; void DetectCastleHovering() const;
glm::vec2 getClickWorldPos() const; void RenderTooltips() const;
void RemoveTower();
Vec2f GetCursorWorldPos() const;
Vec2f GetClickWorldPos() const;
void updateCursorPos(); void UpdateCursorPos();
}; };
} // namespace render } // namespace render

View File

@@ -0,0 +1,28 @@
#pragma once
#include "GuiWidget.h"
namespace td {
namespace game {
class TeamCastle;
} // namespace game
namespace gui {
class CastleTooltip : public GuiWidget {
private:
const game::TeamCastle* m_Castle;
public:
CastleTooltip(client::Client* client);
virtual void Render();
void SetCastle(const game::TeamCastle* castle) { m_Castle = castle; }
bool IsShown() { return m_Castle != nullptr; }
};
} // namespace gui
} // namespace td

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,17 +10,19 @@ namespace gui {
class GuiManager { class GuiManager {
private: private:
std::vector<std::shared_ptr<GuiWidget>> m_Widgets; std::vector<std::unique_ptr<GuiWidget>> m_Widgets;
public: public:
void renderWidgets() { GuiManager() {}
for (auto widget : m_Widgets) {
widget->render();
}
}
void addWidgets(const std::shared_ptr<GuiWidget>& widget) { void RenderWidgets() {
m_Widgets.push_back(std::move(widget)); for (auto& widget : m_Widgets) {
} widget->Render();
}
}
void AddWidget(std::unique_ptr<GuiWidget>&& 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,13 +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; }
}; };
} // 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

@@ -9,6 +9,8 @@
#include <memory> #include <memory>
#include "render/gui/GuiManager.h"
struct SDL_Window; struct SDL_Window;
typedef void* SDL_GLContext; typedef void* SDL_GLContext;
@@ -20,39 +22,27 @@ class Client;
} // namespace client } // namespace client
namespace gui {
class MainMenu;
class GameMenu;
class FrameMenu;
class UpdateMenu;
} // namespace gui
namespace render { namespace render {
class Renderer; 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;
std::unique_ptr<td::client::Client> m_Client; td::gui::GuiManager m_GuiManager;
std::unique_ptr<td::gui::MainMenu> m_MainMenu; std::unique_ptr<td::client::Client> m_Client;
std::unique_ptr<td::gui::GameMenu> m_GameMenu;
std::unique_ptr<td::gui::FrameMenu> m_FrameMenu;
std::unique_ptr<td::gui::UpdateMenu> m_UpdateMenu;
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,33 @@ 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;
};
class Texture {
private:
unsigned int m_ID;
public:
REMOVE_COPY(Texture);
Texture(Texture&& other) {
m_ID = other.m_ID;
other.m_ID = 0;
}
Texture(const char* textureData, int width, int height, int comp);
~Texture();
unsigned int GetTextureID() const { return m_ID; }
void Bind() const;
static void Unbind();
}; };
} }

View File

@@ -0,0 +1,17 @@
#pragma once
#include "GLLoader.h"
#include "render/Renderer.h"
#include "game/Mobs.h"
namespace td {
namespace render {
namespace MobLoader {
TexturedModel LoadMobModel(game::MobType mobType);
} // namespace MobLoader
} // namespace render
} // namespace td

View File

@@ -8,8 +8,13 @@
#ifndef RENDER_LOADER_TEXTURELOADER_H_ #ifndef RENDER_LOADER_TEXTURELOADER_H_
#define RENDER_LOADER_TEXTURELOADER_H_ #define RENDER_LOADER_TEXTURELOADER_H_
#include "render/loader/GLLoader.h"
#include <string>
namespace TextureLoader { namespace TextureLoader {
const unsigned int loadGLTexture(const char* fileName);
GL::Texture LoadTexture(const std::string& 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,44 +2,42 @@
#include "misc/DataBuffer.h" #include "misc/DataBuffer.h"
#include <ctime> #define TD_VERSION "alpha-0.3.0"
#define TD_VERSION "alpha-0.0.3"
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

@@ -6,22 +6,34 @@
// Description : Hello World in C++, Ansi-style // Description : Hello World in C++, Ansi-style
//============================================================================ //============================================================================
#if !defined(NDEBUG) && !defined(_WIN32)
#define BACKWARD_HAS_UNWIND 1
#define BACKWARD_HAS_DW 1
#endif
#include "window/Display.h" #include "window/Display.h"
#include "updater/Updater.h" #include "updater/Updater.h"
#include "misc/Backward.hpp"
#ifdef __ANDROID__ #ifdef __ANDROID__
extern "C" extern "C"
#endif #endif
int main(int argc, const char* args[]) { int main(int argc, const char* args[]) {
td::utils::Updater::removeOldFile(); #if !defined(NDEBUG)
// setup signal handling
backward::SignalHandling sh;
#endif
Display::create(); // remove the outdated binary
while (!Display::isCloseRequested()) { td::utils::Updater::RemoveOldFile();
Display::pollEvents();
Display::render(); Display::Create();
Display::update(); while (!Display::IsCloseRequested()) {
} Display::PollEvents();
Display::destroy(); Display::Render();
return 0; Display::Update();
}
Display::Destroy();
return 0;
} }

View File

@@ -11,10 +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) {
auto it = m_Players.find(id);
if (it == m_Players.end()) return nullptr;
return &it->second;
}
const Player* Game::GetPlayerById(PlayerID id) const {
auto it = m_Players.find(id);
if (it == m_Players.end()) return nullptr;
return &it->second;
} }
} // namespace game } // namespace game

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

@@ -1,4 +1,6 @@
#include "game/Mobs.h" #include "game/Mobs.h"
#include "game/Player.h"
#include "game/World.h"
#include <map> #include <map>
#include <algorithm> #include <algorithm>
@@ -6,80 +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, const Tower* tower) { void Mob::AddEffect(EffectType effectType, float durationSec, Tower* tower) {
if (isImmuneTo(effectType)) if (IsImmuneTo(effectType))
return; return;
if (hasEffect(effectType)) { if (HasEffect(effectType)) {
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::tick(std::uint64_t delta) { void Mob::AttackCastle(std::uint64_t delta, World* world) {
updateEffects(delta); if (!HasReachedEnemyCastle()) return;
if (m_AttackTimer.Update(delta)) {
world->GetMobNotifier().NotifyListeners(&MobListener::OnMobCastleDamage, this, m_CastleTarget, GetStats()->GetDamage());
m_AttackTimer.ApplyCooldown();
}
} }
void Mob::updateEffects(std::uint64_t delta) { void Mob::Walk(std::uint64_t delta, World* world) {
float deltaSec = (float)delta / 1000.0f; float mobWalkSpeed = GetStats()->GetMovementSpeed();
for (std::size_t i = 0; i < m_Effects.size(); i++) {
EffectDuration& effect = m_Effects[i];
effect.duration -= deltaSec;
if (effect.duration < 0) { // effect has gone
m_Effects.erase(m_Effects.begin() + i);
switch (effect.type) {
case EffectType::Fire: {
m_EffectFireTimer.reset();
break;
}
case EffectType::Poison: { float walkAmount = mobWalkSpeed * (static_cast<float>(delta) / 1000.0f);
m_EffectPoisonTimer.reset();
break;
}
case EffectType::Heal: { if (HasEffect(EffectType::Slowness))
m_EffectHealTimer.reset(); walkAmount *= 0.70; // walk 30% slower
}
default: switch (GetDirection()) {
break; case Direction::NegativeX: {
} SetCenterX(GetCenterX() - walkAmount);
} break;
} }
if (hasEffect(EffectType::Fire)) { case Direction::PositiveX: {
if (m_EffectFireTimer.update(delta)) { SetCenterX(GetCenterX() + walkAmount);
damage(3, getEffect(EffectType::Fire).tower); break;
} }
} case Direction::NegativeY: {
if (hasEffect(EffectType::Poison)) { SetCenterY(GetCenterY() - walkAmount);
if (m_EffectPoisonTimer.update(delta)) { break;
damage(1, getEffect(EffectType::Poison).tower); }
} case Direction::PositiveY: {
} SetCenterY(GetCenterY() + walkAmount);
if (hasEffect(EffectType::Heal)) { break;
if (m_EffectFireTimer.update(delta)) { }
heal(10); default:
} break;
} }
} }
bool Mob::hasEffect(EffectType type) { void Mob::Move(std::uint64_t delta, World* world) {
return std::find_if(m_Effects.begin(), m_Effects.end(), [&type](EffectDuration effect) { return effect.type == type;}) != m_Effects.end(); TilePtr tile = world->GetTile(GetCenter().GetX(), GetCenter().GetY());
if (tile != nullptr && tile->GetType() == TileType::Walk) {
WalkableTilePtr walkTile = std::static_pointer_cast<WalkableTile>(tile);
ChangeDirection(*walkTile, world);
}
if (HasReachedEnemyCastle()) return;
Walk(delta, world);
TeamColor mobTeam = world->GetPlayerById(GetSender())->GetTeamColor();
TeamCastle* enemyCastle = nullptr;
if (mobTeam == TeamColor::Red) {
enemyCastle = &world->GetBlueTeam().GetCastle();
} else if (mobTeam == TeamColor::Blue) {
enemyCastle = &world->GetRedTeam().GetCastle();
}
if (IsTouchingCastle(*enemyCastle)) {
MoveBack(*enemyCastle, world);
SetMobReachedCastle(enemyCastle);
world->GetMobNotifier().NotifyListeners(&MobListener::OnMobTouchCastle, this, enemyCastle);
}
}
void Mob::MoveBack(const TeamCastle& enemyCastle, World* world) {
switch (GetDirection()) {
case Direction::NegativeX: {
SetCenterX(enemyCastle.GetBottomRight().GetX() + GetWidth() / 2.0f);
break;
}
case Direction::PositiveX: {
SetCenterX(enemyCastle.GetTopLeft().GetX() - GetWidth() / 2.0f);
break;
}
case Direction::NegativeY: {
SetCenterY(enemyCastle.GetBottomRight().GetY() + GetHeight() / 2.0f);
break;
}
case Direction::PositiveY: {
SetCenterY(enemyCastle.GetTopLeft().GetY() - GetHeight() / 2.0f);
break;
}
default:
break;
}
}
void Mob::ChangeDirection(const WalkableTile& tile, World* world) {
if (GetDirection() == tile.direction) return;
float tileX = static_cast<float>(static_cast<std::int32_t>(GetCenterX()));
float tileY = static_cast<float>(static_cast<std::int32_t>(GetCenterY()));
switch (GetDirection()) {
case Direction::PositiveY: {
if (tile.direction == Direction::NegativeX) {
if (GetTileY() > GetTileX()) {
SetCenterY(tileY + GetTileX());
SetDirection(tile.direction);
}
} else { // tile->direction = Direction::PositiveX
if (GetTileY() > 1 - GetTileX()) {
SetCenterY(tileY + (1 - GetTileX()));
SetDirection(tile.direction);
}
}
return;
}
case Direction::NegativeY: {
if (tile.direction == Direction::PositiveX) {
if (GetTileY() < GetTileX()) {
SetCenterY(tileY + GetTileX());
SetDirection(tile.direction);
}
} else { // tile.direction = Direction::NegativeX
if (GetTileY() < 1 - GetTileX()) {
SetCenterY(tileY + (1 - GetTileX()));
SetDirection(tile.direction);
}
}
return;
}
case Direction::PositiveX: {
if (tile.direction == Direction::NegativeY) {
if (GetTileX() > GetTileY()) {
SetCenterX(tileX + GetTileY());
SetDirection(tile.direction);
}
} else { // tile.direction = Direction::PositiveY
if (GetTileX() > 1 - GetTileY()) {
SetCenterX(tileX + (1 - GetTileY()));
SetDirection(tile.direction);
}
}
return;
}
case Direction::NegativeX: {
if (tile.direction == Direction::PositiveY) {
if (GetTileX() < GetTileY()) {
SetCenterX(tileX + GetTileY());
SetDirection(tile.direction);
}
} else { // tile.direction = Direction::NegativeY
if (GetTileX() < 1 - GetTileY()) {
SetCenterX(tileX + (1 - GetTileY()));
SetDirection(tile.direction);
}
}
return;
}
default:
break;
}
}
bool Mob::IsTouchingCastle(const TeamCastle& enemyCastle) const {
return enemyCastle.CollidesWith(*this);
}
void Mob::Tick(std::uint64_t delta, World* world) {
m_HitCooldown = std::max(0.0f, m_HitCooldown - static_cast<float>(delta / 1000.0f));
UpdateEffects(delta, world);
Move(delta, world);
AttackCastle(delta, world);
}
void Mob::UpdateEffects(std::uint64_t delta, World* world) {
float deltaSec = static_cast<float>(delta / 1000.0f);
for (std::size_t i = 0; i < m_Effects.size(); i++) {
EffectDuration& effect = m_Effects[i];
effect.duration -= deltaSec;
if (effect.duration < 0) { // effect has gone
m_Effects.erase(m_Effects.begin() + static_cast<int>(i));
switch (effect.type) {
case EffectType::Fire: {
m_EffectFireTimer.Reset();
break;
}
case EffectType::Poison: {
m_EffectPoisonTimer.Reset();
break;
}
case EffectType::Heal: {
m_EffectHealTimer.Reset();
}
default:
break;
}
}
}
if (HasEffect(EffectType::Fire)) {
if (m_EffectFireTimer.Update(delta)) {
world->GetMobNotifier().NotifyListeners(&MobListener::OnMobDamage, this, 3.0f, GetEffect(EffectType::Fire).tower);
}
}
if (HasEffect(EffectType::Poison)) {
if (m_EffectPoisonTimer.Update(delta)) {
world->GetMobNotifier().NotifyListeners(&MobListener::OnMobDamage, this, 1.0f, GetEffect(EffectType::Poison).tower);
}
}
if (HasEffect(EffectType::Heal)) {
if (m_EffectFireTimer.Update(delta)) {
Heal(10);
}
}
}
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();
} }
@@ -87,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

@@ -5,22 +5,22 @@
namespace td { namespace td {
namespace game { namespace game {
Team::Team(TeamColor color) : m_Color(color) {} 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->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->notifyListeners(&WorldListener::OnMobDamage, mob, 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->notifyListeners(&WorldListener::OnMobDamage, mob, 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,452 +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) {
bindListener(this); GetWorldNotifier().BindListener(this);
GetMobNotifier().BindListener(this);
} }
TilePtr World::getTile(std::int32_t x, std::int32_t y) const { TilePtr World::GetTile(std::int32_t x, std::int32_t y) const {
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();
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();
getBlueTeam().getCastle() = worldHeader->getBlueCastle(); GetRedTeam().GetCastle().SetTeam(&GetRedTeam());
m_TilePalette = worldHeader->getTilePalette(); GetBlueTeam().GetCastle() = worldHeader->GetBlueCastle();
GetBlueTeam().GetCastle().SetTeam(&GetBlueTeam());
return true; m_TilePalette = worldHeader->GetTilePalette();
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) {
moveMobs(delta); if (m_Game->GetGameState() != GameState::Game) return;
tickMobs(delta);
for (TowerPtr tower : m_Towers) { TickMobs(delta);
tower->tick(delta, this); for (TowerPtr tower : m_Towers) {
} 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());
} }
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;
} }
void World::tickMobs(std::uint64_t delta) { TowerPtr World::RemoveTower(TowerID towerId) {
for (MobPtr mob : m_Mobs) { auto it = std::find_if(m_Towers.begin(), m_Towers.end(), [towerId](TowerPtr tower) { return tower->GetID() == towerId;});
mob->tick(delta); if (it == m_Towers.end()) return nullptr;
}
TowerPtr tower = *it;
m_Towers.erase(it);
return tower;
} }
void World::changeMobDirection(MobPtr mob, WalkableTilePtr tile) { void World::TickMobs(std::uint64_t delta) {
if (mob->getDirection() == tile->direction) return; for (MobPtr mob : m_Mobs) {
mob->Tick(delta, this);
float tileX = static_cast<float>(static_cast<std::int32_t>(mob->getCenterX())); }
float tileY = static_cast<float>(static_cast<std::int32_t>(mob->getCenterY()));
switch (mob->getDirection()) {
case Direction::PositiveY: {
if (tile->direction == Direction::NegativeX) {
if (mob->getTileY() > mob->getTileX()) {
mob->setCenterY(tileY + mob->getTileX());
mob->setDirection(tile->direction);
}
} else { // tile->direction = Direction::PositiveX
if (mob->getTileY() > 1 - mob->getTileX()) {
mob->setCenterY(tileY + (1 - mob->getTileX()));
mob->setDirection(tile->direction);
}
}
return;
}
case Direction::NegativeY: {
if (tile->direction == Direction::PositiveX) {
if (mob->getTileY() < mob->getTileX()) {
mob->setCenterY(tileY + mob->getTileX());
mob->setDirection(tile->direction);
}
} else { // tile->direction = Direction::NegativeX
if (mob->getTileY() < 1 - mob->getTileX()) {
mob->setCenterY(tileY + (1 - mob->getTileX()));
mob->setDirection(tile->direction);
}
}
return;
}
case Direction::PositiveX: {
if (tile->direction == Direction::NegativeY) {
if (mob->getTileX() > mob->getTileY()) {
mob->setCenterX(tileX + mob->getTileY());
mob->setDirection(tile->direction);
}
} else { // tile->direction = Direction::PositiveY
if (mob->getTileX() > 1 - mob->getTileY()) {
mob->setCenterX(tileX + (1 - mob->getTileY()));
mob->setDirection(tile->direction);
}
}
return;
}
case Direction::NegativeX: {
if (tile->direction == Direction::PositiveY) {
if (mob->getTileX() < mob->getTileY()) {
mob->setCenterX(tileX + mob->getTileY());
mob->setDirection(tile->direction);
}
} else { // tile->direction = Direction::NegativeY
if (mob->getTileX() < 1 - mob->getTileY()) {
mob->setCenterX(tileX + (1 - mob->getTileY()));
mob->setDirection(tile->direction);
}
}
return;
}
}
} }
void World::moveMobs(std::uint64_t delta) { const Color* World::GetTileColor(TilePtr tile) const {
for (MobPtr mob : m_Mobs) { switch (tile->GetType()) {
TilePtr tile = getTile(mob->getCenter().getX(), mob->getCenter().getY()); case TileType::Tower: {
TowerTile* towerTile = dynamic_cast<TowerTile*>(tile.get());
if (tile != nullptr && tile->getType() == TileType::Walk) { return &m_TowerPlacePalette[towerTile->color_palette_ref];
WalkableTilePtr walkTile = std::static_pointer_cast<WalkableTile>(tile); }
changeMobDirection(mob, walkTile); case TileType::Walk: {
} return &m_WalkablePalette;
}
if (mob->hasReachedEnemyCastle()) continue; case TileType::Decoration: {
DecorationTile* towerTile = dynamic_cast<DecorationTile*>(tile.get());
moveMob(mob, delta); return &m_DecorationPalette[towerTile->color_palette_ref];
break;
TeamColor mobTeam = m_Game->getPlayerById(mob->getSender()).getTeamColor(); }
default: {
const TeamCastle* enemyCastle = nullptr; return nullptr;
}
if (mobTeam == TeamColor::Red) { }
enemyCastle = &getBlueTeam().getCastle(); return nullptr;
} else if (mobTeam == TeamColor::Blue) {
enemyCastle = &getRedTeam().getCastle();
}
if (isMobTouchingCastle(mob, *enemyCastle)) {
moveBackMob(mob, *enemyCastle);
mob->setMobReachedCastle();
}
}
} }
void World::moveMob(MobPtr mob, std::uint64_t delta) { bool World::CanPlaceLittleTower(const Vec2f& worldPos, PlayerID playerID) const {
float mobWalkSpeed = mob->getStats()->getMovementSpeed(); TilePtr tile = GetTile(worldPos.x, worldPos.y);
const Player& player = m_Game->GetPlayers()[playerID];
float walkAmount = mobWalkSpeed * ((float)delta / 1000.0f); if (tile == nullptr) {
return false;
}
if (mob->hasEffect(EffectType::Slowness)) if (tile->GetType() == game::TileType::Tower) {
walkAmount *= 0.70; // walk 30% slower const TowerTile* towerTile = dynamic_cast<TowerTile*>(tile.get());
if (towerTile->team_owner != player.GetTeamColor())
return false;
for (int x = -1; x < 2; x++) {
for (int y = -1; y < 2; 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) {
return false;
}
}
}
return true;
}
switch (mob->getDirection()) { return false;
case Direction::NegativeX: {
mob->setCenterX(mob->getCenterX() - walkAmount);
break;
}
case Direction::PositiveX: {
mob->setCenterX(mob->getCenterX() + walkAmount);
break;
}
case Direction::NegativeY: {
mob->setCenterY(mob->getCenterY() - walkAmount);
break;
}
case Direction::PositiveY: {
mob->setCenterY(mob->getCenterY() + walkAmount);
break;
}
}
} }
bool World::isMobTouchingCastle(MobPtr mob, const TeamCastle& enemyCastle) const { bool World::CanPlaceBigTower(const Vec2f& worldPos, PlayerID playerID) const {
return enemyCastle.collidesWith(*mob); if (!CanPlaceLittleTower(worldPos, playerID)) return false;
TilePtr tile = GetTile(worldPos.x, worldPos.y);
const Player& player = m_Game->GetPlayers()[playerID];
if (tile == nullptr) {
return false;
}
if (tile->GetType() == game::TileType::Tower) {
const TowerTile* towerTile = dynamic_cast<const TowerTile*>(tile.get());
if (towerTile->team_owner != player.GetTeamColor())
return false;
for (int x = -2; x < 3; x++) {
for (int y = -2; y < 3; 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) {
return false;
}
}
}
return true;
}
return false;
} }
void World::moveBackMob(MobPtr mob, const TeamCastle& enemyCastle) { void World::CleanDeadMobs() {
switch (mob->getDirection()) { // safely remove mobs when unused
case Direction::NegativeX: { for (std::size_t i = 0; i < m_Mobs.size(); i++) {
mob->setCenterX(enemyCastle.getBottomRight().getX() + mob->getWidth() / 2.0f); MobPtr mob = m_Mobs[i];
break; if (mob->IsDead()) {
} m_Mobs.erase(m_Mobs.begin() + static_cast<int>(i));
case Direction::PositiveX: { }
mob->setCenterX(enemyCastle.getTopLeft().getX() - mob->getWidth() / 2.0f); }
break;
}
case Direction::NegativeY: {
mob->setCenterY(enemyCastle.getBottomRight().getY() + mob->getHeight() / 2.0f);
break;
}
case Direction::PositiveY: {
mob->setCenterY(enemyCastle.getTopLeft().getY() - mob->getHeight() / 2.0f);
break;
}
}
} }
const Color* World::getTileColor(TilePtr tile) const { TowerPtr World::GetTower(const Vec2f& position) const {
switch (tile->getType()) { for (TowerPtr tower : m_Towers) {
case TileType::Tower: { if (tower->GetSize() == TowerSize::Big) {
TowerTile* towerTile = (TowerTile*)tile.get(); if (tower->GetCenterX() - 2.5f < position.x && tower->GetCenterX() + 2.5f > position.x &&
return &m_TowerPlacePalette[towerTile->color_palette_ref]; tower->GetCenterY() - 2.5f < position.y && tower->GetCenterY() + 2.5f > position.y) {
} return tower;
case TileType::Walk: { }
return &m_WalkablePalette; } else { // little tower
} if (tower->GetCenterX() - 1.5f < position.x && tower->GetCenterX() + 1.5f > position.x &&
case TileType::Decoration: { tower->GetCenterY() - 1.5f < position.y && tower->GetCenterY() + 1.5f > position.y) {
DecorationTile* towerTile = (DecorationTile*)tile.get(); return tower;
return &m_DecorationPalette[towerTile->color_palette_ref]; }
break; }
} }
case TileType::None: { return nullptr;
return nullptr;
}
}
return nullptr;
} }
bool World::CanPlaceLittleTower(const glm::vec2& worldPos, PlayerID playerID) const { TowerPtr World::GetTowerById(TowerID towerID) {
TilePtr tile = getTile(worldPos.x, worldPos.y); auto it = std::find_if(m_Towers.begin(), m_Towers.end(), [towerID](TowerPtr tower) { return tower->GetID() == towerID;});
const Player& player = m_Game->getPlayers()[playerID]; if (it == m_Towers.end()) return nullptr;
return *it;
if (tile == nullptr) {
return false;
}
if (tile->getType() == game::TileType::Tower) {
const TowerTile* towerTile = (const TowerTile*)tile.get();
if (towerTile->team_owner != player.getTeamColor())
return false;
for (int x = -1; x < 2; x++) {
for (int y = -1; y < 2; 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) {
return false;
}
}
}
return true;
}
return false;
} }
bool World::CanPlaceBigTower(const glm::vec2& worldPos, PlayerID playerID) const { void World::OnArcherTowerShot(MobPtr tarGet, ArcherTower* shooter) {
if (!CanPlaceLittleTower(worldPos, playerID)) return false; bool fireArrows = shooter->GetLevel().GetPath() == TowerPath::Bottom;
bool explosiveArrows = shooter->GetLevel().GetLevel() == 4 && fireArrows;
TilePtr tile = getTile(worldPos.x, worldPos.y); GetWorldNotifier().NotifyListeners(&WorldListener::OnArrowShot, tarGet, fireArrows, shooter);
const Player& player = m_Game->getPlayers()[playerID]; if (explosiveArrows) {
GetWorldNotifier().NotifyListeners(&WorldListener::OnExplosion, utils::shape::Circle{ tarGet->GetCenterX(), tarGet->GetCenterY(), ArcherTower::ExplosionRadius }, shooter->GetStats()->GetDamage(), shooter);
if (tile == nullptr) { }
return false;
}
if (tile->getType() == game::TileType::Tower) {
const TowerTile* towerTile = (const TowerTile*)tile.get();
if (towerTile->team_owner != player.getTeamColor())
return false;
for (int x = -2; x < 3; x++) {
for (int y = -2; y < 3; 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) {
return false;
}
}
}
return true;
}
return false;
} }
void World::cleanDeadMobs() { void World::OnArrowShot(MobPtr tarGet, bool fireArrow, Tower* shooter) {
for (std::size_t i = 0; i < m_Mobs.size(); i++) { GetMobNotifier().NotifyListeners(&MobListener::OnMobDamage, tarGet.get(), shooter->GetStats()->GetDamage(), shooter);
MobPtr mob = m_Mobs[i]; if (fireArrow) {
if (mob->isDead()) { tarGet->AddEffect(EffectType::Fire, ArcherTower::FireDurationSec, shooter);
if (mob->OnDeath(this)) { }
//reward players
Player& sender = m_Game->getPlayerById(mob->getSender());
sender.addExp(mob->getStats()->getExpReward());
Player& killer = m_Game->getPlayerById(mob->getLastDamageTower()->getBuilder());
killer.addGold(mob->getStats()->getMoneyCost());
m_Mobs.erase(m_Mobs.begin() + i);
}
}
}
}
TowerPtr World::getTower(const glm::vec2& position) const {
for (TowerPtr tower : m_Towers) {
if (tower->getSize() == TowerSize::Big) {
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) {
return tower;
}
} else { // little tower
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) {
return tower;
}
}
}
return nullptr;
}
TowerPtr World::getTowerById(TowerID towerID) {
auto it = std::find_if(m_Towers.begin(), m_Towers.end(), [towerID](TowerPtr tower) { return tower->getID() == towerID;});
if (it == m_Towers.end()) return nullptr;
return *it;
}
void World::OnArcherTowerShot(MobPtr target, ArcherTower* shooter) {
bool explosiveArrows = shooter->getLevel().getPath() == TowerPath::Bottom;
notifyListeners(&WorldListener::OnArrowShot, target, shooter);
if (explosiveArrows) {
notifyListeners(&WorldListener::OnExplosion, utils::shape::Circle{ target->getCenterX(), target->getCenterY(), ArcherTower::ExplosionRadius }, shooter->getStats()->getDamage(), shooter);
}
}
void World::OnArrowShot(MobPtr target, Tower* shooter) {
notifyListeners(&WorldListener::OnMobDamage, target, shooter->getStats()->getDamage(), 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;
notifyListeners(&WorldListener::OnMobDamage, mob, explosionDamage, shooter); GetMobNotifier().NotifyListeners(&MobListener::OnMobDamage, mob.get(), explosionDamage, shooter);
} }
} }
} }
void World::OnMobDamage(MobPtr target, float damage, Tower* source) { void World::OnMobCastleDamage(Mob* damager, TeamCastle* enemyCastle, float damage) {
target->damage(damage, source); enemyCastle->Damage(damage);
if (target->isDead()) { if (enemyCastle->GetLife() <= 0) {
notifyListeners(&WorldListener::OnMobDead, target); m_Game->NotifyListeners(&GameListener::OnGameEnd);
} }
} }
Team& World::getRedTeam() { void World::OnMobDamage(Mob* tarGet, float damage, Tower* source) {
return m_Game->getRedTeam(); tarGet->Damage(damage, source);
if (tarGet->IsDead()) {
GetMobNotifier().NotifyListeners(&MobListener::OnMobDie, tarGet);
}
} }
const Team& World::getRedTeam() const { Team& World::GetRedTeam() {
return m_Game->getRedTeam(); return m_Game->GetRedTeam();
} }
Team& World::getBlueTeam() { const Team& World::GetRedTeam() const {
return m_Game->getBlueTeam(); return m_Game->GetRedTeam();
} }
const Team& World::getBlueTeam() const { Team& World::GetBlueTeam() {
return m_Game->getBlueTeam(); return m_Game->GetBlueTeam();
} }
Team& World::getTeam(TeamColor team) { const Team& World::GetBlueTeam() const {
return m_Game->getTeam(team); return m_Game->GetBlueTeam();
} }
const Team& World::getTeam(TeamColor team) const { Team& World::GetTeam(TeamColor team) {
return m_Game->getTeam(team); return m_Game->GetTeam(team);
}
const Team& World::GetTeam(TeamColor team) const {
return m_Game->GetTeam(team);
}
const Player* World::GetPlayerById(PlayerID id) const {
return m_Game->GetPlayerById(id);
}
const TeamList& World::GetTeams() const {
return m_Game->GetTeams();
} }
} // namespace game } // namespace game

View File

@@ -1,67 +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()));
} else { Reset();
m_Game.tick(delta); } else {
} m_Game->Tick(delta);
}
} }
void Client::render() { void Client::Render() {
m_Game.renderWorld(); m_Game->RenderWorld();
} }
void Client::sendMobs(const std::vector<protocol::MobSend>& mobSends) { void Client::Reset() {
protocol::SendMobsPacket packet(mobSends); m_Game.reset(0);
m_Connexion.sendPacket(&packet); m_Game = std::make_unique<ClientGame>(this);
} }
void Client::placeTower(game::TowerType type, const glm::vec2& position) { void Client::SendMobs(const std::vector<protocol::MobSend>& mobSends) {
protocol::PlaceTowerPacket packet(position.x, position.y, type); protocol::SendMobsPacket packet(mobSends);
m_Connexion.sendPacket(&packet); m_Connexion.SendPacket(&packet);
} }
void Client::upgradeTower(game::TowerID tower, game::TowerLevel level) { void Client::PlaceTower(game::TowerType type, const Vec2f& position) {
protocol::UpgradeTowerPacket packet(tower, level); 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) {
protocol::UpgradeTowerPacket packet(tower, level);
m_Connexion.SendPacket(&packet);
}
void Client::RemoveTower(game::TowerID tower) {
protocol::RemoveTowerPacket packet(tower);
m_Connexion.SendPacket(&packet);
} }
} // namespace client } // namespace client

View File

@@ -4,44 +4,45 @@
namespace td { namespace td {
namespace client { namespace client {
ClientConnexion::ClientConnexion() : Connexion(&m_Dispatcher) { 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

@@ -1,119 +1,117 @@
#include "game/client/ClientGame.h" #include "game/client/ClientGame.h"
#include "protocol/PacketDispatcher.h" #include "protocol/PacketDispatcher.h"
//#include "game/Team.h"
#include "game/client/Client.h" #include "game/client/Client.h"
#include <iostream>
namespace td { namespace td {
namespace client { namespace client {
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::WorldAddTower, 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 });
} }
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();
} }
}
void ClientGame::HandlePacket(const protocol::WorldAddTowerPacket* packet) {
m_WorldRenderer.addTower(m_WorldClient.placeTowerAt(packet->getTowerID(), packet->getTowerType(), packet->getTowerX(), packet->getTowerY(), packet->getBuilder()));
} }
} // namespace client } // namespace client

View File

@@ -7,33 +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::WorldBeginData, this); GetDispatcher()->RegisterHandler(protocol::PacketType::WorldAddTower, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::WorldData, this); GetDispatcher()->RegisterHandler(protocol::PacketType::WorldBeginData, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::SpawnMob, this); GetDispatcher()->RegisterHandler(protocol::PacketType::WorldData, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::UpgradeTower, this); GetDispatcher()->RegisterHandler(protocol::PacketType::SpawnMob, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::UpgradeTower, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::RemoveTower, this);
GetDispatcher()->RegisterHandler(protocol::PacketType::UpdateCastleLife, 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) {
const Color& backgroundColor = GetBackgroundColor();
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) });
}
} }
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::OnArrowShot(game::MobPtr target, game::Tower* tower) { void WorldClient::HandlePacket(const protocol::WorldAddTowerPacket* packet) {
World::OnArrowShot(target, tower); game::TowerPtr newTower = PlaceTowerAt(packet->GetTowerID(), packet->GetTowerType(), packet->GetTowerX(), packet->GetTowerY(), packet->GetBuilder());
GetWorldNotifier().NotifyListeners(&WorldListener::OnTowerAdd, newTower);
}
void WorldClient::HandlePacket(const protocol::RemoveTowerPacket* packet) {
game::TowerPtr tower = RemoveTower(packet->GetTowerID());
if (tower != nullptr) {
GetWorldNotifier().NotifyListeners(&WorldListener::OnTowerRemove, tower);
}
}
void WorldClient::HandlePacket(const protocol::UpdateMobStatesPacket* packet) {
for (auto mobState : packet->GetMobStates()) {
game::MobID mobId = mobState.GetMobId();
auto it = std::find_if(GetMobList().begin(), GetMobList().end(), [mobId](game::MobPtr mob) { return mob->GetMobID() == mobId; });
if (it != GetMobList().end()) {
game::MobPtr& mob = *it;
mob->SetCenter(mobState.GetMobPosition());
mob->SetDirection(mobState.GetMobDirection());
mob->SetHealth(mobState.GetMobLife());
}
}
}
void WorldClient::HandlePacket(const protocol::UpdateCastleLifePacket* packet) {
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,68 +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) {
protocol::UpdateGameStatePacket packet(game::GameState::Game); m_Server->GetGame().NotifyListeners(&game::GameListener::OnGameBegin);
m_Server->broadcastPacket(&packet); m_GameStarted = true;
m_GameStarted = true; return;
m_Server->lauchGame(); }
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,135 +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);
} }
void Server::lauchGame() { Server::~Server() {
m_Game.startGame(); if (m_Thread.joinable())
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();
});
} }
void Server::stopThread() { void Server::Close() {
m_ServerRunning = false; StopThread();
if (m_Thread.joinable())
m_Thread.join();
} }
bool Server::start(std::uint16_t port) { void Server::StopThread() {
if (!m_Listener.listen(port, 10)) { m_ServerRunning = false;
std::cout << "Failed to bind port " << port << " !\n";
return false;
}
if (!m_Listener.setBlocking(false)) {
std::cout << "Failed to block server socket !\n";
return false;
}
std::cout << "Server started at port " << port << " !\n";
m_TickCounter.reset();
m_ServerRunning = true;
startThread();
return true;
} }
void Server::stop() { bool Server::Start(std::uint16_t port) {
if (!m_ServerRunning) if (!m_Listener.Listen(port, 10)) {
return; utils::LOGE(utils::format("Failed to bind port %u !", port));
stopThread(); return false;
}
protocol::DisconnectPacket packet("Server closed"); if (!m_Listener.SetBlocking(false)) {
broadcastPacket(&packet); utils::LOGE("Failed to block server socket !");
return false;
m_Listener.close(); }
m_Listener.destroy(); utils::LOG(utils::format("Server started at port %u !", port));
m_TickCounter.Reset();
m_Connections.clear(); m_ServerRunning = true;
getPlayers().clear(); StartThread();
return true;
} }
void Server::tick(std::uint64_t delta) { void Server::Clean() {
accept(); m_Listener.Close();
updateSockets(); m_Listener.Destroy();
m_Lobby.tick();
m_Game.tick(delta); m_Connections.clear();
if (m_TickCounter.update()) { GetPlayers().clear();
protocol::ServerTpsPacket packet(m_TickCounter.getTPS(), utils::getTime());
broadcastPacket(&packet); utils::LOG("Server successfully stopped !");
}
} }
void Server::accept() { void Server::Stop() {
static std::uint8_t newPlayerID = 0; if (!m_ServerRunning)
network::TCPSocket newSocket; return;
if (m_Listener.accept(newSocket)) {
ServerConnexion con(newSocket, newPlayerID); protocol::DisconnectPacket packet("Server closed");
m_Connections.insert(std::move(ConnexionMap::value_type{ newPlayerID, std::move(con) })); BroadcastPacket(&packet);
OnPlayerJoin(newPlayerID);
m_Connections[newPlayerID].setServer(this); StopThread();
newPlayerID++;
}
} }
void Server::updateSockets() { void Server::Tick(std::uint64_t delta) {
std::int16_t closedConnexionID = -1; Accept();
for (auto& connection : m_Connections) { UpdateSockets();
ServerConnexion& con = connection.second; m_Lobby.Tick();
if (con.getSocketStatus() != network::Socket::Status::Connected) { m_Game.Tick(delta);
closedConnexionID = connection.first; if (m_TickCounter.Update()) {
} else { protocol::ServerTpsPacket packet(m_TickCounter.GetTPS(), m_TickCounter.GetMSPT(), utils::GetTime());
con.updateSocket(); BroadcastPacket(&packet);
} }
}
if (closedConnexionID != -1) {
removeConnexion(closedConnexionID);
}
} }
void Server::broadcastPacket(const protocol::Packet* packet) { void Server::Accept() {
for (auto& connection : m_Connections) { static std::uint8_t newPlayerID = 0;
ServerConnexion& con = connection.second; network::TCPSocket newSocket;
con.sendPacket(packet); if (m_Listener.Accept(newSocket)) {
} ServerConnexion con(newSocket, newPlayerID);
m_Connections.insert(std::move(ConnexionMap::value_type{ newPlayerID, std::move(con) }));
OnPlayerJoin(newPlayerID);
m_Connections[newPlayerID].SetServer(this);
newPlayerID++;
}
} }
void Server::removeConnexion(std::uint8_t connexionID) { void Server::UpdateSockets() {
getPlayers().erase(getPlayers().find(connexionID)); std::int16_t closedConnexionID = -1;
m_Connections.erase(connexionID); for (auto& connection : m_Connections) {
m_Lobby.OnPlayerLeave(connexionID); ServerConnexion& con = connection.second;
OnPlayerLeave(connexionID); if (con.GetSocketStatus() != network::Socket::Status::Connected) {
closedConnexionID = connection.first;
} else {
con.UpdateSocket();
}
}
if (closedConnexionID != -1) {
RemoveConnexion(closedConnexionID);
}
}
void Server::BroadcastPacket(const protocol::Packet* packet) {
for (auto& connection : m_Connections) {
ServerConnexion& con = connection.second;
con.SendPacket(packet);
}
}
void Server::RemoveConnexion(std::uint8_t connexionID) {
GetPlayers().erase(GetPlayers().find(connexionID));
m_Connections.erase(connexionID);
m_Lobby.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,165 +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);
} }
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));
protocol::WorldAddTowerPacket addTowerPacket(tower->getID(), packet->getTowerX(), packet->getTowerY(), packet->getTowerType(), m_ID); game::TowerPtr tower = world->PlaceTowerAt(towerType, packet->GetTowerX(), packet->GetTowerY(), m_ID);
m_Server->broadcastPacket(&addTowerPacket);
world->GetWorldNotifier().NotifyListeners(&game::WorldListener::OnTowerAdd, tower);
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) {
//TODO: verify the 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

@@ -4,70 +4,117 @@
namespace td { 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_MobStatesTimer{ 5000, std::bind(&ServerGame::UpdateMobStates, this) },
m_EndGameCooldown{ 1000 * 10 } {
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);
updatePlayerStats(); m_MobStatesTimer.Update(delta);
} UpdatePlayerStats();
} else if (m_GameState == game::GameState::EndGame) {
if (m_EndGameCooldown.Update(delta)) {
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::balanceTeams() { void ServerGame::UpdateGoldMines() {
for (auto& playerInfo : Game::m_Players) { for (auto& [id, player] : m_Server->GetPlayers()) {
game::Player& player = playerInfo.second; player.AddGold(player.getUpgrades().GetGoldPerSecond());
if (player.getTeamColor() == game::TeamColor::None) {
game::Team& redTeam = getRedTeam(); // Update player money and exp every second
game::Team& blueTeam = getBlueTeam(); protocol::UpdateMoneyPacket moneyPacket(player.GetGold());
if (blueTeam.getPlayerCount() > redTeam.getPlayerCount()) { m_Server->GetConnexions()[player.GetID()].SendPacket(&moneyPacket);
player.setTeamColor(game::TeamColor::Red);
redTeam.addPlayer(&player); protocol::UpdateExpPacket expPacket(player.GetExp());
} else { m_Server->GetConnexions()[player.GetID()].SendPacket(&expPacket);
player.setTeamColor(game::TeamColor::Blue); }
blueTeam.addPlayer(&player); }
}
protocol::UpdatePlayerTeamPacket packet(player.getID(), player.getTeamColor()); void ServerGame::UpdateMobStates() {
m_Server->broadcastPacket(&packet); protocol::UpdateMobStatesPacket packet;
} for (auto mob : m_World->GetMobList()) {
} packet.addMobState({ mob->GetMobID(), mob->GetCenter(), mob->GetHealth(), mob->GetDirection() });
}
m_Server->BroadcastPacket(&packet);
}
void ServerGame::BalanceTeams() {
for (auto& playerInfo : Game::m_Players) {
game::Player& player = playerInfo.second;
if (player.GetTeamColor() == game::TeamColor::None) {
game::Team& redTeam = GetRedTeam();
game::Team& blueTeam = GetBlueTeam();
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) {
SetGameState(newState);
protocol::UpdateGameStatePacket packet(newState);
m_Server->BroadcastPacket(&packet);
}
void ServerGame::OnGameBegin() {
NotifyListeners(&game::GameListener::OnGameStateUpdate, game::GameState::Game);
StartGame();
}
void ServerGame::OnGameEnd() {
NotifyListeners(&game::GameListener::OnGameStateUpdate, game::GameState::EndGame);
m_EndGameCooldown.ApplyCooldown();
}
void ServerGame::OnGameClose() {
NotifyListeners(&game::GameListener::OnGameStateUpdate, game::GameState::Closed);
// Disconnect clients
protocol::DisconnectPacket packet("Game finished");
m_Server->BroadcastPacket(&packet);
// Closing server
m_Server->Close();
} }
} // namespace game } // namespace game

View File

@@ -11,46 +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();
} }
std::int32_t spawnCenterX = enemyMobSpawn->getCenterX(); float spawnWidth = enemyMobSpawn->GetWidth();
std::int32_t spawnCenterY = enemyMobSpawn->getCenterY(); float spawnHeight = enemyMobSpawn->GetHeight();
std::int32_t minSpawnY = spawnCenterY - 2; float spawnCenterX = enemyMobSpawn->GetCenterX();
std::int32_t maxSpawnY = spawnCenterY + 2; float spawnCenterY = enemyMobSpawn->GetCenterY();
std::int32_t minSpawnX = spawnCenterX - 2; auto mobStats = GetMobStats(type, level);
std::int32_t maxSpawnX = spawnCenterX + 2; auto mobSize = mobStats->GetSize();
float mobX = utils::getRandomReal<float>(minSpawnX, maxSpawnX); float minSpawnX = spawnCenterX - spawnWidth / 2.0f + mobSize.x / 2.0f;
float mobY = utils::getRandomReal<float>(minSpawnY, maxSpawnY); float maxSpawnX = spawnCenterX + spawnWidth / 2.0f - mobSize.x / 2.0f;
spawnMobAt(m_CurrentMobID, type, level, sender, mobX, mobY, enemyMobSpawn->getDirection()); float minSpawnY = spawnCenterY - spawnHeight / 2.0f + mobSize.y / 2.0f;
float maxSpawnY = spawnCenterY + spawnHeight / 2.0f - mobSize.y / 2.0f;
protocol::SpawnMobPacket packet(m_CurrentMobID, type, level, sender, mobX, mobY, enemyMobSpawn->getDirection()); float mobX = utils::GetRandomReal<float>(minSpawnX + MobSpawnBorder, maxSpawnX - MobSpawnBorder);
m_Server->broadcastPacket(&packet); float mobY = utils::GetRandomReal<float>(minSpawnY + MobSpawnBorder, maxSpawnY - MobSpawnBorder);
m_CurrentMobID++; SpawnMobAt(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_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::OnArrowShot(game::MobPtr target, game::Tower* shooter) { void ServerWorld::OnMobDie(game::Mob* mob) {
World::OnArrowShot(target, shooter); if (mob->OnDeath(this)) { // check if the mob is actually dead (slimes ...)
//reward players
game::Player* sender = m_Game->GetPlayerById(mob->GetSender());
sender->AddExp(mob->GetStats()->GetExpReward());
game::Player* killer = m_Game->GetPlayerById(mob->GetLastDamageTower()->GetBuilder());
killer->AddGold(mob->GetStats()->GetMoneyCost());
}
}
void ServerWorld::OnMobCastleDamage(game::Mob* damager, game::TeamCastle* enemyCastle, float damage) {
// calling base class event
World::OnMobCastleDamage(damager, enemyCastle, damage);
protocol::UpdateCastleLifePacket packet(enemyCastle->GetLife(), enemyCastle->GetTeam()->GetColor());
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

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