indent with tabs
This commit is contained in:
@@ -12,25 +12,25 @@ Game::~Game() {
|
||||
}
|
||||
|
||||
void Game::Tick(std::uint64_t delta) {
|
||||
if (m_GameState == GameState::Game) {
|
||||
m_World->Tick(delta);
|
||||
}
|
||||
if (m_GameState == GameState::Game) {
|
||||
m_World->Tick(delta);
|
||||
}
|
||||
}
|
||||
|
||||
Player* Game::GetPlayerById(PlayerID id) {
|
||||
auto it = m_Players.find(id);
|
||||
auto it = m_Players.find(id);
|
||||
|
||||
if (it == m_Players.end()) return nullptr;
|
||||
if (it == m_Players.end()) return nullptr;
|
||||
|
||||
return &it->second;
|
||||
return &it->second;
|
||||
}
|
||||
|
||||
const Player* Game::GetPlayerById(PlayerID id) const {
|
||||
auto it = m_Players.find(id);
|
||||
auto it = m_Players.find(id);
|
||||
|
||||
if (it == m_Players.end()) return nullptr;
|
||||
if (it == m_Players.end()) return nullptr;
|
||||
|
||||
return &it->second;
|
||||
return &it->second;
|
||||
}
|
||||
|
||||
} // namespace game
|
||||
|
||||
@@ -29,44 +29,44 @@ Connexion::Connexion(protocol::PacketDispatcher* dispatcher, network::TCPSocket&
|
||||
}
|
||||
|
||||
bool Connexion::UpdateSocket() {
|
||||
if (m_Socket.GetStatus() != network::Socket::Connected)
|
||||
return false;
|
||||
if (m_Socket.GetStatus() != network::Socket::Connected)
|
||||
return false;
|
||||
|
||||
while (true) {
|
||||
DataBuffer buffer;
|
||||
m_Socket.Receive(buffer, sizeof(std::uint64_t));
|
||||
if (buffer.GetSize() == 0)
|
||||
break;
|
||||
std::uint64_t packetLenght;
|
||||
buffer >> packetLenght;
|
||||
while (true) {
|
||||
DataBuffer buffer;
|
||||
m_Socket.Receive(buffer, sizeof(std::uint64_t));
|
||||
if (buffer.GetSize() == 0)
|
||||
break;
|
||||
std::uint64_t 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;
|
||||
decompressed >> packetType;
|
||||
protocol::PacketType packetType;
|
||||
decompressed >> packetType;
|
||||
|
||||
PacketPtr packet = protocol::PacketFactory::CreatePacket(packetType, decompressed);
|
||||
GetDispatcher()->Dispatch(packet);
|
||||
}
|
||||
return true;
|
||||
PacketPtr packet = protocol::PacketFactory::CreatePacket(packetType, decompressed);
|
||||
GetDispatcher()->Dispatch(packet);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Connexion::Connect(const std::string& address, std::uint16_t port) {
|
||||
if (!m_Socket.Connect(address, port)) {
|
||||
return false;
|
||||
}
|
||||
m_Socket.SetBlocking(false);
|
||||
return true;
|
||||
if (!m_Socket.Connect(address, port)) {
|
||||
return false;
|
||||
}
|
||||
m_Socket.SetBlocking(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Connexion::SendPacket(const protocol::Packet* packet) {
|
||||
network::SendPacket(packet->Serialize(), m_Socket);
|
||||
network::SendPacket(packet->Serialize(), m_Socket);
|
||||
}
|
||||
|
||||
void Connexion::CloseConnection() {
|
||||
m_Socket.Disconnect();
|
||||
m_Socket.Disconnect();
|
||||
}
|
||||
|
||||
Connexion::~Connexion() {
|
||||
|
||||
@@ -9,251 +9,251 @@ namespace td {
|
||||
namespace game {
|
||||
|
||||
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) {
|
||||
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) {
|
||||
return *std::find_if(m_Effects.begin(), m_Effects.end(), [&effectType](EffectDuration effect) { return effect.type == effectType;});
|
||||
return *std::find_if(m_Effects.begin(), m_Effects.end(), [&effectType](EffectDuration effect) { return effect.type == effectType;});
|
||||
}
|
||||
|
||||
void Mob::AddEffect(EffectType effectType, float durationSec, Tower* tower) {
|
||||
if (IsImmuneTo(effectType))
|
||||
return;
|
||||
if (HasEffect(effectType)) {
|
||||
EffectDuration& effect = GetEffect(effectType);
|
||||
if (effect.duration < durationSec)
|
||||
effect.duration = durationSec; // Setting new duration if it's greater then the actual
|
||||
} else {
|
||||
m_Effects.push_back({ effectType, durationSec, tower });
|
||||
}
|
||||
if (IsImmuneTo(effectType))
|
||||
return;
|
||||
if (HasEffect(effectType)) {
|
||||
EffectDuration& effect = GetEffect(effectType);
|
||||
if (effect.duration < durationSec)
|
||||
effect.duration = durationSec; // Setting new duration if it's greater then the actual
|
||||
} else {
|
||||
m_Effects.push_back({ effectType, durationSec, tower });
|
||||
}
|
||||
}
|
||||
|
||||
void Mob::AttackCastle(std::uint64_t delta, World* world) {
|
||||
if (!HasReachedEnemyCastle()) return;
|
||||
if (!HasReachedEnemyCastle()) return;
|
||||
|
||||
if (m_AttackTimer.Update(delta)) {
|
||||
world->GetMobNotifier().NotifyListeners(&MobListener::OnMobCastleDamage, this, m_CastleTarget, GetStats()->GetDamage());
|
||||
m_AttackTimer.ApplyCooldown();
|
||||
}
|
||||
if (m_AttackTimer.Update(delta)) {
|
||||
world->GetMobNotifier().NotifyListeners(&MobListener::OnMobCastleDamage, this, m_CastleTarget, GetStats()->GetDamage());
|
||||
m_AttackTimer.ApplyCooldown();
|
||||
}
|
||||
}
|
||||
|
||||
void Mob::Walk(std::uint64_t delta, World* world) {
|
||||
float mobWalkSpeed = GetStats()->GetMovementSpeed();
|
||||
float mobWalkSpeed = GetStats()->GetMovementSpeed();
|
||||
|
||||
float walkAmount = mobWalkSpeed * (static_cast<float>(delta) / 1000.0f);
|
||||
float walkAmount = mobWalkSpeed * (static_cast<float>(delta) / 1000.0f);
|
||||
|
||||
if (HasEffect(EffectType::Slowness))
|
||||
walkAmount *= 0.70; // walk 30% slower
|
||||
if (HasEffect(EffectType::Slowness))
|
||||
walkAmount *= 0.70; // walk 30% slower
|
||||
|
||||
switch (GetDirection()) {
|
||||
case Direction::NegativeX: {
|
||||
SetCenterX(GetCenterX() - walkAmount);
|
||||
break;
|
||||
}
|
||||
case Direction::PositiveX: {
|
||||
SetCenterX(GetCenterX() + walkAmount);
|
||||
break;
|
||||
}
|
||||
case Direction::NegativeY: {
|
||||
SetCenterY(GetCenterY() - walkAmount);
|
||||
break;
|
||||
}
|
||||
case Direction::PositiveY: {
|
||||
SetCenterY(GetCenterY() + walkAmount);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
switch (GetDirection()) {
|
||||
case Direction::NegativeX: {
|
||||
SetCenterX(GetCenterX() - walkAmount);
|
||||
break;
|
||||
}
|
||||
case Direction::PositiveX: {
|
||||
SetCenterX(GetCenterX() + walkAmount);
|
||||
break;
|
||||
}
|
||||
case Direction::NegativeY: {
|
||||
SetCenterY(GetCenterY() - walkAmount);
|
||||
break;
|
||||
}
|
||||
case Direction::PositiveY: {
|
||||
SetCenterY(GetCenterY() + walkAmount);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Mob::Move(std::uint64_t delta, World* world) {
|
||||
TilePtr tile = world->GetTile(GetCenter().GetX(), GetCenter().GetY());
|
||||
TilePtr tile = world->GetTile(GetCenter().GetX(), GetCenter().GetY());
|
||||
|
||||
if (tile != nullptr && tile->GetType() == TileType::Walk) {
|
||||
WalkableTilePtr walkTile = std::static_pointer_cast<WalkableTile>(tile);
|
||||
ChangeDirection(*walkTile, world);
|
||||
}
|
||||
if (tile != nullptr && tile->GetType() == TileType::Walk) {
|
||||
WalkableTilePtr walkTile = std::static_pointer_cast<WalkableTile>(tile);
|
||||
ChangeDirection(*walkTile, world);
|
||||
}
|
||||
|
||||
if (HasReachedEnemyCastle()) return;
|
||||
if (HasReachedEnemyCastle()) return;
|
||||
|
||||
Walk(delta, world);
|
||||
Walk(delta, world);
|
||||
|
||||
TeamColor mobTeam = world->GetPlayerById(GetSender())->GetTeamColor();
|
||||
TeamColor mobTeam = world->GetPlayerById(GetSender())->GetTeamColor();
|
||||
|
||||
TeamCastle* enemyCastle = nullptr;
|
||||
TeamCastle* enemyCastle = nullptr;
|
||||
|
||||
if (mobTeam == TeamColor::Red) {
|
||||
enemyCastle = &world->GetBlueTeam().GetCastle();
|
||||
} else if (mobTeam == TeamColor::Blue) {
|
||||
enemyCastle = &world->GetRedTeam().GetCastle();
|
||||
}
|
||||
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);
|
||||
if (IsTouchingCastle(*enemyCastle)) {
|
||||
MoveBack(*enemyCastle, world);
|
||||
SetMobReachedCastle(enemyCastle);
|
||||
|
||||
world->GetMobNotifier().NotifyListeners(&MobListener::OnMobTouchCastle, this, 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;
|
||||
}
|
||||
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;
|
||||
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()));
|
||||
float tileX = static_cast<float>(static_cast<std::int32_t>(GetCenterX()));
|
||||
float tileY = static_cast<float>(static_cast<std::int32_t>(GetCenterY()));
|
||||
|
||||
switch (GetDirection()) {
|
||||
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::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::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::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;
|
||||
}
|
||||
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;
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Mob::IsTouchingCastle(const TeamCastle& enemyCastle) const {
|
||||
return enemyCastle.CollidesWith(*this);
|
||||
return enemyCastle.CollidesWith(*this);
|
||||
}
|
||||
|
||||
void Mob::Tick(std::uint64_t delta, World* world) {
|
||||
UpdateEffects(delta, world);
|
||||
Move(delta, world);
|
||||
AttackCastle(delta, world);
|
||||
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;
|
||||
}
|
||||
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::Poison: {
|
||||
m_EffectPoisonTimer.Reset();
|
||||
break;
|
||||
}
|
||||
|
||||
case EffectType::Heal: {
|
||||
m_EffectHealTimer.Reset();
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
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();
|
||||
return std::find_if(m_Effects.begin(), m_Effects.end(), [&type](EffectDuration effect) { return effect.type == type;}) != m_Effects.end();
|
||||
}
|
||||
|
||||
|
||||
@@ -262,248 +262,248 @@ bool Mob::HasEffect(EffectType type) {
|
||||
typedef std::pair<MobType, std::uint8_t> MobKey;
|
||||
|
||||
static const std::map<MobKey, MobStats> MobConstants = {
|
||||
// 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, 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, 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}}},
|
||||
// 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, 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, 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::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, 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, 5},{MobStats{1.5, 2.5, {1, 1}, 52, 938, 22, 307}}},
|
||||
{{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, 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, 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, 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, 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, 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, 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, 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, 2},{MobStats{1, 2, {1, 1}, 120, 263, 24, 210}}},
|
||||
{{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, 5},{MobStats{1.5, 2, {1, 1}, 207, 1407, 27, 576}}},
|
||||
{{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, 3},{MobStats{1, 2, {1, 1}, 144, 459, 25, 297}}},
|
||||
{{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::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, 3},{MobStats{2, 2, {1, 1}, 350, 800, 55, 630}}},
|
||||
{{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, 1},{MobStats{1, 2, {1, 1}, 250, 325, 46, 350}}},
|
||||
{{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, 4},{MobStats{3, 2, {1, 1}, 420, 1300, 61, 900}}},
|
||||
{{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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 5},{MobStats{50, 0.8, {1, 1}, 6407, 22000, 648, 31640}}},
|
||||
};
|
||||
|
||||
const MobStats* GetMobStats(MobType type, std::uint8_t level) {
|
||||
return &MobConstants.at(MobKey{ type, level });
|
||||
return &MobConstants.at(MobKey{ type, level });
|
||||
}
|
||||
|
||||
static const std::map<MobKey, TowerImmunities> MobsTowerImmunities = {
|
||||
{{MobType::Zombie, 1},{}},
|
||||
{{MobType::Zombie, 2},{}},
|
||||
{{MobType::Zombie, 3},{}},
|
||||
{{MobType::Zombie, 4},{}},
|
||||
{{MobType::Zombie, 5},{}},
|
||||
{{MobType::Zombie, 1},{}},
|
||||
{{MobType::Zombie, 2},{}},
|
||||
{{MobType::Zombie, 3},{}},
|
||||
{{MobType::Zombie, 4},{}},
|
||||
{{MobType::Zombie, 5},{}},
|
||||
|
||||
{{MobType::Spider, 1},{}},
|
||||
{{MobType::Spider, 2},{}},
|
||||
{{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, 5},{TowerType::Archer, TowerType::Artillery, TowerType::Leach, TowerType::Necromancer, TowerType::Poison, TowerType::Quake, TowerType::Sorcerer, TowerType::Turret, TowerType::Zeus}},
|
||||
{{MobType::Spider, 1},{}},
|
||||
{{MobType::Spider, 2},{}},
|
||||
{{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, 5},{TowerType::Archer, TowerType::Artillery, TowerType::Leach, TowerType::Necromancer, TowerType::Poison, TowerType::Quake, TowerType::Sorcerer, TowerType::Turret, TowerType::Zeus}},
|
||||
|
||||
{{MobType::Skeleton, 1},{}},
|
||||
{{MobType::Skeleton, 2},{}},
|
||||
{{MobType::Skeleton, 3},{}},
|
||||
{{MobType::Skeleton, 4},{}},
|
||||
{{MobType::Skeleton, 5},{}},
|
||||
{{MobType::Skeleton, 1},{}},
|
||||
{{MobType::Skeleton, 2},{}},
|
||||
{{MobType::Skeleton, 3},{}},
|
||||
{{MobType::Skeleton, 4},{}},
|
||||
{{MobType::Skeleton, 5},{}},
|
||||
|
||||
{{MobType::Pigman, 1},{TowerType::Zeus}},
|
||||
{{MobType::Pigman, 2},{TowerType::Zeus}},
|
||||
{{MobType::Pigman, 3},{TowerType::Zeus}},
|
||||
{{MobType::Pigman, 4},{TowerType::Zeus}},
|
||||
{{MobType::Pigman, 5},{TowerType::Zeus}},
|
||||
{{MobType::Pigman, 1},{TowerType::Zeus}},
|
||||
{{MobType::Pigman, 2},{TowerType::Zeus}},
|
||||
{{MobType::Pigman, 3},{TowerType::Zeus}},
|
||||
{{MobType::Pigman, 4},{TowerType::Zeus}},
|
||||
{{MobType::Pigman, 5},{TowerType::Zeus}},
|
||||
|
||||
{{MobType::Creeper, 1},{}},
|
||||
{{MobType::Creeper, 2},{}},
|
||||
{{MobType::Creeper, 3},{}},
|
||||
{{MobType::Creeper, 4},{}},
|
||||
{{MobType::Creeper, 5},{}},
|
||||
{{MobType::Creeper, 1},{}},
|
||||
{{MobType::Creeper, 2},{}},
|
||||
{{MobType::Creeper, 3},{}},
|
||||
{{MobType::Creeper, 4},{}},
|
||||
{{MobType::Creeper, 5},{}},
|
||||
|
||||
{{MobType::Silverfish, 1},{}},
|
||||
{{MobType::Silverfish, 2},{}},
|
||||
{{MobType::Silverfish, 3},{}},
|
||||
{{MobType::Silverfish, 4},{}},
|
||||
{{MobType::Silverfish, 5},{}},
|
||||
{{MobType::Silverfish, 1},{}},
|
||||
{{MobType::Silverfish, 2},{}},
|
||||
{{MobType::Silverfish, 3},{}},
|
||||
{{MobType::Silverfish, 4},{}},
|
||||
{{MobType::Silverfish, 5},{}},
|
||||
|
||||
{{MobType::Blaze, 1},{}},
|
||||
{{MobType::Blaze, 2},{}},
|
||||
{{MobType::Blaze, 3},{}},
|
||||
{{MobType::Blaze, 4},{}},
|
||||
{{MobType::Blaze, 5},{}},
|
||||
{{MobType::Blaze, 1},{}},
|
||||
{{MobType::Blaze, 2},{}},
|
||||
{{MobType::Blaze, 3},{}},
|
||||
{{MobType::Blaze, 4},{}},
|
||||
{{MobType::Blaze, 5},{}},
|
||||
|
||||
{{MobType::Witch, 1},{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, 4},{TowerType::Zeus, TowerType::Mage, TowerType::Poison}},
|
||||
{{MobType::Witch, 5},{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, 3},{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::Slime, 1},{}},
|
||||
{{MobType::Slime, 2},{}},
|
||||
{{MobType::Slime, 3},{}},
|
||||
{{MobType::Slime, 4},{}},
|
||||
{{MobType::Slime, 5},{}},
|
||||
{{MobType::Slime, 1},{}},
|
||||
{{MobType::Slime, 2},{}},
|
||||
{{MobType::Slime, 3},{}},
|
||||
{{MobType::Slime, 4},{}},
|
||||
{{MobType::Slime, 5},{}},
|
||||
|
||||
{{MobType::Giant, 1},{}},
|
||||
{{MobType::Giant, 2},{}},
|
||||
{{MobType::Giant, 3},{}},
|
||||
{{MobType::Giant, 4},{}},
|
||||
{{MobType::Giant, 5},{}},
|
||||
{{MobType::Giant, 1},{}},
|
||||
{{MobType::Giant, 2},{}},
|
||||
{{MobType::Giant, 3},{}},
|
||||
{{MobType::Giant, 4},{}},
|
||||
{{MobType::Giant, 5},{}},
|
||||
};
|
||||
|
||||
const TowerImmunities& GetMobTowerImmunities(MobType type, std::uint8_t level) {
|
||||
return MobsTowerImmunities.at({ type, level });
|
||||
return MobsTowerImmunities.at({ type, level });
|
||||
}
|
||||
|
||||
static const std::map<MobKey, EffectImmunities> MobsEffectImmunities = {
|
||||
{{MobType::Zombie, 1},{}},
|
||||
{{MobType::Zombie, 2},{}},
|
||||
{{MobType::Zombie, 3},{}},
|
||||
{{MobType::Zombie, 4},{}},
|
||||
{{MobType::Zombie, 5},{}},
|
||||
{{MobType::Zombie, 1},{}},
|
||||
{{MobType::Zombie, 2},{}},
|
||||
{{MobType::Zombie, 3},{}},
|
||||
{{MobType::Zombie, 4},{}},
|
||||
{{MobType::Zombie, 5},{}},
|
||||
|
||||
{{MobType::Spider, 1},{}},
|
||||
{{MobType::Spider, 2},{}},
|
||||
{{MobType::Spider, 3},{}},
|
||||
{{MobType::Spider, 4},{}},
|
||||
{{MobType::Spider, 5},{}},
|
||||
{{MobType::Spider, 1},{}},
|
||||
{{MobType::Spider, 2},{}},
|
||||
{{MobType::Spider, 3},{}},
|
||||
{{MobType::Spider, 4},{}},
|
||||
{{MobType::Spider, 5},{}},
|
||||
|
||||
{{MobType::Skeleton, 1},{}},
|
||||
{{MobType::Skeleton, 2},{}},
|
||||
{{MobType::Skeleton, 3},{}},
|
||||
{{MobType::Skeleton, 4},{EffectType::Fire}},
|
||||
{{MobType::Skeleton, 5},{EffectType::Fire}},
|
||||
{{MobType::Skeleton, 1},{}},
|
||||
{{MobType::Skeleton, 2},{}},
|
||||
{{MobType::Skeleton, 3},{}},
|
||||
{{MobType::Skeleton, 4},{EffectType::Fire}},
|
||||
{{MobType::Skeleton, 5},{EffectType::Fire}},
|
||||
|
||||
{{MobType::Pigman, 1},{EffectType::Fire}},
|
||||
{{MobType::Pigman, 2},{EffectType::Fire}},
|
||||
{{MobType::Pigman, 3},{EffectType::Fire}},
|
||||
{{MobType::Pigman, 4},{EffectType::Fire}},
|
||||
{{MobType::Pigman, 5},{EffectType::Fire}},
|
||||
{{MobType::Pigman, 1},{EffectType::Fire}},
|
||||
{{MobType::Pigman, 2},{EffectType::Fire}},
|
||||
{{MobType::Pigman, 3},{EffectType::Fire}},
|
||||
{{MobType::Pigman, 4},{EffectType::Fire}},
|
||||
{{MobType::Pigman, 5},{EffectType::Fire}},
|
||||
|
||||
{{MobType::Creeper, 1},{}},
|
||||
{{MobType::Creeper, 2},{}},
|
||||
{{MobType::Creeper, 3},{}},
|
||||
{{MobType::Creeper, 4},{}},
|
||||
{{MobType::Creeper, 5},{}},
|
||||
{{MobType::Creeper, 1},{}},
|
||||
{{MobType::Creeper, 2},{}},
|
||||
{{MobType::Creeper, 3},{}},
|
||||
{{MobType::Creeper, 4},{}},
|
||||
{{MobType::Creeper, 5},{}},
|
||||
|
||||
{{MobType::Silverfish, 1},{}},
|
||||
{{MobType::Silverfish, 2},{}},
|
||||
{{MobType::Silverfish, 3},{}},
|
||||
{{MobType::Silverfish, 4},{EffectType::Fire}},
|
||||
{{MobType::Silverfish, 5},{EffectType::Fire}},
|
||||
{{MobType::Silverfish, 1},{}},
|
||||
{{MobType::Silverfish, 2},{}},
|
||||
{{MobType::Silverfish, 3},{}},
|
||||
{{MobType::Silverfish, 4},{EffectType::Fire}},
|
||||
{{MobType::Silverfish, 5},{EffectType::Fire}},
|
||||
|
||||
{{MobType::Blaze, 1},{EffectType::Fire}},
|
||||
{{MobType::Blaze, 2},{EffectType::Fire}},
|
||||
{{MobType::Blaze, 3},{EffectType::Fire}},
|
||||
{{MobType::Blaze, 4},{EffectType::Fire}},
|
||||
{{MobType::Blaze, 5},{EffectType::Fire}},
|
||||
{{MobType::Blaze, 1},{EffectType::Fire}},
|
||||
{{MobType::Blaze, 2},{EffectType::Fire}},
|
||||
{{MobType::Blaze, 3},{EffectType::Fire}},
|
||||
{{MobType::Blaze, 4},{EffectType::Fire}},
|
||||
{{MobType::Blaze, 5},{EffectType::Fire}},
|
||||
|
||||
{{MobType::Witch, 1},{}},
|
||||
{{MobType::Witch, 2},{}},
|
||||
{{MobType::Witch, 3},{}},
|
||||
{{MobType::Witch, 4},{}},
|
||||
{{MobType::Witch, 5},{}},
|
||||
{{MobType::Witch, 1},{}},
|
||||
{{MobType::Witch, 2},{}},
|
||||
{{MobType::Witch, 3},{}},
|
||||
{{MobType::Witch, 4},{}},
|
||||
{{MobType::Witch, 5},{}},
|
||||
|
||||
{{MobType::Slime, 1},{}},
|
||||
{{MobType::Slime, 2},{}},
|
||||
{{MobType::Slime, 3},{}},
|
||||
{{MobType::Slime, 4},{EffectType::Fire}},
|
||||
{{MobType::Slime, 5},{EffectType::Fire}},
|
||||
{{MobType::Slime, 1},{}},
|
||||
{{MobType::Slime, 2},{}},
|
||||
{{MobType::Slime, 3},{}},
|
||||
{{MobType::Slime, 4},{EffectType::Fire}},
|
||||
{{MobType::Slime, 5},{EffectType::Fire}},
|
||||
|
||||
{{MobType::Giant, 1},{EffectType::Stun}},
|
||||
{{MobType::Giant, 2},{EffectType::Stun}},
|
||||
{{MobType::Giant, 3},{EffectType::Stun}},
|
||||
{{MobType::Giant, 4},{EffectType::Stun}},
|
||||
{{MobType::Giant, 5},{EffectType::Stun}},
|
||||
{{MobType::Giant, 1},{EffectType::Stun}},
|
||||
{{MobType::Giant, 2},{EffectType::Stun}},
|
||||
{{MobType::Giant, 3},{EffectType::Stun}},
|
||||
{{MobType::Giant, 4},{EffectType::Stun}},
|
||||
{{MobType::Giant, 5},{EffectType::Stun}},
|
||||
};
|
||||
|
||||
const EffectImmunities& GetMobEffectImmunities(MobType type, std::uint8_t level) {
|
||||
return MobsEffectImmunities.at({ type, level });
|
||||
return MobsEffectImmunities.at({ type, level });
|
||||
}
|
||||
|
||||
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 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::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::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::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::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::Giant, [](MobID id, std::uint8_t level, PlayerID sender) -> MobPtr {return std::make_shared<Giant>(id, level, sender);} },
|
||||
};
|
||||
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::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::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::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::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::Giant, [](MobID id, std::uint8_t level, PlayerID sender) -> MobPtr {return std::make_shared<Giant>(id, level, sender);} },
|
||||
};
|
||||
|
||||
return mobFactory.at(mobType)(mobId, mobLevel, mobSender);
|
||||
return mobFactory.at(mobType)(mobId, mobLevel, mobSender);
|
||||
}
|
||||
|
||||
std::string MobFactory::GetMobName(MobType type) {
|
||||
switch (type) {
|
||||
case MobType::Zombie:
|
||||
return "Zombie";
|
||||
case MobType::Spider:
|
||||
return "Spider";
|
||||
case MobType::Skeleton:
|
||||
return "Skeleton";
|
||||
case MobType::Pigman:
|
||||
return "Pigman";
|
||||
case MobType::Creeper:
|
||||
return "Creeper";
|
||||
case MobType::Silverfish:
|
||||
return "Silverfish";
|
||||
case MobType::Blaze:
|
||||
return "Blaze";
|
||||
case MobType::Witch:
|
||||
return "Witch";
|
||||
case MobType::Slime:
|
||||
return "Slime";
|
||||
case MobType::Giant:
|
||||
return "Giant";
|
||||
default:
|
||||
return "Unknow";
|
||||
}
|
||||
switch (type) {
|
||||
case MobType::Zombie:
|
||||
return "Zombie";
|
||||
case MobType::Spider:
|
||||
return "Spider";
|
||||
case MobType::Skeleton:
|
||||
return "Skeleton";
|
||||
case MobType::Pigman:
|
||||
return "Pigman";
|
||||
case MobType::Creeper:
|
||||
return "Creeper";
|
||||
case MobType::Silverfish:
|
||||
return "Silverfish";
|
||||
case MobType::Blaze:
|
||||
return "Blaze";
|
||||
case MobType::Witch:
|
||||
return "Witch";
|
||||
case MobType::Slime:
|
||||
return "Slime";
|
||||
case MobType::Giant:
|
||||
return "Giant";
|
||||
default:
|
||||
return "Unknow";
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace game
|
||||
|
||||
@@ -8,19 +8,19 @@ namespace game {
|
||||
Team::Team(TeamColor color) : m_Color(color), m_TeamCastle(this) {}
|
||||
|
||||
void Team::AddPlayer(Player* newPlayer) {
|
||||
m_Players.push_back(newPlayer);
|
||||
m_Players.push_back(newPlayer);
|
||||
}
|
||||
|
||||
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 {
|
||||
return m_Color;
|
||||
return m_Color;
|
||||
}
|
||||
|
||||
std::uint8_t Team::GetPlayerCount() const {
|
||||
return m_Players.size();
|
||||
return m_Players.size();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -7,118 +7,118 @@ namespace td {
|
||||
namespace game {
|
||||
|
||||
bool Tower::IsMobInRange(MobPtr mob) {
|
||||
if (mob->IsDead())
|
||||
return false;
|
||||
return mob->CollidesWith(*this);
|
||||
if (mob->IsDead())
|
||||
return false;
|
||||
return mob->CollidesWith(*this);
|
||||
}
|
||||
|
||||
const std::map<std::pair<TowerType, TowerLevel>, TowerStats> TowerConstants = {
|
||||
// // rate damage range
|
||||
{{TowerType::Archer, {1, TowerPath::Base}}, {2, 5, 10}},
|
||||
// // rate damage range
|
||||
{{TowerType::Archer, {1, TowerPath::Base}}, {2, 5, 10}},
|
||||
|
||||
{{TowerType::Archer, {2, TowerPath::Top}}, {1, 0, 12}},
|
||||
{{TowerType::Archer, {3, TowerPath::Top}}, {1, 0, 13}},
|
||||
{{TowerType::Archer, {4, TowerPath::Top}}, {0.8, 0, 15}},
|
||||
{{TowerType::Archer, {2, TowerPath::Top}}, {1, 0, 12}},
|
||||
{{TowerType::Archer, {3, TowerPath::Top}}, {1, 0, 13}},
|
||||
{{TowerType::Archer, {4, TowerPath::Top}}, {0.8, 0, 15}},
|
||||
|
||||
{{TowerType::Archer, {2, TowerPath::Bottom}}, {2, 10, 12}},
|
||||
{{TowerType::Archer, {3, TowerPath::Bottom}}, {2, 10, 13}},
|
||||
{{TowerType::Archer, {4, TowerPath::Bottom}}, {2, 10, 15}},
|
||||
{{TowerType::Archer, {2, TowerPath::Bottom}}, {2, 10, 12}},
|
||||
{{TowerType::Archer, {3, TowerPath::Bottom}}, {2, 10, 13}},
|
||||
{{TowerType::Archer, {4, TowerPath::Bottom}}, {2, 10, 15}},
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
//-----------------------------------------------------------------
|
||||
|
||||
{{TowerType::Ice, {1, TowerPath::Base}}, {1, 0, 10}},
|
||||
{{TowerType::Ice, {2, TowerPath::Base}}, {1, 0, 12}},
|
||||
{{TowerType::Ice, {3, TowerPath::Base}}, {1, 0, 13}},
|
||||
{{TowerType::Ice, {4, TowerPath::Base}}, {1, 1, 15}},
|
||||
{{TowerType::Ice, {1, TowerPath::Base}}, {1, 0, 10}},
|
||||
{{TowerType::Ice, {2, TowerPath::Base}}, {1, 0, 12}},
|
||||
{{TowerType::Ice, {3, TowerPath::Base}}, {1, 0, 13}},
|
||||
{{TowerType::Ice, {4, TowerPath::Base}}, {1, 1, 15}},
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
//-----------------------------------------------------------------
|
||||
|
||||
{{TowerType::Sorcerer, {1, TowerPath::Base}}, {5, 0, 10}},
|
||||
{{TowerType::Sorcerer, {2, TowerPath::Base}}, {4, 0, 12}},
|
||||
{{TowerType::Sorcerer, {1, TowerPath::Base}}, {5, 0, 10}},
|
||||
{{TowerType::Sorcerer, {2, TowerPath::Base}}, {4, 0, 12}},
|
||||
|
||||
{{TowerType::Sorcerer, {3, TowerPath::Top}}, {4, 0, 14}},
|
||||
{{TowerType::Sorcerer, {4, TowerPath::Top}}, {4, 0, 15}},
|
||||
{{TowerType::Sorcerer, {3, TowerPath::Top}}, {4, 0, 14}},
|
||||
{{TowerType::Sorcerer, {4, TowerPath::Top}}, {4, 0, 15}},
|
||||
|
||||
{{TowerType::Sorcerer, {3, TowerPath::Bottom}}, {4, 0, 14}},
|
||||
{{TowerType::Sorcerer, {4, TowerPath::Bottom}}, {4, 0, 15}},
|
||||
{{TowerType::Sorcerer, {3, TowerPath::Bottom}}, {4, 0, 14}},
|
||||
{{TowerType::Sorcerer, {4, TowerPath::Bottom}}, {4, 0, 15}},
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
//-----------------------------------------------------------------
|
||||
|
||||
{{TowerType::Zeus, {1, TowerPath::Base}}, {5, 0, 10}},
|
||||
{{TowerType::Zeus, {2, TowerPath::Base}}, {4, 0, 12}},
|
||||
{{TowerType::Zeus, {1, TowerPath::Base}}, {5, 0, 10}},
|
||||
{{TowerType::Zeus, {2, TowerPath::Base}}, {4, 0, 12}},
|
||||
|
||||
{{TowerType::Zeus, {3, TowerPath::Top}}, {0, 0, 0}},
|
||||
{{TowerType::Zeus, {4, TowerPath::Top}}, {0, 0, 0}},
|
||||
{{TowerType::Zeus, {3, TowerPath::Top}}, {0, 0, 0}},
|
||||
{{TowerType::Zeus, {4, TowerPath::Top}}, {0, 0, 0}},
|
||||
|
||||
{{TowerType::Zeus, {3, TowerPath::Bottom}}, {1.2, 0, 14}},
|
||||
{{TowerType::Zeus, {4, TowerPath::Bottom}}, {0.8, 0, 15}},
|
||||
{{TowerType::Zeus, {3, TowerPath::Bottom}}, {1.2, 0, 14}},
|
||||
{{TowerType::Zeus, {4, TowerPath::Bottom}}, {0.8, 0, 15}},
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
//-----------------------------------------------------------------
|
||||
|
||||
{{TowerType::Mage, {1, TowerPath::Base}}, {5, 0, 10}},
|
||||
{{TowerType::Mage, {2, TowerPath::Base}}, {4, 0, 12}},
|
||||
{{TowerType::Mage, {3, TowerPath::Base}}, {3, 0, 13}},
|
||||
{{TowerType::Mage, {4, TowerPath::Base}}, {1, 30, 15}},
|
||||
{{TowerType::Mage, {1, TowerPath::Base}}, {5, 0, 10}},
|
||||
{{TowerType::Mage, {2, TowerPath::Base}}, {4, 0, 12}},
|
||||
{{TowerType::Mage, {3, TowerPath::Base}}, {3, 0, 13}},
|
||||
{{TowerType::Mage, {4, TowerPath::Base}}, {1, 30, 15}},
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
//-----------------------------------------------------------------
|
||||
|
||||
{{TowerType::Artillery, {1, TowerPath::Base}}, {7, 0, 10}},
|
||||
{{TowerType::Artillery, {2, TowerPath::Base}}, {7, 0, 12}},
|
||||
{{TowerType::Artillery, {1, TowerPath::Base}}, {7, 0, 10}},
|
||||
{{TowerType::Artillery, {2, TowerPath::Base}}, {7, 0, 12}},
|
||||
|
||||
{{TowerType::Artillery, {3, TowerPath::Top}}, {7, 0, 13}},
|
||||
{{TowerType::Artillery, {4, TowerPath::Top}}, {7, 0, 15}},
|
||||
{{TowerType::Artillery, {3, TowerPath::Top}}, {7, 0, 13}},
|
||||
{{TowerType::Artillery, {4, TowerPath::Top}}, {7, 0, 15}},
|
||||
|
||||
{{TowerType::Artillery, {3, TowerPath::Bottom}}, {5, 0, 13}},
|
||||
{{TowerType::Artillery, {4, TowerPath::Bottom}}, {4, 0, 15}},
|
||||
{{TowerType::Artillery, {3, TowerPath::Bottom}}, {5, 0, 13}},
|
||||
{{TowerType::Artillery, {4, TowerPath::Bottom}}, {4, 0, 15}},
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
//-----------------------------------------------------------------
|
||||
|
||||
{{TowerType::Quake, {1, TowerPath::Base}}, {5, 5, 10}},
|
||||
{{TowerType::Quake, {2, TowerPath::Base}}, {4, 7, 12}},
|
||||
{{TowerType::Quake, {3, TowerPath::Base}}, {3, 9, 13}},
|
||||
{{TowerType::Quake, {4, TowerPath::Base}}, {2, 11, 15}},
|
||||
{{TowerType::Quake, {1, TowerPath::Base}}, {5, 5, 10}},
|
||||
{{TowerType::Quake, {2, TowerPath::Base}}, {4, 7, 12}},
|
||||
{{TowerType::Quake, {3, TowerPath::Base}}, {3, 9, 13}},
|
||||
{{TowerType::Quake, {4, TowerPath::Base}}, {2, 11, 15}},
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
//-----------------------------------------------------------------
|
||||
|
||||
{{TowerType::Poison, {1, TowerPath::Base}}, {5, 0, 10}},
|
||||
{{TowerType::Poison, {2, TowerPath::Base}}, {5, 0, 12}},
|
||||
{{TowerType::Poison, {1, TowerPath::Base}}, {5, 0, 10}},
|
||||
{{TowerType::Poison, {2, TowerPath::Base}}, {5, 0, 12}},
|
||||
|
||||
{{TowerType::Poison, {3, TowerPath::Top}}, {6, 0, 13}},
|
||||
{{TowerType::Poison, {4, TowerPath::Top}}, {5, 0, 15}},
|
||||
{{TowerType::Poison, {3, TowerPath::Top}}, {6, 0, 13}},
|
||||
{{TowerType::Poison, {4, TowerPath::Top}}, {5, 0, 15}},
|
||||
|
||||
{{TowerType::Poison, {3, TowerPath::Bottom}}, {5, 10, 13}},
|
||||
{{TowerType::Poison, {4, TowerPath::Bottom}}, {6, 20, 15}},
|
||||
{{TowerType::Poison, {3, TowerPath::Bottom}}, {5, 10, 13}},
|
||||
{{TowerType::Poison, {4, TowerPath::Bottom}}, {6, 20, 15}},
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
//-----------------------------------------------------------------
|
||||
|
||||
{{TowerType::Leach, {1, TowerPath::Base}}, {0, 0, 0}},
|
||||
{{TowerType::Leach, {2, TowerPath::Base}}, {0, 0, 0}},
|
||||
{{TowerType::Leach, {3, TowerPath::Base}}, {0, 0, 0}},
|
||||
{{TowerType::Leach, {1, TowerPath::Base}}, {0, 0, 0}},
|
||||
{{TowerType::Leach, {2, 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, {3, TowerPath::Top}}, {0, 0, 0}},
|
||||
{{TowerType::Turret, {2, TowerPath::Top}}, {0, 0, 0}},
|
||||
{{TowerType::Turret, {3, TowerPath::Top}}, {0, 0, 0}},
|
||||
|
||||
{{TowerType::Turret, {2, TowerPath::Bottom}}, {0, 0, 0}},
|
||||
{{TowerType::Turret, {3, TowerPath::Bottom}}, {0, 0, 0}},
|
||||
{{TowerType::Turret, {2, TowerPath::Bottom}}, {0, 0, 0}},
|
||||
{{TowerType::Turret, {3, TowerPath::Bottom}}, {0, 0, 0}},
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
//-----------------------------------------------------------------
|
||||
|
||||
{{TowerType::Necromancer, {1, TowerPath::Base}}, {2, 0, 11}},
|
||||
{{TowerType::Necromancer, {2, TowerPath::Base}}, {1, 0, 14}},
|
||||
{{TowerType::Necromancer, {1, TowerPath::Base}}, {2, 0, 11}},
|
||||
{{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) {
|
||||
auto it = TowerConstants.find({ type, level });
|
||||
if (it == TowerConstants.end()) return nullptr;
|
||||
return &it->second;
|
||||
auto it = TowerConstants.find({ type, level });
|
||||
if (it == TowerConstants.end()) return nullptr;
|
||||
return &it->second;
|
||||
}
|
||||
|
||||
|
||||
@@ -126,21 +126,21 @@ const TowerStats* GetTowerStats(TowerType type, TowerLevel level) {
|
||||
|
||||
|
||||
static const std::map<TowerType, TowerInfo> TowerInfoConstants = {
|
||||
{TowerType::Archer, {"Archer", "Shoot projectiles", false}},
|
||||
{TowerType::Artillery, {"Artillery", "Explosion", false}},
|
||||
{TowerType::Ice, {"Ice", "Slow down enemies", false}},
|
||||
{TowerType::Leach, {"Leach", "Shoot projectiles", true}},
|
||||
{TowerType::Mage, {"Mage", "Set enemies on fire", false}},
|
||||
{TowerType::Necromancer, {"Necromancer", "Summon troops", true}},
|
||||
{TowerType::Poison, {"Poison", "Poison enemies", false}},
|
||||
{TowerType::Quake, {"Quake", "Shoot projectiles", false}},
|
||||
{TowerType::Sorcerer, {"Sorcerer", "Summon friendly troops", false}},
|
||||
{TowerType::Turret, {"Turret", "Shoot arrow very fast", true}},
|
||||
{TowerType::Zeus, {"Zeus", "Strike lightning", false}},
|
||||
{TowerType::Archer, {"Archer", "Shoot projectiles", false}},
|
||||
{TowerType::Artillery, {"Artillery", "Explosion", false}},
|
||||
{TowerType::Ice, {"Ice", "Slow down enemies", false}},
|
||||
{TowerType::Leach, {"Leach", "Shoot projectiles", true}},
|
||||
{TowerType::Mage, {"Mage", "Set enemies on fire", false}},
|
||||
{TowerType::Necromancer, {"Necromancer", "Summon troops", true}},
|
||||
{TowerType::Poison, {"Poison", "Poison enemies", false}},
|
||||
{TowerType::Quake, {"Quake", "Shoot projectiles", false}},
|
||||
{TowerType::Sorcerer, {"Sorcerer", "Summon friendly troops", false}},
|
||||
{TowerType::Turret, {"Turret", "Shoot arrow very fast", true}},
|
||||
{TowerType::Zeus, {"Zeus", "Strike lightning", false}},
|
||||
};
|
||||
|
||||
const TowerInfo& GetTowerInfo(TowerType type) {
|
||||
return TowerInfoConstants.at(type);
|
||||
return TowerInfoConstants.at(type);
|
||||
}
|
||||
|
||||
|
||||
@@ -152,52 +152,52 @@ namespace TowerFactory {
|
||||
using TowerCreator = std::function<std::shared_ptr<Tower>(TowerID, std::int32_t, std::int32_t, PlayerID)>;
|
||||
|
||||
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::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::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::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::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::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::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::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::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::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::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::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) {
|
||||
return towerFactory.at(type)(id, x, y, builder);
|
||||
return towerFactory.at(type)(id, x, y, builder);
|
||||
}
|
||||
|
||||
std::string GetTowerName(TowerType type) {
|
||||
switch (type) {
|
||||
switch (type) {
|
||||
|
||||
case TowerType::Archer:
|
||||
return "Archer";
|
||||
case TowerType::Artillery:
|
||||
return "Artillery";
|
||||
case TowerType::Ice:
|
||||
return "Ice";
|
||||
case TowerType::Mage:
|
||||
return "Mage";
|
||||
case TowerType::Poison:
|
||||
return "Poison";
|
||||
case TowerType::Quake:
|
||||
return "Quake";
|
||||
case TowerType::Sorcerer:
|
||||
return "Sorcerer";
|
||||
case TowerType::Zeus:
|
||||
return "Zeus";
|
||||
case TowerType::Leach:
|
||||
return "Leach";
|
||||
case TowerType::Necromancer:
|
||||
return "Necromancer";
|
||||
case TowerType::Turret:
|
||||
return "Turret";
|
||||
default:
|
||||
return "Unknow";
|
||||
case TowerType::Archer:
|
||||
return "Archer";
|
||||
case TowerType::Artillery:
|
||||
return "Artillery";
|
||||
case TowerType::Ice:
|
||||
return "Ice";
|
||||
case TowerType::Mage:
|
||||
return "Mage";
|
||||
case TowerType::Poison:
|
||||
return "Poison";
|
||||
case TowerType::Quake:
|
||||
return "Quake";
|
||||
case TowerType::Sorcerer:
|
||||
return "Sorcerer";
|
||||
case TowerType::Zeus:
|
||||
return "Zeus";
|
||||
case TowerType::Leach:
|
||||
return "Leach";
|
||||
case TowerType::Necromancer:
|
||||
return "Necromancer";
|
||||
case TowerType::Turret:
|
||||
return "Turret";
|
||||
default:
|
||||
return "Unknow";
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace TowerFactory
|
||||
@@ -207,82 +207,82 @@ std::string GetTowerName(TowerType type) {
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (m_Timer.Update(delta)) {
|
||||
std::uint8_t arrowsShot = 0;
|
||||
bool explosiveArrows = GetLevel().GetPath() == TowerPath::Bottom;
|
||||
std::uint8_t arrows = explosiveArrows ? 2 : GetLevel().GetLevel();
|
||||
for (MobPtr mob : world->GetMobList()) {
|
||||
if (IsMobInRange(mob)) {
|
||||
world->GetWorldNotifier().NotifyListeners(&WorldListener::OnArcherTowerShot, mob, this);
|
||||
m_Timer.ApplyCooldown();
|
||||
arrowsShot++;
|
||||
if (arrowsShot >= arrows)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void IceTower::Tick(std::uint64_t delta, World* world) {
|
||||
if (m_Timer.Update(delta)) {
|
||||
float damage = GetStats()->GetDamage();
|
||||
for (MobPtr mob : world->GetMobList()) {
|
||||
if (IsMobInRange(mob)) {
|
||||
mob->AddEffect(EffectType::Slowness, 1, this); // slowness for 1s every second
|
||||
if (damage > 0)
|
||||
world->GetMobNotifier().NotifyListeners(&MobListener::OnMobDamage, mob.get(), damage, this);
|
||||
m_Timer.ApplyCooldown();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (m_Timer.Update(delta)) {
|
||||
float damage = GetStats()->GetDamage();
|
||||
for (MobPtr mob : world->GetMobList()) {
|
||||
if (IsMobInRange(mob)) {
|
||||
mob->AddEffect(EffectType::Slowness, 1, this); // slowness for 1s every second
|
||||
if (damage > 0)
|
||||
world->GetMobNotifier().NotifyListeners(&MobListener::OnMobDamage, mob.get(), damage, this);
|
||||
m_Timer.ApplyCooldown();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MageTower::Tick(std::uint64_t delta, World* world) {
|
||||
if (m_Timer.Update(delta)) {
|
||||
for (MobPtr mob : world->GetMobList()) {
|
||||
if (IsMobInRange(mob)) {
|
||||
mob->AddEffect(EffectType::Fire, GetLevel().GetLevel() * 3, this);
|
||||
m_Timer.ApplyCooldown();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (m_Timer.Update(delta)) {
|
||||
for (MobPtr mob : world->GetMobList()) {
|
||||
if (IsMobInRange(mob)) {
|
||||
mob->AddEffect(EffectType::Fire, GetLevel().GetLevel() * 3, this);
|
||||
m_Timer.ApplyCooldown();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PoisonTower::Tick(std::uint64_t delta, World* world) {
|
||||
if (m_Timer.Update(delta)) {
|
||||
for (MobPtr mob : world->GetMobList()) {
|
||||
if (IsMobInRange(mob)) {
|
||||
if (GetLevel().GetPath() == TowerPath::Bottom) {
|
||||
world->GetMobNotifier().NotifyListeners(&MobListener::OnMobDamage, mob.get(), GetStats()->GetDamage(), this);
|
||||
} else {
|
||||
float durationSec;
|
||||
switch (GetLevel().GetLevel()) {
|
||||
case 1:
|
||||
durationSec = 5;
|
||||
break;
|
||||
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 2:
|
||||
durationSec = 15;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
durationSec = 30;
|
||||
break;
|
||||
case 3:
|
||||
durationSec = 30;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
durationSec = 1e10; // about 3 million hours. It should be enough
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
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) {
|
||||
|
||||
@@ -12,312 +12,312 @@ namespace td {
|
||||
namespace game {
|
||||
|
||||
World::World(Game* game) : m_Game(game) {
|
||||
GetWorldNotifier().BindListener(this);
|
||||
GetMobNotifier().BindListener(this);
|
||||
GetWorldNotifier().BindListener(this);
|
||||
GetMobNotifier().BindListener(this);
|
||||
}
|
||||
|
||||
TilePtr World::GetTile(std::int32_t x, std::int32_t y) const {
|
||||
std::int16_t chunkX = x / Chunk::ChunkWidth;
|
||||
std::int16_t chunkY = y / Chunk::ChunkHeight;
|
||||
std::int16_t chunkX = x / Chunk::ChunkWidth;
|
||||
std::int16_t chunkY = y / Chunk::ChunkHeight;
|
||||
|
||||
std::uint16_t subChunkX = std::abs(x % Chunk::ChunkWidth);
|
||||
std::uint16_t subChunkY = std::abs(y % Chunk::ChunkHeight);
|
||||
std::uint16_t subChunkX = std::abs(x % Chunk::ChunkWidth);
|
||||
std::uint16_t subChunkY = std::abs(y % Chunk::ChunkHeight);
|
||||
|
||||
auto chunkIt = m_Chunks.find({ chunkX, chunkY });
|
||||
if (chunkIt == m_Chunks.end())
|
||||
return nullptr;
|
||||
auto chunkIt = m_Chunks.find({ chunkX, chunkY });
|
||||
if (chunkIt == m_Chunks.end())
|
||||
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) {
|
||||
m_TowerPlacePalette = worldHeader->GetTowerTilePalette();
|
||||
m_WalkablePalette = worldHeader->GetWalkableTileColor();
|
||||
m_DecorationPalette = worldHeader->GetDecorationPalette();
|
||||
m_Background = worldHeader->GetBackgroundColor();
|
||||
m_TowerPlacePalette = worldHeader->GetTowerTilePalette();
|
||||
m_WalkablePalette = worldHeader->GetWalkableTileColor();
|
||||
m_DecorationPalette = worldHeader->GetDecorationPalette();
|
||||
m_Background = worldHeader->GetBackgroundColor();
|
||||
|
||||
GetRedTeam().GetSpawn() = worldHeader->GetRedSpawn();
|
||||
GetBlueTeam().GetSpawn() = worldHeader->GetBlueSpawn();
|
||||
GetRedTeam().GetSpawn() = worldHeader->GetRedSpawn();
|
||||
GetBlueTeam().GetSpawn() = worldHeader->GetBlueSpawn();
|
||||
|
||||
m_SpawnColorPalette = worldHeader->GetSpawnPalette();
|
||||
m_SpawnColorPalette = worldHeader->GetSpawnPalette();
|
||||
|
||||
GetRedTeam().GetCastle() = worldHeader->GetRedCastle();
|
||||
GetRedTeam().GetCastle().SetTeam(&GetRedTeam());
|
||||
GetRedTeam().GetCastle() = worldHeader->GetRedCastle();
|
||||
GetRedTeam().GetCastle().SetTeam(&GetRedTeam());
|
||||
|
||||
GetBlueTeam().GetCastle() = worldHeader->GetBlueCastle();
|
||||
GetBlueTeam().GetCastle().SetTeam(&GetBlueTeam());
|
||||
GetBlueTeam().GetCastle() = worldHeader->GetBlueCastle();
|
||||
GetBlueTeam().GetCastle().SetTeam(&GetBlueTeam());
|
||||
|
||||
m_TilePalette = worldHeader->GetTilePalette();
|
||||
m_TilePalette = worldHeader->GetTilePalette();
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool World::LoadMap(const protocol::WorldDataPacket* worldData) {
|
||||
m_Chunks = worldData->GetChunks();
|
||||
return true;
|
||||
m_Chunks = worldData->GetChunks();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool World::LoadMapFromFile(const std::string& fileName) {
|
||||
DataBuffer buffer;
|
||||
if (!buffer.ReadFile(fileName)) {
|
||||
utils::LOGE(utils::format("Failed to load map from file %s", fileName.c_str()));
|
||||
return false;
|
||||
}
|
||||
DataBuffer buffer;
|
||||
if (!buffer.ReadFile(fileName)) {
|
||||
utils::LOGE(utils::format("Failed to load map from file %s", fileName.c_str()));
|
||||
return false;
|
||||
}
|
||||
|
||||
utils::LOG(utils::format("Read file : %s (File size : %u)", fileName.c_str(), buffer.GetSize()));
|
||||
utils::LOG(utils::format("Read file : %s (File size : %u)", fileName.c_str(), buffer.GetSize()));
|
||||
|
||||
DataBuffer mapHeaderPacketBuffer = utils::Decompress(buffer);
|
||||
DataBuffer mapDataPacketBuffer = utils::Decompress(buffer);
|
||||
DataBuffer mapHeaderPacketBuffer = utils::Decompress(buffer);
|
||||
DataBuffer mapDataPacketBuffer = utils::Decompress(buffer);
|
||||
|
||||
protocol::WorldBeginDataPacket headerPacket;
|
||||
headerPacket.Deserialize(mapHeaderPacketBuffer);
|
||||
protocol::WorldBeginDataPacket headerPacket;
|
||||
headerPacket.Deserialize(mapHeaderPacketBuffer);
|
||||
|
||||
protocol::WorldDataPacket dataPacket;
|
||||
dataPacket.Deserialize(mapDataPacketBuffer);
|
||||
protocol::WorldDataPacket dataPacket;
|
||||
dataPacket.Deserialize(mapDataPacketBuffer);
|
||||
|
||||
LoadMap(&headerPacket);
|
||||
LoadMap(&dataPacket);
|
||||
LoadMap(&headerPacket);
|
||||
LoadMap(&dataPacket);
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool World::SaveMap(const std::string& fileName) const {
|
||||
protocol::WorldBeginDataPacket headerPacket(this);
|
||||
protocol::WorldDataPacket dataPacket(this);
|
||||
protocol::WorldBeginDataPacket headerPacket(this);
|
||||
protocol::WorldDataPacket dataPacket(this);
|
||||
|
||||
DataBuffer mapHeaderCompressed = utils::Compress(headerPacket.Serialize(false));
|
||||
DataBuffer mapDataCompressed = utils::Compress(dataPacket.Serialize(false));
|
||||
DataBuffer mapHeaderCompressed = utils::Compress(headerPacket.Serialize(false));
|
||||
DataBuffer mapDataCompressed = utils::Compress(dataPacket.Serialize(false));
|
||||
|
||||
utils::LOG(utils::format("Header Packet Size : %u", mapHeaderCompressed.GetSize()));
|
||||
utils::LOG(utils::format("World Data Packet Size : %u", mapDataCompressed.GetSize()));
|
||||
utils::LOG(utils::format("Header Packet Size : %u", mapHeaderCompressed.GetSize()));
|
||||
utils::LOG(utils::format("World Data Packet Size : %u", mapDataCompressed.GetSize()));
|
||||
|
||||
DataBuffer buffer = mapHeaderCompressed << mapDataCompressed;
|
||||
utils::LOG(utils::format("Total Size : %u", buffer.GetSize()));
|
||||
return buffer.WriteFile(fileName);
|
||||
DataBuffer buffer = mapHeaderCompressed << mapDataCompressed;
|
||||
utils::LOG(utils::format("Total Size : %u", buffer.GetSize()));
|
||||
return buffer.WriteFile(fileName);
|
||||
}
|
||||
|
||||
void World::Tick(std::uint64_t delta) {
|
||||
if (m_Game->GetGameState() != GameState::Game) return;
|
||||
if (m_Game->GetGameState() != GameState::Game) return;
|
||||
|
||||
TickMobs(delta);
|
||||
for (TowerPtr tower : m_Towers) {
|
||||
tower->Tick(delta, this);
|
||||
}
|
||||
CleanDeadMobs();
|
||||
TickMobs(delta);
|
||||
for (TowerPtr tower : m_Towers) {
|
||||
tower->Tick(delta, this);
|
||||
}
|
||||
CleanDeadMobs();
|
||||
}
|
||||
|
||||
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);
|
||||
mob->SetCenter({ x, y });
|
||||
mob->SetDirection(dir);
|
||||
m_Mobs.push_back(mob);
|
||||
GetMobNotifier().NotifyListeners(&MobListener::OnMobSpawn, mob.get());
|
||||
MobPtr mob = MobFactory::CreateMob(id, type, level, sender);
|
||||
mob->SetCenter({ x, y });
|
||||
mob->SetDirection(dir);
|
||||
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 tower = TowerFactory::CreateTower(type, id, x, y, builder);
|
||||
m_Towers.push_back(tower);
|
||||
return tower;
|
||||
TowerPtr tower = TowerFactory::CreateTower(type, id, x, y, builder);
|
||||
m_Towers.push_back(tower);
|
||||
return tower;
|
||||
}
|
||||
|
||||
TowerPtr World::RemoveTower(TowerID towerId) {
|
||||
auto it = std::find_if(m_Towers.begin(), m_Towers.end(), [towerId](TowerPtr tower) { return tower->GetID() == towerId;});
|
||||
if (it == m_Towers.end()) return nullptr;
|
||||
auto it = std::find_if(m_Towers.begin(), m_Towers.end(), [towerId](TowerPtr tower) { return tower->GetID() == towerId;});
|
||||
if (it == m_Towers.end()) return nullptr;
|
||||
|
||||
TowerPtr tower = *it;
|
||||
TowerPtr tower = *it;
|
||||
|
||||
m_Towers.erase(it);
|
||||
m_Towers.erase(it);
|
||||
|
||||
return tower;
|
||||
return tower;
|
||||
}
|
||||
|
||||
void World::TickMobs(std::uint64_t delta) {
|
||||
for (MobPtr mob : m_Mobs) {
|
||||
mob->Tick(delta, this);
|
||||
}
|
||||
for (MobPtr mob : m_Mobs) {
|
||||
mob->Tick(delta, this);
|
||||
}
|
||||
}
|
||||
|
||||
const Color* World::GetTileColor(TilePtr tile) const {
|
||||
switch (tile->GetType()) {
|
||||
case TileType::Tower: {
|
||||
TowerTile* towerTile = dynamic_cast<TowerTile*>(tile.get());
|
||||
return &m_TowerPlacePalette[towerTile->color_palette_ref];
|
||||
}
|
||||
case TileType::Walk: {
|
||||
return &m_WalkablePalette;
|
||||
}
|
||||
case TileType::Decoration: {
|
||||
DecorationTile* towerTile = dynamic_cast<DecorationTile*>(tile.get());
|
||||
return &m_DecorationPalette[towerTile->color_palette_ref];
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
switch (tile->GetType()) {
|
||||
case TileType::Tower: {
|
||||
TowerTile* towerTile = dynamic_cast<TowerTile*>(tile.get());
|
||||
return &m_TowerPlacePalette[towerTile->color_palette_ref];
|
||||
}
|
||||
case TileType::Walk: {
|
||||
return &m_WalkablePalette;
|
||||
}
|
||||
case TileType::Decoration: {
|
||||
DecorationTile* towerTile = dynamic_cast<DecorationTile*>(tile.get());
|
||||
return &m_DecorationPalette[towerTile->color_palette_ref];
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool World::CanPlaceLittleTower(const Vec2f& worldPos, PlayerID playerID) const {
|
||||
TilePtr tile = GetTile(worldPos.x, worldPos.y);
|
||||
const Player& player = m_Game->GetPlayers()[playerID];
|
||||
TilePtr tile = GetTile(worldPos.x, worldPos.y);
|
||||
const Player& player = m_Game->GetPlayers()[playerID];
|
||||
|
||||
if (tile == nullptr) {
|
||||
return false;
|
||||
}
|
||||
if (tile == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (tile->GetType() == game::TileType::Tower) {
|
||||
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;
|
||||
}
|
||||
if (tile->GetType() == game::TileType::Tower) {
|
||||
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;
|
||||
}
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool World::CanPlaceBigTower(const Vec2f& worldPos, PlayerID playerID) const {
|
||||
if (!CanPlaceLittleTower(worldPos, playerID)) return false;
|
||||
if (!CanPlaceLittleTower(worldPos, playerID)) return false;
|
||||
|
||||
TilePtr tile = GetTile(worldPos.x, worldPos.y);
|
||||
const Player& player = m_Game->GetPlayers()[playerID];
|
||||
TilePtr tile = GetTile(worldPos.x, worldPos.y);
|
||||
const Player& player = m_Game->GetPlayers()[playerID];
|
||||
|
||||
if (tile == nullptr) {
|
||||
return false;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
return false;
|
||||
}
|
||||
|
||||
void World::CleanDeadMobs() {
|
||||
// safely remove mobs when unused
|
||||
for (std::size_t i = 0; i < m_Mobs.size(); i++) {
|
||||
MobPtr mob = m_Mobs[i];
|
||||
if (mob->IsDead()) {
|
||||
m_Mobs.erase(m_Mobs.begin() + static_cast<int>(i));
|
||||
}
|
||||
}
|
||||
// safely remove mobs when unused
|
||||
for (std::size_t i = 0; i < m_Mobs.size(); i++) {
|
||||
MobPtr mob = m_Mobs[i];
|
||||
if (mob->IsDead()) {
|
||||
m_Mobs.erase(m_Mobs.begin() + static_cast<int>(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TowerPtr World::GetTower(const Vec2f& 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;
|
||||
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;
|
||||
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 fireArrows = shooter->GetLevel().GetPath() == TowerPath::Bottom;
|
||||
bool explosiveArrows = shooter->GetLevel().GetLevel() == 4 && fireArrows;
|
||||
bool fireArrows = shooter->GetLevel().GetPath() == TowerPath::Bottom;
|
||||
bool explosiveArrows = shooter->GetLevel().GetLevel() == 4 && fireArrows;
|
||||
|
||||
GetWorldNotifier().NotifyListeners(&WorldListener::OnArrowShot, tarGet, fireArrows, shooter);
|
||||
if (explosiveArrows) {
|
||||
GetWorldNotifier().NotifyListeners(&WorldListener::OnExplosion, utils::shape::Circle{ tarGet->GetCenterX(), tarGet->GetCenterY(), ArcherTower::ExplosionRadius }, shooter->GetStats()->GetDamage(), shooter);
|
||||
}
|
||||
GetWorldNotifier().NotifyListeners(&WorldListener::OnArrowShot, tarGet, fireArrows, shooter);
|
||||
if (explosiveArrows) {
|
||||
GetWorldNotifier().NotifyListeners(&WorldListener::OnExplosion, utils::shape::Circle{ tarGet->GetCenterX(), tarGet->GetCenterY(), ArcherTower::ExplosionRadius }, shooter->GetStats()->GetDamage(), shooter);
|
||||
}
|
||||
}
|
||||
|
||||
void World::OnArrowShot(MobPtr tarGet, bool fireArrow, Tower* shooter) {
|
||||
GetMobNotifier().NotifyListeners(&MobListener::OnMobDamage, tarGet.get(), shooter->GetStats()->GetDamage(), shooter);
|
||||
if (fireArrow) {
|
||||
tarGet->AddEffect(EffectType::Fire, ArcherTower::FireDurationSec, shooter);
|
||||
}
|
||||
GetMobNotifier().NotifyListeners(&MobListener::OnMobDamage, tarGet.get(), shooter->GetStats()->GetDamage(), shooter);
|
||||
if (fireArrow) {
|
||||
tarGet->AddEffect(EffectType::Fire, ArcherTower::FireDurationSec, shooter);
|
||||
}
|
||||
}
|
||||
|
||||
void World::OnExplosion(utils::shape::Circle explosion, float centerDamage, Tower* shooter) {
|
||||
for (MobPtr mob : m_Mobs) {
|
||||
if (mob->IsAlive() && mob->CollidesWith(explosion)) {
|
||||
// linear distance damage reduction
|
||||
float explosionDamage = mob->Distance(explosion) / explosion.GetRadius() * centerDamage;
|
||||
GetMobNotifier().NotifyListeners(&MobListener::OnMobDamage, mob.get(), explosionDamage, shooter);
|
||||
}
|
||||
}
|
||||
for (MobPtr mob : m_Mobs) {
|
||||
if (mob->IsAlive() && mob->CollidesWith(explosion)) {
|
||||
// linear distance damage reduction
|
||||
float explosionDamage = mob->Distance(explosion) / explosion.GetRadius() * centerDamage;
|
||||
GetMobNotifier().NotifyListeners(&MobListener::OnMobDamage, mob.get(), explosionDamage, shooter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void World::OnMobCastleDamage(Mob* damager, TeamCastle* enemyCastle, float damage) {
|
||||
enemyCastle->Damage(damage);
|
||||
if (enemyCastle->GetLife() <= 0) {
|
||||
m_Game->NotifyListeners(&GameListener::OnGameEnd);
|
||||
}
|
||||
enemyCastle->Damage(damage);
|
||||
if (enemyCastle->GetLife() <= 0) {
|
||||
m_Game->NotifyListeners(&GameListener::OnGameEnd);
|
||||
}
|
||||
}
|
||||
|
||||
void World::OnMobDamage(Mob* tarGet, float damage, Tower* source) {
|
||||
tarGet->Damage(damage, source);
|
||||
if (tarGet->IsDead()) {
|
||||
GetMobNotifier().NotifyListeners(&MobListener::OnMobDie, tarGet);
|
||||
}
|
||||
tarGet->Damage(damage, source);
|
||||
if (tarGet->IsDead()) {
|
||||
GetMobNotifier().NotifyListeners(&MobListener::OnMobDie, tarGet);
|
||||
}
|
||||
}
|
||||
|
||||
Team& World::GetRedTeam() {
|
||||
return m_Game->GetRedTeam();
|
||||
return m_Game->GetRedTeam();
|
||||
}
|
||||
|
||||
const Team& World::GetRedTeam() const {
|
||||
return m_Game->GetRedTeam();
|
||||
return m_Game->GetRedTeam();
|
||||
}
|
||||
|
||||
Team& World::GetBlueTeam() {
|
||||
return m_Game->GetBlueTeam();
|
||||
return m_Game->GetBlueTeam();
|
||||
}
|
||||
|
||||
const Team& World::GetBlueTeam() const {
|
||||
return m_Game->GetBlueTeam();
|
||||
return m_Game->GetBlueTeam();
|
||||
}
|
||||
|
||||
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);
|
||||
return m_Game->GetTeam(team);
|
||||
}
|
||||
|
||||
const Player* World::GetPlayerById(PlayerID id) const {
|
||||
return m_Game->GetPlayerById(id);
|
||||
return m_Game->GetPlayerById(id);
|
||||
}
|
||||
|
||||
const TeamList& World::GetTeams() const {
|
||||
return m_Game->GetTeams();
|
||||
return m_Game->GetTeams();
|
||||
}
|
||||
|
||||
} // namespace game
|
||||
|
||||
@@ -5,73 +5,73 @@ namespace td {
|
||||
namespace client {
|
||||
|
||||
bool Client::Connect(const network::IPAddresses& addresses, std::uint16_t port) {
|
||||
for (const network::IPAddress& address : addresses) {
|
||||
if (address.IsValid() && m_Connexion.Connect(address.ToString(), port)) {
|
||||
m_Connected = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
utils::LOGE("Failed to connect !");
|
||||
return false;
|
||||
for (const network::IPAddress& address : addresses) {
|
||||
if (address.IsValid() && m_Connexion.Connect(address.ToString(), port)) {
|
||||
m_Connected = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
utils::LOGE("Failed to connect !");
|
||||
return false;
|
||||
}
|
||||
|
||||
void Client::SelectTeam(game::TeamColor team) {
|
||||
if (!m_Connected)
|
||||
return;
|
||||
if (!m_Connected)
|
||||
return;
|
||||
|
||||
protocol::SelectTeamPacket packet(team);
|
||||
m_Connexion.SendPacket(&packet);
|
||||
protocol::SelectTeamPacket packet(team);
|
||||
m_Connexion.SendPacket(&packet);
|
||||
}
|
||||
|
||||
void Client::CloseConnection() {
|
||||
if (!m_Connected)
|
||||
return;
|
||||
if (!m_Connected)
|
||||
return;
|
||||
|
||||
m_Connected = false;
|
||||
m_Connected = false;
|
||||
|
||||
protocol::DisconnectPacket packet;
|
||||
m_Connexion.SendPacket(&packet);
|
||||
protocol::DisconnectPacket packet;
|
||||
m_Connexion.SendPacket(&packet);
|
||||
}
|
||||
|
||||
void Client::Tick(std::uint64_t delta) {
|
||||
if (!m_Connected)
|
||||
return;
|
||||
m_Connected = m_Connexion.UpdateSocket();
|
||||
if (!m_Connected) {
|
||||
utils::LOG(utils::format("Disconnected ! (Reason : %s)", m_Connexion.GetDisconnectReason().c_str()));
|
||||
Reset();
|
||||
} else {
|
||||
m_Game->Tick(delta);
|
||||
}
|
||||
if (!m_Connected)
|
||||
return;
|
||||
m_Connected = m_Connexion.UpdateSocket();
|
||||
if (!m_Connected) {
|
||||
utils::LOG(utils::format("Disconnected ! (Reason : %s)", m_Connexion.GetDisconnectReason().c_str()));
|
||||
Reset();
|
||||
} else {
|
||||
m_Game->Tick(delta);
|
||||
}
|
||||
}
|
||||
|
||||
void Client::Render() {
|
||||
m_Game->RenderWorld();
|
||||
m_Game->RenderWorld();
|
||||
}
|
||||
|
||||
void Client::Reset() {
|
||||
m_Game.reset(0);
|
||||
m_Game = std::make_unique<ClientGame>(this);
|
||||
m_Game.reset(0);
|
||||
m_Game = std::make_unique<ClientGame>(this);
|
||||
}
|
||||
|
||||
void Client::SendMobs(const std::vector<protocol::MobSend>& mobSends) {
|
||||
protocol::SendMobsPacket packet(mobSends);
|
||||
m_Connexion.SendPacket(&packet);
|
||||
protocol::SendMobsPacket packet(mobSends);
|
||||
m_Connexion.SendPacket(&packet);
|
||||
}
|
||||
|
||||
void Client::PlaceTower(game::TowerType type, const Vec2f& position) {
|
||||
protocol::PlaceTowerPacket packet(position.x, position.y, type);
|
||||
m_Connexion.SendPacket(&packet);
|
||||
protocol::PlaceTowerPacket packet(position.x, position.y, type);
|
||||
m_Connexion.SendPacket(&packet);
|
||||
}
|
||||
|
||||
void Client::UpgradeTower(game::TowerID tower, game::TowerLevel level) {
|
||||
protocol::UpgradeTowerPacket packet(tower, level);
|
||||
m_Connexion.SendPacket(&packet);
|
||||
protocol::UpgradeTowerPacket packet(tower, level);
|
||||
m_Connexion.SendPacket(&packet);
|
||||
}
|
||||
|
||||
void Client::RemoveTower(game::TowerID tower) {
|
||||
protocol::RemoveTowerPacket packet(tower);
|
||||
m_Connexion.SendPacket(&packet);
|
||||
protocol::RemoveTowerPacket packet(tower);
|
||||
m_Connexion.SendPacket(&packet);
|
||||
}
|
||||
|
||||
} // namespace client
|
||||
|
||||
@@ -5,43 +5,43 @@ namespace td {
|
||||
namespace client {
|
||||
|
||||
ClientConnexion::ClientConnexion() : Connexion(&m_Dispatcher), m_ServerTPS(0) {
|
||||
RegisterHandlers();
|
||||
RegisterHandlers();
|
||||
}
|
||||
|
||||
void ClientConnexion::RegisterHandlers() {
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::KeepAlive, this);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::ConnectionInfo, this);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::Disconnect, this);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::ServerTps, this);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::KeepAlive, this);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::ConnectionInfo, this);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::Disconnect, this);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::ServerTps, this);
|
||||
}
|
||||
|
||||
void ClientConnexion::HandlePacket(const protocol::KeepAlivePacket* packet) {
|
||||
protocol::KeepAlivePacket keepAlivePacket(packet->GetAliveID());
|
||||
SendPacket(&keepAlivePacket);
|
||||
protocol::KeepAlivePacket keepAlivePacket(packet->GetAliveID());
|
||||
SendPacket(&keepAlivePacket);
|
||||
}
|
||||
|
||||
void ClientConnexion::HandlePacket(const protocol::ConnexionInfoPacket* packet) {
|
||||
m_ConnectionID = packet->GetConnectionID();
|
||||
Login();
|
||||
m_ConnectionID = packet->GetConnectionID();
|
||||
Login();
|
||||
}
|
||||
|
||||
void ClientConnexion::HandlePacket(const protocol::ServerTpsPacket* packet) {
|
||||
m_ServerTPS = packet->GetTPS();
|
||||
m_Ping = utils::GetTime() - packet->GetPacketSendTime();
|
||||
m_ServerTPS = packet->GetTPS();
|
||||
m_Ping = utils::GetTime() - packet->GetPacketSendTime();
|
||||
}
|
||||
|
||||
void ClientConnexion::Login() {
|
||||
td::protocol::PlayerLoginPacket loginPacket("Persson" + std::to_string(m_ConnectionID));
|
||||
SendPacket(&loginPacket);
|
||||
td::protocol::PlayerLoginPacket loginPacket("Persson" + std::to_string(m_ConnectionID));
|
||||
SendPacket(&loginPacket);
|
||||
}
|
||||
|
||||
bool ClientConnexion::UpdateSocket() {
|
||||
return Connexion::UpdateSocket();
|
||||
return Connexion::UpdateSocket();
|
||||
}
|
||||
|
||||
void ClientConnexion::HandlePacket(const protocol::DisconnectPacket* packet) {
|
||||
m_DisconnectReason = packet->GetReason();
|
||||
CloseConnection();
|
||||
m_DisconnectReason = packet->GetReason();
|
||||
CloseConnection();
|
||||
}
|
||||
|
||||
} // namespace client
|
||||
|
||||
@@ -8,110 +8,110 @@ namespace client {
|
||||
ClientGame::ClientGame(Client* client) : protocol::PacketHandler(client->GetConnexion().GetDispatcher()),
|
||||
game::Game(&m_WorldClient), m_Client(client), m_Renderer(client->GetRenderer()), m_WorldClient(this),
|
||||
m_WorldRenderer(&m_WorldClient, this) {
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::ConnectionInfo, this);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::PlayerJoin, this);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::PlayerList, this);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::PlayerLeave, this);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::UpdatePlayerTeam, this);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::UpdateLobbyTime, this);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::UpdateGameState, this);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::UpdateMoney, this);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::UpdateEXP, this);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::Disconnect, this);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::WorldData, this);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::ConnectionInfo, this);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::PlayerJoin, this);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::PlayerList, this);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::PlayerLeave, this);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::UpdatePlayerTeam, this);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::UpdateLobbyTime, this);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::UpdateGameState, this);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::UpdateMoney, this);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::UpdateEXP, this);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::Disconnect, this);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::WorldData, this);
|
||||
}
|
||||
|
||||
ClientGame::~ClientGame() {
|
||||
GetDispatcher()->UnregisterHandler(this);
|
||||
GetDispatcher()->UnregisterHandler(this);
|
||||
}
|
||||
|
||||
void ClientGame::Tick(std::uint64_t delta) {
|
||||
game::Game::Tick(delta);
|
||||
m_WorldRenderer.Update();
|
||||
if (m_GameState == game::GameState::Lobby && m_LobbyTime > 0) {
|
||||
m_LobbyTime -= delta;
|
||||
}
|
||||
game::Game::Tick(delta);
|
||||
m_WorldRenderer.Update();
|
||||
if (m_GameState == game::GameState::Lobby && m_LobbyTime > 0) {
|
||||
m_LobbyTime -= delta;
|
||||
}
|
||||
}
|
||||
|
||||
void ClientGame::HandlePacket(const protocol::PlayerJoinPacket* packet) {
|
||||
game::Player player(packet->GetPlayerID());
|
||||
player.SetName(packet->GetPlayerName());
|
||||
game::Player player(packet->GetPlayerID());
|
||||
player.SetName(packet->GetPlayerName());
|
||||
|
||||
m_Players.insert({ player.GetID(), player });
|
||||
m_Players.insert({ player.GetID(), player });
|
||||
}
|
||||
|
||||
void ClientGame::HandlePacket(const protocol::PlayerLeavePacket* packet) {
|
||||
game::Player* player = &m_Players[packet->GetPlayerID()];
|
||||
if (player->GetTeamColor() != game::TeamColor::None) {
|
||||
m_Teams[(std::size_t)player->GetTeamColor()].RemovePlayer(player);
|
||||
}
|
||||
m_Players.erase(player->GetID());
|
||||
game::Player* player = &m_Players[packet->GetPlayerID()];
|
||||
if (player->GetTeamColor() != game::TeamColor::None) {
|
||||
m_Teams[(std::size_t)player->GetTeamColor()].RemovePlayer(player);
|
||||
}
|
||||
m_Players.erase(player->GetID());
|
||||
}
|
||||
|
||||
void ClientGame::HandlePacket(const protocol::PlayerListPacket* packet) {
|
||||
for (auto pair : packet->GetPlayers()) {
|
||||
std::uint8_t playerID = pair.first;
|
||||
protocol::PlayerInfo playerInfo = pair.second;
|
||||
game::Player player(playerID);
|
||||
player.SetName(playerInfo.name);
|
||||
player.SetTeamColor(playerInfo.team);
|
||||
m_Players.insert({ playerID, player });
|
||||
if (player.GetTeamColor() != game::TeamColor::None) {
|
||||
m_Teams[(std::size_t)player.GetTeamColor()].AddPlayer(&m_Players[playerID]);
|
||||
}
|
||||
}
|
||||
m_Player = &m_Players[m_ConnexionID];
|
||||
for (auto pair : packet->GetPlayers()) {
|
||||
std::uint8_t playerID = pair.first;
|
||||
protocol::PlayerInfo playerInfo = pair.second;
|
||||
game::Player player(playerID);
|
||||
player.SetName(playerInfo.name);
|
||||
player.SetTeamColor(playerInfo.team);
|
||||
m_Players.insert({ playerID, player });
|
||||
if (player.GetTeamColor() != game::TeamColor::None) {
|
||||
m_Teams[(std::size_t)player.GetTeamColor()].AddPlayer(&m_Players[playerID]);
|
||||
}
|
||||
}
|
||||
m_Player = &m_Players[m_ConnexionID];
|
||||
}
|
||||
|
||||
void ClientGame::HandlePacket(const protocol::UpdatePlayerTeamPacket* packet) {
|
||||
game::Player* player = &m_Players[packet->GetPlayerID()];
|
||||
if (player->GetTeamColor() == game::TeamColor::None) { //join a team
|
||||
GetTeam(packet->GetSelectedTeam()).AddPlayer(player);
|
||||
} else if (packet->GetSelectedTeam() == game::TeamColor::None) { // leave a team
|
||||
GetTeam(player->GetTeamColor()).RemovePlayer(player);
|
||||
} else { // change team
|
||||
GetTeam(player->GetTeamColor()).RemovePlayer(player);
|
||||
GetTeam(packet->GetSelectedTeam()).AddPlayer(player);
|
||||
}
|
||||
player->SetTeamColor(packet->GetSelectedTeam());
|
||||
game::Player* player = &m_Players[packet->GetPlayerID()];
|
||||
if (player->GetTeamColor() == game::TeamColor::None) { //join a team
|
||||
GetTeam(packet->GetSelectedTeam()).AddPlayer(player);
|
||||
} else if (packet->GetSelectedTeam() == game::TeamColor::None) { // leave a team
|
||||
GetTeam(player->GetTeamColor()).RemovePlayer(player);
|
||||
} else { // change team
|
||||
GetTeam(player->GetTeamColor()).RemovePlayer(player);
|
||||
GetTeam(packet->GetSelectedTeam()).AddPlayer(player);
|
||||
}
|
||||
player->SetTeamColor(packet->GetSelectedTeam());
|
||||
}
|
||||
|
||||
void ClientGame::HandlePacket(const protocol::UpdateGameStatePacket* packet) {
|
||||
SetGameState(packet->GetGameState());
|
||||
SetGameState(packet->GetGameState());
|
||||
}
|
||||
|
||||
void ClientGame::HandlePacket(const protocol::ConnexionInfoPacket* packet) {
|
||||
m_ConnexionID = packet->GetConnectionID();
|
||||
m_ConnexionID = packet->GetConnectionID();
|
||||
}
|
||||
|
||||
void ClientGame::HandlePacket(const protocol::UpdateLobbyTimePacket* packet) {
|
||||
m_LobbyTime = packet->GetRemainingTime();
|
||||
m_LobbyTime = packet->GetRemainingTime();
|
||||
}
|
||||
|
||||
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());
|
||||
m_Player->SetExp(packet->GetExp());
|
||||
}
|
||||
|
||||
void ClientGame::HandlePacket(const protocol::DisconnectPacket* packet) {
|
||||
m_GameState = game::GameState::Disconnected;
|
||||
m_Renderer->SetBackgroundColor({ 0, 0, 0 });
|
||||
m_GameState = game::GameState::Disconnected;
|
||||
m_Renderer->SetBackgroundColor({ 0, 0, 0 });
|
||||
}
|
||||
|
||||
void ClientGame::HandlePacket(const protocol::WorldDataPacket* packet) {
|
||||
m_WorldRenderer.LoadModels();
|
||||
// set cam pos to player spawn
|
||||
const game::Spawn& spawn = m_World->GetTeam(m_Player->GetTeamColor()).GetSpawn();
|
||||
m_WorldRenderer.SetCamPos(spawn.GetCenterX(), spawn.GetCenterY());
|
||||
m_WorldRenderer.LoadModels();
|
||||
// set cam pos to player spawn
|
||||
const game::Spawn& spawn = m_World->GetTeam(m_Player->GetTeamColor()).GetSpawn();
|
||||
m_WorldRenderer.SetCamPos(spawn.GetCenterX(), spawn.GetCenterY());
|
||||
}
|
||||
|
||||
void ClientGame::RenderWorld() {
|
||||
if (m_GameState == game::GameState::Game || m_GameState == game::GameState::EndGame) {
|
||||
m_WorldRenderer.Render();
|
||||
}
|
||||
if (m_GameState == game::GameState::Game || m_GameState == game::GameState::EndGame) {
|
||||
m_WorldRenderer.Render();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace client
|
||||
|
||||
@@ -7,69 +7,69 @@ namespace td {
|
||||
namespace client {
|
||||
|
||||
WorldClient::WorldClient(ClientGame* game) : game::World(game), protocol::PacketHandler(game->GetDispatcher()), m_Game(game) {
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::WorldAddTower, this);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::WorldBeginData, this);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::WorldData, 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);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::WorldAddTower, this);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::WorldBeginData, this);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::WorldData, 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) {
|
||||
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) });
|
||||
}
|
||||
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) {
|
||||
LoadMap(packet);
|
||||
LoadMap(packet);
|
||||
}
|
||||
|
||||
void WorldClient::HandlePacket(const protocol::SpawnMobPacket* packet) {
|
||||
SpawnMobAt(packet->GetMobID(), packet->GetMobType(), packet->GetMobLevel(), packet->GetSender(),
|
||||
packet->GetMobX(), packet->GetMobY(), packet->GetMobDirection());
|
||||
SpawnMobAt(packet->GetMobID(), packet->GetMobType(), packet->GetMobLevel(), packet->GetSender(),
|
||||
packet->GetMobX(), packet->GetMobY(), packet->GetMobDirection());
|
||||
}
|
||||
|
||||
void WorldClient::HandlePacket(const protocol::UpgradeTowerPacket* packet) {
|
||||
game::TowerPtr tower = GetTowerById(packet->GetTowerID());
|
||||
if (tower == nullptr) return; // this should not happen but who knows ?
|
||||
tower->Upgrade(packet->GetTowerLevel().GetLevel(), packet->GetTowerLevel().GetPath());
|
||||
game::TowerPtr tower = GetTowerById(packet->GetTowerID());
|
||||
if (tower == nullptr) return; // this should not happen but who knows ?
|
||||
tower->Upgrade(packet->GetTowerLevel().GetLevel(), packet->GetTowerLevel().GetPath());
|
||||
}
|
||||
|
||||
void WorldClient::HandlePacket(const protocol::WorldAddTowerPacket* packet) {
|
||||
game::TowerPtr newTower = PlaceTowerAt(packet->GetTowerID(), packet->GetTowerType(), packet->GetTowerX(), packet->GetTowerY(), packet->GetBuilder());
|
||||
game::TowerPtr newTower = PlaceTowerAt(packet->GetTowerID(), packet->GetTowerType(), packet->GetTowerX(), packet->GetTowerY(), packet->GetBuilder());
|
||||
|
||||
GetWorldNotifier().NotifyListeners(&WorldListener::OnTowerAdd, newTower);
|
||||
GetWorldNotifier().NotifyListeners(&WorldListener::OnTowerAdd, newTower);
|
||||
}
|
||||
|
||||
void WorldClient::HandlePacket(const protocol::RemoveTowerPacket* packet) {
|
||||
game::TowerPtr tower = RemoveTower(packet->GetTowerID());
|
||||
game::TowerPtr tower = RemoveTower(packet->GetTowerID());
|
||||
|
||||
if (tower != nullptr) {
|
||||
GetWorldNotifier().NotifyListeners(&WorldListener::OnTowerRemove, tower);
|
||||
}
|
||||
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());
|
||||
}
|
||||
}
|
||||
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());
|
||||
GetTeam(packet->GetTeamColor()).GetCastle().SetLife(packet->GetCastleLife());
|
||||
}
|
||||
|
||||
} // namespace client
|
||||
|
||||
@@ -13,17 +13,17 @@ namespace td {
|
||||
namespace server {
|
||||
|
||||
/*static constexpr std::uint8_t timeNotifications[] = {
|
||||
2 * 60, // 2 min
|
||||
60 + 30, // 1 min 30 s
|
||||
60, // 1 min
|
||||
30, // 30 s
|
||||
15, // 15 s
|
||||
10, // 10 s
|
||||
5, // 5 s
|
||||
4, // 4 s
|
||||
3, // 3 s
|
||||
2, // 2 s
|
||||
1, // 1 s
|
||||
2 * 60, // 2 min
|
||||
60 + 30, // 1 min 30 s
|
||||
60, // 1 min
|
||||
30, // 30 s
|
||||
15, // 15 s
|
||||
10, // 10 s
|
||||
5, // 5 s
|
||||
4, // 4 s
|
||||
3, // 3 s
|
||||
2, // 2 s
|
||||
1, // 1 s
|
||||
};*/
|
||||
|
||||
Lobby::Lobby(Server* server) : m_Server(server), m_Timer(1000, std::bind(&Lobby::SendTimeRemaining, this)) {
|
||||
@@ -31,50 +31,50 @@ Lobby::Lobby(Server* server) : m_Server(server), m_Timer(1000, std::bind(&Lobby:
|
||||
}
|
||||
|
||||
void Lobby::Tick() {
|
||||
if (m_GameStarted || m_StartTimerTime == 0)
|
||||
return;
|
||||
if (m_GameStarted || m_StartTimerTime == 0)
|
||||
return;
|
||||
|
||||
if (utils::GetTime() - m_StartTimerTime >= LobbyWaitingTime) {
|
||||
m_Server->GetGame().NotifyListeners(&game::GameListener::OnGameBegin);
|
||||
m_GameStarted = true;
|
||||
return;
|
||||
}
|
||||
if (utils::GetTime() - m_StartTimerTime >= LobbyWaitingTime) {
|
||||
m_Server->GetGame().NotifyListeners(&game::GameListener::OnGameBegin);
|
||||
m_GameStarted = true;
|
||||
return;
|
||||
}
|
||||
|
||||
m_Timer.Update();
|
||||
m_Timer.Update();
|
||||
}
|
||||
|
||||
void Lobby::SendTimeRemaining() {
|
||||
protocol::UpdateLobbyTimePacket packet(LobbyWaitingTime - (utils::GetTime() - m_StartTimerTime)); // converting second to millis
|
||||
m_Server->BroadcastPacket(&packet);
|
||||
protocol::UpdateLobbyTimePacket packet(LobbyWaitingTime - (utils::GetTime() - m_StartTimerTime)); // converting second to millis
|
||||
m_Server->BroadcastPacket(&packet);
|
||||
}
|
||||
|
||||
void Lobby::OnPlayerJoin(std::uint8_t playerID) {
|
||||
if (m_GameStarted)
|
||||
return;
|
||||
utils::LOG("(Server) Player Joined Lobby !");
|
||||
m_Players.push_back(playerID);
|
||||
if (m_Players.size() == MIN_PLAYER_WAITING) { // start timer if a second player join the match
|
||||
m_StartTimerTime = utils::GetTime();
|
||||
m_Timer.Reset();
|
||||
SendTimeRemaining();
|
||||
}
|
||||
if (m_GameStarted)
|
||||
return;
|
||||
utils::LOG("(Server) Player Joined Lobby !");
|
||||
m_Players.push_back(playerID);
|
||||
if (m_Players.size() == MIN_PLAYER_WAITING) { // start timer if a second player join the match
|
||||
m_StartTimerTime = utils::GetTime();
|
||||
m_Timer.Reset();
|
||||
SendTimeRemaining();
|
||||
}
|
||||
}
|
||||
|
||||
void Lobby::OnPlayerLeave(std::uint8_t playerID) {
|
||||
if (m_GameStarted)
|
||||
return;
|
||||
utils::LOG("(Server) Player Leaved Lobby !");
|
||||
if (m_GameStarted)
|
||||
return;
|
||||
utils::LOG("(Server) Player Leaved Lobby !");
|
||||
|
||||
auto it = std::find(m_Players.begin(), m_Players.end(), playerID);
|
||||
if (it == m_Players.end())
|
||||
return;
|
||||
m_Players.erase(it);
|
||||
auto it = std::find(m_Players.begin(), m_Players.end(), playerID);
|
||||
if (it == m_Players.end())
|
||||
return;
|
||||
m_Players.erase(it);
|
||||
|
||||
if (m_Players.size() == 1) {
|
||||
protocol::UpdateLobbyTimePacket packet(0);
|
||||
m_Server->BroadcastPacket(&packet);
|
||||
m_StartTimerTime = 0; // reset timer if there is only one player left
|
||||
}
|
||||
if (m_Players.size() == 1) {
|
||||
protocol::UpdateLobbyTimePacket packet(0);
|
||||
m_Server->BroadcastPacket(&packet);
|
||||
m_StartTimerTime = 0; // reset timer if there is only one player left
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace server
|
||||
|
||||
@@ -7,139 +7,139 @@ namespace td {
|
||||
namespace server {
|
||||
|
||||
Server::Server(const std::string& worldFilePath) : m_ServerRunning(false) {
|
||||
m_Game.GetWorld()->LoadMapFromFile(worldFilePath);
|
||||
m_Game.GetWorld()->LoadMapFromFile(worldFilePath);
|
||||
}
|
||||
|
||||
Server::~Server() {
|
||||
if (m_Thread.joinable())
|
||||
m_Thread.join();
|
||||
if (m_Thread.joinable())
|
||||
m_Thread.join();
|
||||
}
|
||||
|
||||
void Server::StartThread() {
|
||||
m_Thread = std::thread([this]() {
|
||||
std::uint64_t lastTime = td::utils::GetTime();
|
||||
while (m_ServerRunning) {
|
||||
std::uint64_t time = td::utils::GetTime();
|
||||
m_Thread = std::thread([this]() {
|
||||
std::uint64_t lastTime = td::utils::GetTime();
|
||||
while (m_ServerRunning) {
|
||||
std::uint64_t time = td::utils::GetTime();
|
||||
|
||||
std::uint64_t delta = time - lastTime;
|
||||
std::uint64_t delta = time - lastTime;
|
||||
|
||||
if (delta >= SERVER_TICK) {
|
||||
Tick(delta);
|
||||
lastTime = td::utils::GetTime();
|
||||
std::uint64_t sleepTime = SERVER_TICK - (delta - SERVER_TICK);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(sleepTime));
|
||||
}
|
||||
if (delta >= SERVER_TICK) {
|
||||
Tick(delta);
|
||||
lastTime = td::utils::GetTime();
|
||||
std::uint64_t sleepTime = SERVER_TICK - (delta - SERVER_TICK);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(sleepTime));
|
||||
}
|
||||
|
||||
}
|
||||
Clean();
|
||||
});
|
||||
}
|
||||
Clean();
|
||||
});
|
||||
}
|
||||
|
||||
void Server::Close() {
|
||||
StopThread();
|
||||
StopThread();
|
||||
}
|
||||
|
||||
void Server::StopThread() {
|
||||
m_ServerRunning = false;
|
||||
m_ServerRunning = false;
|
||||
}
|
||||
|
||||
bool Server::Start(std::uint16_t port) {
|
||||
if (!m_Listener.Listen(port, 10)) {
|
||||
utils::LOGE(utils::format("Failed to bind port %u !", port));
|
||||
return false;
|
||||
}
|
||||
if (!m_Listener.SetBlocking(false)) {
|
||||
utils::LOGE("Failed to block server socket !");
|
||||
return false;
|
||||
}
|
||||
utils::LOG(utils::format("Server started at port %u !", port));
|
||||
m_TickCounter.Reset();
|
||||
m_ServerRunning = true;
|
||||
StartThread();
|
||||
return true;
|
||||
if (!m_Listener.Listen(port, 10)) {
|
||||
utils::LOGE(utils::format("Failed to bind port %u !", port));
|
||||
return false;
|
||||
}
|
||||
if (!m_Listener.SetBlocking(false)) {
|
||||
utils::LOGE("Failed to block server socket !");
|
||||
return false;
|
||||
}
|
||||
utils::LOG(utils::format("Server started at port %u !", port));
|
||||
m_TickCounter.Reset();
|
||||
m_ServerRunning = true;
|
||||
StartThread();
|
||||
return true;
|
||||
}
|
||||
|
||||
void Server::Clean() {
|
||||
m_Listener.Close();
|
||||
m_Listener.Destroy();
|
||||
m_Listener.Close();
|
||||
m_Listener.Destroy();
|
||||
|
||||
m_Connections.clear();
|
||||
GetPlayers().clear();
|
||||
m_Connections.clear();
|
||||
GetPlayers().clear();
|
||||
|
||||
utils::LOG("Server successfully stopped !");
|
||||
utils::LOG("Server successfully stopped !");
|
||||
}
|
||||
|
||||
void Server::Stop() {
|
||||
if (!m_ServerRunning)
|
||||
return;
|
||||
if (!m_ServerRunning)
|
||||
return;
|
||||
|
||||
protocol::DisconnectPacket packet("Server closed");
|
||||
BroadcastPacket(&packet);
|
||||
protocol::DisconnectPacket packet("Server closed");
|
||||
BroadcastPacket(&packet);
|
||||
|
||||
StopThread();
|
||||
StopThread();
|
||||
}
|
||||
|
||||
void Server::Tick(std::uint64_t delta) {
|
||||
Accept();
|
||||
UpdateSockets();
|
||||
m_Lobby.Tick();
|
||||
m_Game.Tick(delta);
|
||||
if (m_TickCounter.Update()) {
|
||||
protocol::ServerTpsPacket packet(m_TickCounter.GetTPS(), utils::GetTime());
|
||||
BroadcastPacket(&packet);
|
||||
}
|
||||
Accept();
|
||||
UpdateSockets();
|
||||
m_Lobby.Tick();
|
||||
m_Game.Tick(delta);
|
||||
if (m_TickCounter.Update()) {
|
||||
protocol::ServerTpsPacket packet(m_TickCounter.GetTPS(), utils::GetTime());
|
||||
BroadcastPacket(&packet);
|
||||
}
|
||||
}
|
||||
|
||||
void Server::Accept() {
|
||||
static std::uint8_t newPlayerID = 0;
|
||||
network::TCPSocket newSocket;
|
||||
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++;
|
||||
}
|
||||
static std::uint8_t newPlayerID = 0;
|
||||
network::TCPSocket newSocket;
|
||||
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::UpdateSockets() {
|
||||
std::int16_t closedConnexionID = -1;
|
||||
for (auto& connection : m_Connections) {
|
||||
ServerConnexion& con = connection.second;
|
||||
if (con.GetSocketStatus() != network::Socket::Status::Connected) {
|
||||
closedConnexionID = connection.first;
|
||||
} else {
|
||||
con.UpdateSocket();
|
||||
}
|
||||
}
|
||||
if (closedConnexionID != -1) {
|
||||
RemoveConnexion(closedConnexionID);
|
||||
}
|
||||
std::int16_t closedConnexionID = -1;
|
||||
for (auto& connection : m_Connections) {
|
||||
ServerConnexion& con = connection.second;
|
||||
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);
|
||||
}
|
||||
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);
|
||||
GetPlayers().erase(GetPlayers().find(connexionID));
|
||||
m_Connections.erase(connexionID);
|
||||
m_Lobby.OnPlayerLeave(connexionID);
|
||||
OnPlayerLeave(connexionID);
|
||||
}
|
||||
|
||||
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) {
|
||||
protocol::PlayerLeavePacket packet(id);
|
||||
BroadcastPacket(&packet);
|
||||
protocol::PlayerLeavePacket packet(id);
|
||||
BroadcastPacket(&packet);
|
||||
}
|
||||
|
||||
} // namespace server
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace td {
|
||||
namespace server {
|
||||
|
||||
/*
|
||||
NEVER TRUST USER INPUT
|
||||
NEVER TRUST USER INPUT
|
||||
*/
|
||||
|
||||
|
||||
@@ -23,176 +23,176 @@ 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) {
|
||||
Connexion::UpdateSocket();
|
||||
Connexion::UpdateSocket();
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
move.m_Server = nullptr;
|
||||
RegisterHandlers();
|
||||
move.m_Server = nullptr;
|
||||
RegisterHandlers();
|
||||
}
|
||||
|
||||
void ServerConnexion::RegisterHandlers() {
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::PlayerLogin, this);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::KeepAlive, this);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::SelectTeam, this);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::Disconnect, this);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::PlaceTower, this);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::SendMobs, this);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::UpgradeTower, this);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::RemoveTower, this);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::PlayerLogin, this);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::KeepAlive, this);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::SelectTeam, this);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::Disconnect, this);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::PlaceTower, this);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::SendMobs, this);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::UpgradeTower, this);
|
||||
GetDispatcher()->RegisterHandler(protocol::PacketType::RemoveTower, this);
|
||||
}
|
||||
|
||||
bool ServerConnexion::UpdateSocket() {
|
||||
CheckKeepAlive();
|
||||
return Connexion::UpdateSocket();
|
||||
CheckKeepAlive();
|
||||
return Connexion::UpdateSocket();
|
||||
}
|
||||
|
||||
void ServerConnexion::CheckKeepAlive() {
|
||||
std::uint64_t time = utils::GetTime();
|
||||
if (time - m_KeepAlive.sendTime > KEEP_ALIVE_TIMEOUT) {
|
||||
if (m_KeepAlive.recievedResponse) {
|
||||
SendKeepAlive();
|
||||
} else {
|
||||
protocol::DisconnectPacket packet("Time out");
|
||||
SendPacket(&packet);
|
||||
CloseConnection();
|
||||
}
|
||||
}
|
||||
std::uint64_t time = utils::GetTime();
|
||||
if (time - m_KeepAlive.sendTime > KEEP_ALIVE_TIMEOUT) {
|
||||
if (m_KeepAlive.recievedResponse) {
|
||||
SendKeepAlive();
|
||||
} else {
|
||||
protocol::DisconnectPacket packet("Time out");
|
||||
SendPacket(&packet);
|
||||
CloseConnection();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ServerConnexion::SendKeepAlive() {
|
||||
m_KeepAlive.keepAliveID = utils::GetRandomInt<std::uint64_t>(0, RAND_MAX);
|
||||
m_KeepAlive.recievedResponse = false;
|
||||
m_KeepAlive.keepAliveID = utils::GetRandomInt<std::uint64_t>(0, RAND_MAX);
|
||||
m_KeepAlive.recievedResponse = false;
|
||||
|
||||
protocol::KeepAlivePacket keepAlivePacket(m_KeepAlive.keepAliveID);
|
||||
SendPacket(&keepAlivePacket);
|
||||
protocol::KeepAlivePacket keepAlivePacket(m_KeepAlive.keepAliveID);
|
||||
SendPacket(&keepAlivePacket);
|
||||
|
||||
std::uint64_t time = utils::GetTime();
|
||||
m_KeepAlive.sendTime = time;
|
||||
std::uint64_t time = utils::GetTime();
|
||||
m_KeepAlive.sendTime = time;
|
||||
}
|
||||
|
||||
void ServerConnexion::HandlePacket(const protocol::PlayerLoginPacket* packet) {
|
||||
if (m_Player->GetName().empty() && !packet->GetPlayerName().empty()) {
|
||||
m_Player->SetName(packet->GetPlayerName());
|
||||
if (m_Player->GetName().empty() && !packet->GetPlayerName().empty()) {
|
||||
m_Player->SetName(packet->GetPlayerName());
|
||||
|
||||
protocol::PlayerJoinPacket joinPacket(m_ID, m_Player->GetName());
|
||||
m_Server->BroadcastPacket(&joinPacket);
|
||||
protocol::PlayerJoinPacket joinPacket(m_ID, m_Player->GetName());
|
||||
m_Server->BroadcastPacket(&joinPacket);
|
||||
|
||||
std::map<std::uint8_t, protocol::PlayerInfo> playerNames;
|
||||
for (const auto& pair : m_Server->GetPlayers()) {
|
||||
const game::Player& player = pair.second;
|
||||
if (!player.GetName().empty()) {
|
||||
protocol::PlayerInfo playerInfo;
|
||||
playerInfo.name = player.GetName();
|
||||
playerInfo.team = player.GetTeamColor();
|
||||
playerNames.insert({ player.GetID(), playerInfo });
|
||||
}
|
||||
}
|
||||
std::map<std::uint8_t, protocol::PlayerInfo> playerNames;
|
||||
for (const auto& pair : m_Server->GetPlayers()) {
|
||||
const game::Player& player = pair.second;
|
||||
if (!player.GetName().empty()) {
|
||||
protocol::PlayerInfo playerInfo;
|
||||
playerInfo.name = player.GetName();
|
||||
playerInfo.team = player.GetTeamColor();
|
||||
playerNames.insert({ player.GetID(), playerInfo });
|
||||
}
|
||||
}
|
||||
|
||||
protocol::PlayerListPacket listPacket(playerNames);
|
||||
SendPacket(&listPacket);
|
||||
}
|
||||
protocol::PlayerListPacket listPacket(playerNames);
|
||||
SendPacket(&listPacket);
|
||||
}
|
||||
}
|
||||
|
||||
void ServerConnexion::HandlePacket(const protocol::SelectTeamPacket* packet) {
|
||||
if (m_Server->GetGame().GetGameState() != game::GameState::Lobby)
|
||||
return;
|
||||
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
|
||||
m_Server->GetGame().GetTeam(packet->GetSelectedTeam()).AddPlayer(m_Player);
|
||||
} else if (packet->GetSelectedTeam() == game::TeamColor::None) { // leave a team
|
||||
m_Server->GetGame().GetTeam(m_Player->GetTeamColor()).RemovePlayer(m_Player);
|
||||
m_Player->SetTeamColor(game::TeamColor::None);
|
||||
} else { // change team
|
||||
m_Server->GetGame().GetTeam(m_Player->GetTeamColor()).RemovePlayer(m_Player);
|
||||
m_Server->GetGame().GetTeam(packet->GetSelectedTeam()).AddPlayer(m_Player);
|
||||
}
|
||||
m_Player->SetTeamColor(packet->GetSelectedTeam());
|
||||
protocol::UpdatePlayerTeamPacket updateTeamPacket(m_ID, packet->GetSelectedTeam());
|
||||
m_Server->BroadcastPacket(&updateTeamPacket);
|
||||
}
|
||||
if (m_Server->GetGame().GetGameState() != game::GameState::Lobby)
|
||||
return;
|
||||
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
|
||||
m_Server->GetGame().GetTeam(packet->GetSelectedTeam()).AddPlayer(m_Player);
|
||||
} else if (packet->GetSelectedTeam() == game::TeamColor::None) { // leave a team
|
||||
m_Server->GetGame().GetTeam(m_Player->GetTeamColor()).RemovePlayer(m_Player);
|
||||
m_Player->SetTeamColor(game::TeamColor::None);
|
||||
} else { // change team
|
||||
m_Server->GetGame().GetTeam(m_Player->GetTeamColor()).RemovePlayer(m_Player);
|
||||
m_Server->GetGame().GetTeam(packet->GetSelectedTeam()).AddPlayer(m_Player);
|
||||
}
|
||||
m_Player->SetTeamColor(packet->GetSelectedTeam());
|
||||
protocol::UpdatePlayerTeamPacket updateTeamPacket(m_ID, packet->GetSelectedTeam());
|
||||
m_Server->BroadcastPacket(&updateTeamPacket);
|
||||
}
|
||||
}
|
||||
|
||||
void ServerConnexion::HandlePacket(const protocol::KeepAlivePacket* packet) {
|
||||
if (packet->GetAliveID() == m_KeepAlive.keepAliveID)
|
||||
m_KeepAlive.recievedResponse = true;
|
||||
if (packet->GetAliveID() == m_KeepAlive.keepAliveID)
|
||||
m_KeepAlive.recievedResponse = true;
|
||||
}
|
||||
|
||||
void ServerConnexion::HandlePacket(const protocol::DisconnectPacket* packet) {
|
||||
CloseConnection();
|
||||
CloseConnection();
|
||||
}
|
||||
|
||||
void ServerConnexion::SetServer(Server* server) {
|
||||
m_Server = server;
|
||||
m_Player = &m_Server->GetPlayers().at(m_ID);
|
||||
InitConnection();
|
||||
SendKeepAlive();
|
||||
m_Server = server;
|
||||
m_Player = &m_Server->GetPlayers().at(m_ID);
|
||||
InitConnection();
|
||||
SendKeepAlive();
|
||||
}
|
||||
|
||||
void ServerConnexion::InitConnection() {
|
||||
protocol::UpdateGameStatePacket statePacket(m_Server->GetGame().GetGameState());
|
||||
SendPacket(&statePacket);
|
||||
protocol::UpdateGameStatePacket statePacket(m_Server->GetGame().GetGameState());
|
||||
SendPacket(&statePacket);
|
||||
|
||||
protocol::ConnexionInfoPacket conPacket(m_ID);
|
||||
SendPacket(&conPacket);
|
||||
protocol::ConnexionInfoPacket conPacket(m_ID);
|
||||
SendPacket(&conPacket);
|
||||
|
||||
if (m_Server->GetGame().GetGameState() == game::GameState::Game) {
|
||||
protocol::WorldBeginDataPacket headerDataPacket(m_Server->GetGame().GetWorld());
|
||||
protocol::WorldBeginDataPacket dataPacket(m_Server->GetGame().GetWorld());
|
||||
SendPacket(&headerDataPacket);
|
||||
SendPacket(&dataPacket);
|
||||
}
|
||||
if (m_Server->GetGame().GetGameState() == game::GameState::Game) {
|
||||
protocol::WorldBeginDataPacket headerDataPacket(m_Server->GetGame().GetWorld());
|
||||
protocol::WorldBeginDataPacket dataPacket(m_Server->GetGame().GetWorld());
|
||||
SendPacket(&headerDataPacket);
|
||||
SendPacket(&dataPacket);
|
||||
}
|
||||
}
|
||||
|
||||
void ServerConnexion::HandlePacket(const protocol::PlaceTowerPacket* packet) {
|
||||
game::TowerType towerType = packet->GetTowerType();
|
||||
const game::TowerInfo& towerInfo = game::GetTowerInfo(towerType);
|
||||
server::ServerWorld* world = m_Server->GetGame().GetServerWorld();
|
||||
game::TowerType towerType = packet->GetTowerType();
|
||||
const game::TowerInfo& towerInfo = game::GetTowerInfo(towerType);
|
||||
server::ServerWorld* world = m_Server->GetGame().GetServerWorld();
|
||||
|
||||
Vec2f towerPos = { static_cast<float>(packet->GetTowerX()), static_cast<float>(packet->GetTowerY()) };
|
||||
Vec2f towerPos = { static_cast<float>(packet->GetTowerX()), static_cast<float>(packet->GetTowerY()) };
|
||||
|
||||
if (!world->CanPlaceLittleTower(towerPos, m_ID))
|
||||
return;
|
||||
if (!world->CanPlaceLittleTower(towerPos, m_ID))
|
||||
return;
|
||||
|
||||
if (towerInfo.IsBigTower())
|
||||
if (!world->CanPlaceBigTower(towerPos, m_ID))
|
||||
return;
|
||||
if (towerInfo.IsBigTower())
|
||||
if (!world->CanPlaceBigTower(towerPos, m_ID))
|
||||
return;
|
||||
|
||||
game::TowerPtr tower = world->PlaceTowerAt(towerType, packet->GetTowerX(), packet->GetTowerY(), m_ID);
|
||||
game::TowerPtr tower = world->PlaceTowerAt(towerType, packet->GetTowerX(), packet->GetTowerY(), m_ID);
|
||||
|
||||
world->GetWorldNotifier().NotifyListeners(&game::WorldListener::OnTowerAdd, tower);
|
||||
world->GetWorldNotifier().NotifyListeners(&game::WorldListener::OnTowerAdd, tower);
|
||||
|
||||
protocol::WorldAddTowerPacket addTowerPacket(tower->GetID(), packet->GetTowerX(), packet->GetTowerY(), packet->GetTowerType(), m_ID);
|
||||
m_Server->BroadcastPacket(&addTowerPacket);
|
||||
protocol::WorldAddTowerPacket addTowerPacket(tower->GetID(), packet->GetTowerX(), packet->GetTowerY(), packet->GetTowerType(), m_ID);
|
||||
m_Server->BroadcastPacket(&addTowerPacket);
|
||||
}
|
||||
|
||||
void ServerConnexion::HandlePacket(const protocol::SendMobsPacket* packet) {
|
||||
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) {
|
||||
m_Server->GetGame().GetServerWorld()->SpawnMobs(mobSend.mobType, mobSend.mobLevel, m_ID, mobSend.mobCount);
|
||||
}
|
||||
for (protocol::MobSend mobSend : mobSent) {
|
||||
m_Server->GetGame().GetServerWorld()->SpawnMobs(mobSend.mobType, mobSend.mobLevel, m_ID, mobSend.mobCount);
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
//TODO: verify the packet
|
||||
|
||||
m_Server->BroadcastPacket(packet);
|
||||
m_Server->BroadcastPacket(packet);
|
||||
}
|
||||
|
||||
ServerConnexion::~ServerConnexion() {
|
||||
if (GetDispatcher() != nullptr)
|
||||
GetDispatcher()->UnregisterHandler(this);
|
||||
if (GetDispatcher() != nullptr)
|
||||
GetDispatcher()->UnregisterHandler(this);
|
||||
}
|
||||
|
||||
} // namespace server
|
||||
|
||||
@@ -8,113 +8,113 @@ ServerGame::ServerGame(server::Server* server) : game::Game(&m_ServerWorld), m_S
|
||||
m_GoldMineTimer{ 1000, std::bind(&ServerGame::UpdateGoldMines, this) },
|
||||
m_MobStatesTimer{ 5000, std::bind(&ServerGame::UpdateMobStates, this) },
|
||||
m_EndGameCooldown{ 1000 * 10 } {
|
||||
BindListener(this);
|
||||
BindListener(this);
|
||||
}
|
||||
|
||||
void ServerGame::Tick(std::uint64_t delta) {
|
||||
if (m_GameState == game::GameState::Game) {
|
||||
Game::Tick(delta);
|
||||
m_MobStatesTimer.Update(delta);
|
||||
UpdatePlayerStats();
|
||||
} else if (m_GameState == game::GameState::EndGame) {
|
||||
if (m_EndGameCooldown.Update(delta)) {
|
||||
NotifyListeners(&game::GameListener::OnGameClose);
|
||||
}
|
||||
}
|
||||
if (m_GameState == game::GameState::Game) {
|
||||
Game::Tick(delta);
|
||||
m_MobStatesTimer.Update(delta);
|
||||
UpdatePlayerStats();
|
||||
} else if (m_GameState == game::GameState::EndGame) {
|
||||
if (m_EndGameCooldown.Update(delta)) {
|
||||
NotifyListeners(&game::GameListener::OnGameClose);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ServerGame::StartGame() {
|
||||
BalanceTeams();
|
||||
BalanceTeams();
|
||||
|
||||
protocol::WorldBeginDataPacket headerMapData(m_World);
|
||||
m_Server->BroadcastPacket(&headerMapData);
|
||||
protocol::WorldBeginDataPacket headerMapData(m_World);
|
||||
m_Server->BroadcastPacket(&headerMapData);
|
||||
|
||||
protocol::WorldDataPacket mapData(m_World);
|
||||
m_Server->BroadcastPacket(&mapData);
|
||||
protocol::WorldDataPacket mapData(m_World);
|
||||
m_Server->BroadcastPacket(&mapData);
|
||||
|
||||
InitPlayerStats();
|
||||
InitPlayerStats();
|
||||
|
||||
m_GameState = game::GameState::Game;
|
||||
m_GameState = game::GameState::Game;
|
||||
}
|
||||
|
||||
void ServerGame::InitPlayerStats() {
|
||||
static const unsigned int START_GOLD = 100;
|
||||
static const unsigned int START_EXP = 0;
|
||||
for (auto& [id, player] : m_Server->GetPlayers()) {
|
||||
player.SetGold(START_GOLD);
|
||||
player.SetExp(START_EXP);
|
||||
player.getUpgrades().SetGoldPerSecond(5);
|
||||
}
|
||||
static const unsigned int START_GOLD = 100;
|
||||
static const unsigned int START_EXP = 0;
|
||||
for (auto& [id, player] : m_Server->GetPlayers()) {
|
||||
player.SetGold(START_GOLD);
|
||||
player.SetExp(START_EXP);
|
||||
player.getUpgrades().SetGoldPerSecond(5);
|
||||
}
|
||||
}
|
||||
|
||||
void ServerGame::UpdatePlayerStats() {
|
||||
m_GoldMineTimer.Update();
|
||||
m_GoldMineTimer.Update();
|
||||
}
|
||||
|
||||
void ServerGame::UpdateGoldMines() {
|
||||
for (auto& [id, player] : m_Server->GetPlayers()) {
|
||||
player.AddGold(player.getUpgrades().GetGoldPerSecond());
|
||||
for (auto& [id, player] : m_Server->GetPlayers()) {
|
||||
player.AddGold(player.getUpgrades().GetGoldPerSecond());
|
||||
|
||||
// Update player money and exp every second
|
||||
protocol::UpdateMoneyPacket moneyPacket(player.GetGold());
|
||||
m_Server->GetConnexions()[player.GetID()].SendPacket(&moneyPacket);
|
||||
// Update player money and exp every second
|
||||
protocol::UpdateMoneyPacket moneyPacket(player.GetGold());
|
||||
m_Server->GetConnexions()[player.GetID()].SendPacket(&moneyPacket);
|
||||
|
||||
protocol::UpdateExpPacket expPacket(player.GetExp());
|
||||
m_Server->GetConnexions()[player.GetID()].SendPacket(&expPacket);
|
||||
}
|
||||
protocol::UpdateExpPacket expPacket(player.GetExp());
|
||||
m_Server->GetConnexions()[player.GetID()].SendPacket(&expPacket);
|
||||
}
|
||||
}
|
||||
|
||||
void ServerGame::UpdateMobStates() {
|
||||
protocol::UpdateMobStatesPacket packet;
|
||||
for (auto mob : m_World->GetMobList()) {
|
||||
packet.addMobState({ mob->GetMobID(), mob->GetCenter(), mob->GetHealth(), mob->GetDirection() });
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
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);
|
||||
SetGameState(newState);
|
||||
protocol::UpdateGameStatePacket packet(newState);
|
||||
m_Server->BroadcastPacket(&packet);
|
||||
}
|
||||
|
||||
void ServerGame::OnGameBegin() {
|
||||
NotifyListeners(&game::GameListener::OnGameStateUpdate, game::GameState::Game);
|
||||
StartGame();
|
||||
NotifyListeners(&game::GameListener::OnGameStateUpdate, game::GameState::Game);
|
||||
StartGame();
|
||||
}
|
||||
|
||||
void ServerGame::OnGameEnd() {
|
||||
NotifyListeners(&game::GameListener::OnGameStateUpdate, game::GameState::EndGame);
|
||||
m_EndGameCooldown.ApplyCooldown();
|
||||
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);
|
||||
NotifyListeners(&game::GameListener::OnGameStateUpdate, game::GameState::Closed);
|
||||
// Disconnect clients
|
||||
protocol::DisconnectPacket packet("Game finished");
|
||||
m_Server->BroadcastPacket(&packet);
|
||||
|
||||
// Closing server
|
||||
m_Server->Close();
|
||||
// Closing server
|
||||
m_Server->Close();
|
||||
}
|
||||
|
||||
} // namespace game
|
||||
|
||||
@@ -12,66 +12,66 @@ 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) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
game::TeamColor senderTeam = m_Game->GetPlayers().at(sender).GetTeamColor();
|
||||
game::Spawn* enemyMobSpawn;
|
||||
for (int i = 0; i < count; i++) {
|
||||
game::TeamColor senderTeam = m_Game->GetPlayers().at(sender).GetTeamColor();
|
||||
game::Spawn* enemyMobSpawn;
|
||||
|
||||
if (senderTeam == game::TeamColor::Red) {
|
||||
enemyMobSpawn = &GetTeam(game::TeamColor::Blue).GetSpawn();
|
||||
} else {
|
||||
enemyMobSpawn = &GetTeam(game::TeamColor::Red).GetSpawn();
|
||||
}
|
||||
if (senderTeam == game::TeamColor::Red) {
|
||||
enemyMobSpawn = &GetTeam(game::TeamColor::Blue).GetSpawn();
|
||||
} else {
|
||||
enemyMobSpawn = &GetTeam(game::TeamColor::Red).GetSpawn();
|
||||
}
|
||||
|
||||
float spawnWidth = enemyMobSpawn->GetWidth();
|
||||
float spawnHeight = enemyMobSpawn->GetHeight();
|
||||
float spawnWidth = enemyMobSpawn->GetWidth();
|
||||
float spawnHeight = enemyMobSpawn->GetHeight();
|
||||
|
||||
float spawnCenterX = enemyMobSpawn->GetCenterX();
|
||||
float spawnCenterY = enemyMobSpawn->GetCenterY();
|
||||
float spawnCenterX = enemyMobSpawn->GetCenterX();
|
||||
float spawnCenterY = enemyMobSpawn->GetCenterY();
|
||||
|
||||
auto mobStats = GetMobStats(type, level);
|
||||
auto mobSize = mobStats->GetSize();
|
||||
auto mobStats = GetMobStats(type, level);
|
||||
auto mobSize = mobStats->GetSize();
|
||||
|
||||
float minSpawnX = spawnCenterX - spawnWidth / 2.0f + mobSize.x / 2.0f;
|
||||
float maxSpawnX = spawnCenterX + spawnWidth / 2.0f - mobSize.x / 2.0f;
|
||||
float minSpawnX = spawnCenterX - spawnWidth / 2.0f + mobSize.x / 2.0f;
|
||||
float maxSpawnX = spawnCenterX + spawnWidth / 2.0f - mobSize.x / 2.0f;
|
||||
|
||||
float minSpawnY = spawnCenterY - spawnHeight / 2.0f + mobSize.y / 2.0f;
|
||||
float maxSpawnY = spawnCenterY + spawnHeight / 2.0f - mobSize.y / 2.0f;
|
||||
float minSpawnY = spawnCenterY - spawnHeight / 2.0f + mobSize.y / 2.0f;
|
||||
float maxSpawnY = spawnCenterY + spawnHeight / 2.0f - mobSize.y / 2.0f;
|
||||
|
||||
float mobX = utils::GetRandomReal<float>(minSpawnX + MobSpawnBorder, maxSpawnX - MobSpawnBorder);
|
||||
float mobY = utils::GetRandomReal<float>(minSpawnY + MobSpawnBorder, maxSpawnY - MobSpawnBorder);
|
||||
float mobX = utils::GetRandomReal<float>(minSpawnX + MobSpawnBorder, maxSpawnX - MobSpawnBorder);
|
||||
float mobY = utils::GetRandomReal<float>(minSpawnY + MobSpawnBorder, maxSpawnY - MobSpawnBorder);
|
||||
|
||||
SpawnMobAt(m_CurrentMobID, type, level, sender, mobX, mobY, enemyMobSpawn->GetDirection());
|
||||
SpawnMobAt(m_CurrentMobID, type, level, sender, mobX, mobY, enemyMobSpawn->GetDirection());
|
||||
|
||||
protocol::SpawnMobPacket packet(m_CurrentMobID, type, level, sender, mobX, mobY, enemyMobSpawn->GetDirection());
|
||||
m_Server->BroadcastPacket(&packet);
|
||||
protocol::SpawnMobPacket packet(m_CurrentMobID, type, level, sender, mobX, mobY, enemyMobSpawn->GetDirection());
|
||||
m_Server->BroadcastPacket(&packet);
|
||||
|
||||
m_CurrentMobID++;
|
||||
}
|
||||
m_CurrentMobID++;
|
||||
}
|
||||
}
|
||||
|
||||
game::TowerPtr ServerWorld::PlaceTowerAt(game::TowerType type, std::int32_t x, std::int32_t y, game::PlayerID builder) {
|
||||
game::TowerPtr tower = World::PlaceTowerAt(m_CurrentTowerID, type, x, y, builder);
|
||||
m_CurrentTowerID++;
|
||||
return tower;
|
||||
game::TowerPtr tower = World::PlaceTowerAt(m_CurrentTowerID, type, x, y, builder);
|
||||
m_CurrentTowerID++;
|
||||
return tower;
|
||||
}
|
||||
|
||||
void ServerWorld::OnMobDie(game::Mob* mob) {
|
||||
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());
|
||||
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());
|
||||
}
|
||||
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);
|
||||
// calling base class event
|
||||
World::OnMobCastleDamage(damager, enemyCastle, damage);
|
||||
|
||||
protocol::UpdateCastleLifePacket packet(enemyCastle->GetLife(), enemyCastle->GetTeam()->GetColor());
|
||||
m_Server->BroadcastPacket(&packet);
|
||||
protocol::UpdateCastleLifePacket packet(enemyCastle->GetLife(), enemyCastle->GetTeam()->GetColor());
|
||||
m_Server->BroadcastPacket(&packet);
|
||||
}
|
||||
|
||||
} // namespace server
|
||||
|
||||
Reference in New Issue
Block a user