#pragma once #include #include #include #include #include #include "Mobs.h" #include "Team.h" namespace td { namespace game { struct ChunkCoord { std::int16_t x, y; friend bool operator==(const td::game::ChunkCoord& first, const td::game::ChunkCoord& other) { return first.x == other.x && first.y == other.y; } }; } } namespace std { template <> struct hash { std::size_t operator()(const td::game::ChunkCoord& key) const noexcept { return std::hash()(key.x << 16 | key.y); } }; } namespace td { namespace protocol { class WorldBeginDataPacket; class WorldDataPacket; } namespace game { class Game; enum class TileType : std::uint8_t { None = 0, Tower, Walk, Decoration, /*Heal, Lava, Bedrock, Freeze, Ice,*/ }; static constexpr Color BLACK{ 0, 0, 0 }; static constexpr Color WHITE{ 255, 255, 255 }; static constexpr Color RED{ 255, 0, 0 }; static constexpr Color GREEN{ 0, 255, 0 }; static constexpr Color BLUE{ 0, 0, 255 }; struct Tile { virtual TileType GetType() const = 0; }; struct TowerTile : Tile { std::uint8_t color_palette_ref; TeamColor team_owner; virtual TileType GetType() const { return TileType::Tower; } }; struct WalkableTile : Tile { Direction direction; virtual TileType GetType() const { return TileType::Walk; } }; struct DecorationTile : Tile { std::uint16_t color_palette_ref; virtual TileType GetType() const { return TileType::Decoration; } }; typedef std::shared_ptr TilePtr; typedef std::vector ChunkPalette; typedef std::shared_ptr WalkableTilePtr; typedef std::uint32_t TileIndex; //32 x 32 area struct Chunk { enum { ChunkWidth = 32, ChunkHeight = 32, ChunkSize = ChunkWidth * ChunkHeight }; typedef std::array ChunkData; // stores index of tile palette ChunkData tiles{ 0 }; ChunkPalette palette; TileIndex GetTileIndex(std::uint16_t tileNumber) const { TileIndex chunkPaletteIndex = tiles.at(tileNumber); if (chunkPaletteIndex == 0) // index 0 means empty tile index 1 = first tile return 0; return palette.at(chunkPaletteIndex); } }; typedef std::shared_ptr ChunkPtr; typedef std::array TowerTileColorPalette; typedef std::vector TilePalette; typedef std::vector MobList; typedef std::array SpawnColorPalette; typedef std::vector TowerList; class WorldListener { public: WorldListener() {} virtual void OnTowerAdd(TowerPtr tower) {} virtual void OnTowerRemove(TowerPtr tower) {} virtual void OnArcherTowerShot(MobPtr target, ArcherTower* shooter) {} virtual void OnArrowShot(MobPtr target, bool fire, Tower* shooter) {} virtual void OnExplosion(utils::shape::Circle explosion, float centerDamage, Tower* shooter) {} }; typedef utils::ObjectNotifier WorldNotifier; class World : public WorldListener, public MobListener { protected: TowerTileColorPalette m_TowerPlacePalette; Color m_WalkablePalette; std::vector m_DecorationPalette; Color m_Background; std::unordered_map m_Chunks; SpawnColorPalette m_SpawnColorPalette; TilePalette m_TilePalette; MobList m_Mobs; TowerList m_Towers; Game* m_Game; WorldNotifier m_WorldNotifier; MobNotifier m_MobNotifier; public: World(Game* game); bool LoadMap(const protocol::WorldBeginDataPacket* worldHeader); bool LoadMap(const protocol::WorldDataPacket* worldData); bool LoadMapFromFile(const std::string& fileName); bool SaveMap(const std::string& fileName) const; void Tick(std::uint64_t delta); void Reset(); // clear mobs and towers void SpawnMobAt(MobID id, MobType type, std::uint8_t level, PlayerID sender, float x, float y, Direction dir); TowerPtr PlaceTowerAt(TowerID id, TowerType type, std::int32_t x, std::int32_t y, PlayerID builder); TowerPtr RemoveTower(TowerID id); TilePtr GetTile(std::int32_t x, std::int32_t y) const; const TowerTileColorPalette& GetTowerTileColorPalette() const { return m_TowerPlacePalette; } const Color& GetWalkableTileColor() const { return m_WalkablePalette; } const std::vector& GetDecorationPalette() const { return m_DecorationPalette; } const Color& GetBackgroundColor() const { return m_Background; } const TilePalette& GetTilePalette() const { return m_TilePalette; } TilePtr GetTilePtr(TileIndex index) const { if (index == 0) return nullptr; return m_TilePalette.at(index - 1); } bool CanPlaceLittleTower(const Vec2f& worldPos, PlayerID player) const; bool CanPlaceBigTower(const Vec2f& worldPos, PlayerID player) const; TowerPtr GetTower(const Vec2f& position) const; // returns null if no tower is here const std::unordered_map& GetChunks() const { return m_Chunks; } const Color& GetSpawnColor(TeamColor color) const { return m_SpawnColorPalette[static_cast(color)]; } const SpawnColorPalette& GetSpawnColors() const { return m_SpawnColorPalette; } const MobList& GetMobList() const { return m_Mobs; } MobList& GetMobList() { return m_Mobs; } const Color* GetTileColor(TilePtr tile) const; Team& GetRedTeam(); const Team& GetRedTeam() const; Team& GetBlueTeam(); const Team& GetBlueTeam() const; Team& GetTeam(TeamColor team); const Team& GetTeam(TeamColor team) const; const TeamList& GetTeams() const; TowerList& GetTowers() { return m_Towers; } const TowerList& GetTowers() const { return m_Towers; } TowerPtr GetTowerById(TowerID tower); const Player* GetPlayerById(PlayerID id) const; WorldNotifier& GetWorldNotifier() { return m_WorldNotifier; } MobNotifier& GetMobNotifier() { return m_MobNotifier; } // WorldListener virtual void OnArcherTowerShot(MobPtr target, ArcherTower* shooter) override; virtual void OnArrowShot(MobPtr target, bool fire, Tower* shooter) override; virtual void OnExplosion(utils::shape::Circle explosion, float centerDamage, Tower* shooter) override; // MobListener virtual void OnMobDamage(Mob* target, float damage, Tower* source) override; virtual void OnMobCastleDamage(Mob* damager, TeamCastle* enemyCastle, float damage) override; private: void TickMobs(std::uint64_t delta); void CleanDeadMobs(); }; } // namespace game } // namespace td