diff --git a/.gitignore b/.gitignore
index 50ca99b..e12a977 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,2 @@
-.idea/**/workspace.xml
-.idea/**/tasks.xml
+.idea/**
/cmake-build-*/
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b6c9ede..fae5755 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,20 +1,55 @@
cmake_minimum_required(VERSION 3.6)
+
project(TowerDefense)
+project(server)
set(CMAKE_CXX_STANDARD 17)
-add_executable(${PROJECT_NAME} src/main.cpp src/Game.cpp src/Game.h src/ResourceManager/ResourcesHolder.h
+add_executable(server src/server_main.cpp
+ src/GameOverState.h src/GameOverState.cpp src/WinState.cpp src/WinState.h
+ src/Game.cpp src/Game.h src/ResourceManager/ResourcesHolder.h
+ src/ResourceManager/ResourcesIdentifier.h src/Graphics/Button.cpp src/Graphics/Button.h src/GameContext.h
+ src/GameState.cpp src/GameState.h src/GameStates.h src/Graphics/Gui.cpp src/Graphics/Gui.h src/Graphics/HUD.cpp src/Graphics/HUD.h
+ src/Graphics/Icon.h src/Graphics/Icon.cpp src/Graphics/Label.cpp src/Graphics/Label.h src/MenuState.cpp src/MenuState.h
+ src/PauseState.cpp src/PauseState.h src/State.cpp src/State.h src/StateManager.cpp
+ src/StateManager.h src/Graphics/Widget.h src/Map.h src/Map.cpp src/Constants.h src/Tile.h src/Tile.cpp
+ src/Units/Warrior/Warrior.cpp src/Units/Warrior/Warrior.h src/Units/Warrior/WarriorLvlOne.cpp
+ src/Units/Warrior/WarriorLvlOne.h
+ src/Units/Warrior/WarriorLvlTwo.cpp src/Units/Warrior/WarriorLvlTwo.h src/Units/Tower/Tower.cpp src/Units/Tower/Tower.h
+ src/Units/GameUnit.cpp src/Units/GameUnit.h src/Units/Tower/TowerLvlZero.cpp src/Units/Tower/TowerLvlZero.h
+ src/Units/Tower/TowerLvlOne.cpp src/Units/Tower/TowerLvlOne.h src/Units/Tower/TowerLvlTwo.cpp src/Units/Tower/TowerLvlTwo.h
+ src/Units/Bullet/Bullet.cpp src/Units/Bullet/Bullet.h src/Units/Bullet/BulletLvlOne.cpp src/Units/Bullet/BulletLvlOne.h
+ src/Units/Bullet/BulletLvlTwo.h src/Units/Bullet/BulletLvlTwo.cpp src/Units/Tower/TowerLvlThree.cpp src/Units/Tower/TowerLvlThree.h
+ src/Graphics/TextBox.h src/Graphics/TextBox.cpp src/ConnectGameState.h src/ConnectGameState.cpp
+ src/Units/Bullet/BulletLvlTwo.h src/Units/Bullet/BulletLvlTwo.cpp src/Units/Tower/TowerLvlThree.cpp src/Units/Tower/TowerLvlThree.h src/Castle/Castle.cpp src/Castle/Castle.h src/Castle/Building/Building.cpp src/Castle/Building/Building.h src/Castle/Building/Farm.cpp src/Castle/Building/Farm.h src/Castle/Building/Barracks.cpp src/Castle/Building/Barracks.h src/Castle/Building/Weapons.cpp src/Castle/Building/Weapons.h
+ src/Graphics/GraphicsUnits/GraphicsCastle.cpp src/Graphics/GraphicsUnits/GraphicsCastle.h src/Graphics/GraphicsUnits/GraphicsTower.cpp src/Graphics/GraphicsUnits/GraphicsTower.h src/Graphics/GraphicsUnits/GraphicsWarrior.cpp src/Graphics/GraphicsUnits/GraphicsWarrior.h src/Graphics/GraphicsUnits/GraphicsBullet.cpp src/Graphics/GraphicsUnits/GraphicsBullet.h src/Units/Bullet/BulletLvlThree.cpp src/Units/Bullet/BulletLvlThree.h src/Graphics/GraphicsUnits/GraphicsUnitManager.cpp src/Graphics/GraphicsUnits/GraphicsUnitManager.h src/Units/LogicUnitsManager.cpp src/Units/LogicUnitsManager.h src/GameConstants.cpp src/GameConstants.h
+ src/Multiplayer/MultiplayerFacade/AbstractMultiplayerFacade.cpp src/Multiplayer/MultiplayerFacade/AbstractMultiplayerFacade.h src/Multiplayer/MultiplayerFacade/ClientMultiplayerFacade.cpp src/Multiplayer/MultiplayerFacade/ClientMultiplayerFacade.h src/Multiplayer/MultiplayerFacade/ServerMultiplayerFacade.cpp src/Multiplayer/MultiplayerFacade/ServerMultiplayerFacade.h src/Multiplayer/ConnectionFacade/AbstractConnectionFacade.cpp src/Multiplayer/ConnectionFacade/AbstractConnectionFacade.h src/Multiplayer/ConnectionFacade/ServerConnectionFacade.cpp src/Multiplayer/ConnectionFacade/ServerConnectionFacade.h src/Multiplayer/ConnectionFacade/ClientConnectionFacade.cpp src/Multiplayer/ConnectionFacade/ClientConnectionFacade.h src/Multiplayer/Entities/Event.cpp src/Multiplayer/Entities/Event.h src/Multiplayer/Entities/Entity.cpp src/Multiplayer/Entities/Entity.h src/Multiplayer/Entities/Player.cpp src/Multiplayer/Entities/Player.h src/Multiplayer/Entities/Game.cpp src/Multiplayer/Entities/Game.h src/Multiplayer/Manager/Manager.cpp src/Multiplayer/Manager/Manager.h src/Multiplayer/Manager/PlayerManager.cpp src/Multiplayer/Manager/PlayerManager.h src/Multiplayer/Worker.cpp src/Multiplayer/Worker.h src/Multiplayer/Master.cpp src/Multiplayer/Master.h)
+
+
+add_executable(TowerDefense src/main.cpp src/GameOverState.h src/GameOverState.cpp src/WinState.cpp src/WinState.h src/Game.cpp src/Game.h src/ResourceManager/ResourcesHolder.h
src/ResourceManager/ResourcesIdentifier.h src/Graphics/Button.cpp src/Graphics/Button.h src/GameContext.h
src/GameState.cpp src/GameState.h src/GameStates.h src/Graphics/Gui.cpp src/Graphics/Gui.h src/Graphics/HUD.cpp src/Graphics/HUD.h
src/Graphics/Icon.h src/Graphics/Icon.cpp src/Graphics/Label.cpp src/Graphics/Label.h src/MenuState.cpp src/MenuState.h
src/PauseState.cpp src/PauseState.h src/State.cpp src/State.h src/StateManager.cpp
- src/StateManager.h src/Graphics/Widget.h)
+ src/StateManager.h src/Graphics/Widget.h src/Map.h src/Map.cpp src/Constants.h src/Tile.h src/Tile.cpp
+ src/Units/Warrior/Warrior.cpp src/Units/Warrior/Warrior.h src/Units/Warrior/WarriorLvlOne.cpp
+ src/Units/Warrior/WarriorLvlOne.h
+ src/Units/Warrior/WarriorLvlTwo.cpp src/Units/Warrior/WarriorLvlTwo.h src/Units/Tower/Tower.cpp src/Units/Tower/Tower.h
+ src/Units/GameUnit.cpp src/Units/GameUnit.h src/Units/Tower/TowerLvlZero.cpp src/Units/Tower/TowerLvlZero.h
+ src/Units/Tower/TowerLvlOne.cpp src/Units/Tower/TowerLvlOne.h src/Units/Tower/TowerLvlTwo.cpp src/Units/Tower/TowerLvlTwo.h
+ src/Units/Bullet/Bullet.cpp src/Units/Bullet/Bullet.h src/Units/Bullet/BulletLvlOne.cpp src/Units/Bullet/BulletLvlOne.h
+ src/Units/Bullet/BulletLvlTwo.h src/Units/Bullet/BulletLvlTwo.cpp src/Units/Tower/TowerLvlThree.cpp src/Units/Tower/TowerLvlThree.h
+ src/Graphics/TextBox.h src/Graphics/TextBox.cpp src/ConnectGameState.h src/ConnectGameState.cpp
+ src/Units/Bullet/BulletLvlTwo.h src/Units/Bullet/BulletLvlTwo.cpp src/Units/Tower/TowerLvlThree.cpp src/Units/Tower/TowerLvlThree.h src/Castle/Castle.cpp src/Castle/Castle.h src/Castle/Building/Building.cpp src/Castle/Building/Building.h src/Castle/Building/Farm.cpp src/Castle/Building/Farm.h src/Castle/Building/Barracks.cpp src/Castle/Building/Barracks.h src/Castle/Building/Weapons.cpp src/Castle/Building/Weapons.h
+ src/Graphics/GraphicsUnits/GraphicsCastle.cpp src/Graphics/GraphicsUnits/GraphicsCastle.h src/Graphics/GraphicsUnits/GraphicsTower.cpp src/Graphics/GraphicsUnits/GraphicsTower.h src/Graphics/GraphicsUnits/GraphicsWarrior.cpp src/Graphics/GraphicsUnits/GraphicsWarrior.h src/Graphics/GraphicsUnits/GraphicsBullet.cpp src/Graphics/GraphicsUnits/GraphicsBullet.h src/Units/Bullet/BulletLvlThree.cpp src/Units/Bullet/BulletLvlThree.h src/Graphics/GraphicsUnits/GraphicsUnitManager.cpp src/Graphics/GraphicsUnits/GraphicsUnitManager.h src/Units/LogicUnitsManager.cpp src/Units/LogicUnitsManager.h src/GameConstants.cpp src/GameConstants.h
+ src/Multiplayer/MultiplayerFacade/AbstractMultiplayerFacade.cpp src/Multiplayer/MultiplayerFacade/AbstractMultiplayerFacade.h src/Multiplayer/MultiplayerFacade/ClientMultiplayerFacade.cpp src/Multiplayer/MultiplayerFacade/ClientMultiplayerFacade.h src/Multiplayer/MultiplayerFacade/ServerMultiplayerFacade.cpp src/Multiplayer/MultiplayerFacade/ServerMultiplayerFacade.h src/Multiplayer/ConnectionFacade/AbstractConnectionFacade.cpp src/Multiplayer/ConnectionFacade/AbstractConnectionFacade.h src/Multiplayer/ConnectionFacade/ServerConnectionFacade.cpp src/Multiplayer/ConnectionFacade/ServerConnectionFacade.h src/Multiplayer/ConnectionFacade/ClientConnectionFacade.cpp src/Multiplayer/ConnectionFacade/ClientConnectionFacade.h src/Multiplayer/Entities/Event.cpp src/Multiplayer/Entities/Event.h src/Multiplayer/Entities/Entity.cpp src/Multiplayer/Entities/Entity.h src/Multiplayer/Entities/Player.cpp src/Multiplayer/Entities/Player.h src/Multiplayer/Entities/Game.cpp src/Multiplayer/Entities/Game.h src/Multiplayer/Manager/Manager.cpp src/Multiplayer/Manager/Manager.h src/Multiplayer/Manager/PlayerManager.cpp src/Multiplayer/Manager/PlayerManager.h src/Multiplayer/Worker.cpp src/Multiplayer/Worker.h src/Multiplayer/Master.cpp src/Multiplayer/Master.h)
-SET (CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
+SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
FIND_PACKAGE(SFML 2 REQUIRED system window graphics network audio)
#INCLUDE(FindPkgConfig)
#PKG_SEARCH_MODULE(SFML REQUIRED sfml)
INCLUDE_DIRECTORIES(${SFML_INCLUDE_DIR})
-TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${SFML_LIBRARIES})
+TARGET_LINK_LIBRARIES(server ${SFML_LIBRARIES})
+TARGET_LINK_LIBRARIES(TowerDefense ${SFML_LIBRARIES})
file(COPY Resources DESTINATION .)
\ No newline at end of file
diff --git a/README.md b/README.md
index ddd9be7..33039c0 100644
--- a/README.md
+++ b/README.md
@@ -10,15 +10,3 @@
Константин Митраков github.com/ConstaConst
Сергей Ломачев github.com/Silvman
-
-Илья Тюнькин github.com/tyunkinilya
-
-
Напоминание команде:
-
-
Создайте свои ветки!
-
-Если кто-то раньше с этим не сталкивался, то вот неплохая шпаргалка:
-https://git-scm.com/book/ru/v1/Ветвление-в-Git-Основы-ветвления-и-слияния
-Если пользуетесь GitHub Desktop, то там это делается достаточно просто:
-сверху есть кнопочка с разветвлением, нажимаем на неё и называем ветку своей фамилией.
-
diff --git a/Resources/BlueCastle.png b/Resources/BlueCastle.png
new file mode 100644
index 0000000..1d85387
Binary files /dev/null and b/Resources/BlueCastle.png differ
diff --git a/Resources/RedCastle.png b/Resources/RedCastle.png
new file mode 100644
index 0000000..7387361
Binary files /dev/null and b/Resources/RedCastle.png differ
diff --git a/Resources/addBarraks.png b/Resources/addBarraks.png
new file mode 100644
index 0000000..7c65ca8
Binary files /dev/null and b/Resources/addBarraks.png differ
diff --git a/Resources/addFarm.png b/Resources/addFarm.png
new file mode 100644
index 0000000..844a7cf
Binary files /dev/null and b/Resources/addFarm.png differ
diff --git a/Resources/addWarrior.png b/Resources/addWarrior.png
new file mode 100644
index 0000000..e440548
Binary files /dev/null and b/Resources/addWarrior.png differ
diff --git a/Resources/addWarriorOne.png b/Resources/addWarriorOne.png
new file mode 100644
index 0000000..3da0a85
Binary files /dev/null and b/Resources/addWarriorOne.png differ
diff --git a/Resources/addWeapons.png b/Resources/addWeapons.png
new file mode 100644
index 0000000..2ac66f6
Binary files /dev/null and b/Resources/addWeapons.png differ
diff --git a/Resources/audioOff.png b/Resources/audioOff.png
old mode 100755
new mode 100644
diff --git a/Resources/audioOn.png b/Resources/audioOn.png
old mode 100755
new mode 100644
diff --git a/Resources/barraks.png b/Resources/barraks.png
new file mode 100644
index 0000000..9c77879
Binary files /dev/null and b/Resources/barraks.png differ
diff --git a/Resources/blood.png b/Resources/blood.png
new file mode 100644
index 0000000..6620a9f
Binary files /dev/null and b/Resources/blood.png differ
diff --git a/Resources/blueTarget.png b/Resources/blueTarget.png
new file mode 100644
index 0000000..87919b2
Binary files /dev/null and b/Resources/blueTarget.png differ
diff --git a/Resources/bulletThree.png b/Resources/bulletThree.png
new file mode 100644
index 0000000..83ffbae
Binary files /dev/null and b/Resources/bulletThree.png differ
diff --git a/Resources/bulletTwo.png b/Resources/bulletTwo.png
index 83ffbae..510e2b6 100644
Binary files a/Resources/bulletTwo.png and b/Resources/bulletTwo.png differ
diff --git a/Resources/button.png b/Resources/button.png
old mode 100755
new mode 100644
index 4cd391f..bf3c933
Binary files a/Resources/button.png and b/Resources/button.png differ
diff --git a/Resources/click4.wav b/Resources/click4.wav
old mode 100755
new mode 100644
diff --git a/Resources/cursor.png b/Resources/cursor.png
old mode 100755
new mode 100644
diff --git a/Resources/decoration.csv b/Resources/decoration.csv
index 062d578..174948b 100644
--- a/Resources/decoration.csv
+++ b/Resources/decoration.csv
@@ -1,12 +1,12 @@
-3,2,1,3,4,2,0,6,0,0,0,0,0,0,0,
-1,1,4,2,4,2,0,0,0,1,0,4,0,0,0,
-3,2,2,4,1,0,0,2,0,0,0,0,0,0,0,
-3,2,3,1,0,0,0,0,0,0,0,2,0,0,0,
-1,3,4,0,0,0,0,0,0,0,0,0,0,0,0,
-2,1,2,0,0,0,0,0,5,0,4,0,0,0,0,
-4,3,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,
-0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,
-0,0,0,2,2,0,6,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,1,0,7,0,4,0,0,0,0,0,0,4,
\ No newline at end of file
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
\ No newline at end of file
diff --git a/Resources/diamond.png b/Resources/diamond.png
old mode 100755
new mode 100644
diff --git a/Resources/exit.png b/Resources/exit.png
old mode 100755
new mode 100644
diff --git a/Resources/explosionOne.png b/Resources/explosionOne.png
new file mode 100644
index 0000000..c3dce2b
Binary files /dev/null and b/Resources/explosionOne.png differ
diff --git a/Resources/explosion.png b/Resources/explosionThree.png
similarity index 100%
rename from Resources/explosion.png
rename to Resources/explosionThree.png
diff --git a/Resources/explosionTwo.png b/Resources/explosionTwo.png
new file mode 100644
index 0000000..460cb74
Binary files /dev/null and b/Resources/explosionTwo.png differ
diff --git a/Resources/farm.png b/Resources/farm.png
new file mode 100644
index 0000000..67601af
Binary files /dev/null and b/Resources/farm.png differ
diff --git a/Resources/fastForward.mp3 b/Resources/fastForward.mp3
index b9b8422..e69de29 100644
Binary files a/Resources/fastForward.mp3 and b/Resources/fastForward.mp3 differ
diff --git a/Resources/fastForward.wav b/Resources/fastForward.wav
index 9736c97..e69de29 100644
Binary files a/Resources/fastForward.wav and b/Resources/fastForward.wav differ
diff --git a/Resources/fastForwardOff.png b/Resources/fastForwardOff.png
old mode 100755
new mode 100644
diff --git a/Resources/fastForwardOn.png b/Resources/fastForwardOn.png
old mode 100755
new mode 100644
diff --git a/Resources/fight.png b/Resources/fight.png
old mode 100755
new mode 100644
diff --git a/Resources/forwardOff.png b/Resources/forwardOff.png
old mode 100755
new mode 100644
diff --git a/Resources/forwardOn.png b/Resources/forwardOn.png
old mode 100755
new mode 100644
diff --git a/Resources/grey_panel.png b/Resources/grey_panel.png
old mode 100755
new mode 100644
diff --git a/Resources/heart.png b/Resources/heart.png
old mode 100755
new mode 100644
diff --git a/Resources/hexagonVector_objects.svg b/Resources/hexagonVector_objects.svg
new file mode 100755
index 0000000..4681873
--- /dev/null
+++ b/Resources/hexagonVector_objects.svg
@@ -0,0 +1,1149 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Resources/hexagonVector_objects.swf b/Resources/hexagonVector_objects.swf
new file mode 100755
index 0000000..8453505
Binary files /dev/null and b/Resources/hexagonVector_objects.swf differ
diff --git a/Resources/iconSheet.png b/Resources/iconSheet.png
old mode 100755
new mode 100644
diff --git a/Resources/logo.png b/Resources/logo.png
new file mode 100644
index 0000000..9d52bcf
Binary files /dev/null and b/Resources/logo.png differ
diff --git a/Resources/map.csv b/Resources/map.csv
old mode 100755
new mode 100644
index 547b624..c918b9e
--- a/Resources/map.csv
+++ b/Resources/map.csv
@@ -1,12 +1,20 @@
-16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
-16,16,16,16,16,16,16,16,16,16,16,16,3 ,31,31,
-16,16,16,16,16,16,16,16,16,16,16,16,17, 0 ,1 ,
-16,16,16,16,16,16,16,16,16,16,16,16,17,15,16,
-16,16,16,16,3 ,31,31,31,4 ,16,16,16,17,15,16,
-16,16,16,16,17,0 ,1 ,2 ,15,16,16,16,17,15,16,
-16,16,16,16,17,15,16,17,15,16,16,16,17,15,16,
-16,3 ,31,31,32,15,16,17,15,16,16,16,17,15,16,
-16,17,0 ,1 ,1 ,19,16,17,15,16,16,16,17,15,16,
-16,17,15,16,16,16,16,17,30,31,31,31,32,15,16,
-16,17,15,16,16,16,16,18,1 ,1 ,1 ,1 ,1 ,19 ,16,
-16,17,15,16,16,16,16,16,16,16,16,16,16,16,16
+2
+12 19
+
+16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16
+3 31 31 31 4 16 3 31 31 31 31 4 16 16 3 31 31 31 4
+17 0 1 2 15 14 17 0 1 1 2 15 16 16 17 0 1 2 15
+17 15 16 17 30 31 32 15 14 14 17 15 14 14 17 15 16 17 15
+16 16 16 18 1 1 1 19 16 16 17 30 31 31 32 15 16 16 16
+16 16 16 16 14 13 14 16 16 16 18 1 1 1 1 19 16 16 16
+
+16 16 16 3 31 31 31 31 4 16 16 16 13 14 13 16 16 16 16
+16 16 16 17 0 1 1 2 15 16 16 3 31 31 31 4 16 16 16
+17 15 16 17 15 13 13 17 15 13 13 17 0 1 2 15 16 17 15
+17 30 31 32 15 16 16 17 30 31 31 32 15 13 17 30 31 32 15
+18 1 1 1 19 16 16 18 1 1 1 1 19 16 18 1 1 1 19
+16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16
+
+3 0
+
+8 17
diff --git a/Resources/map.png b/Resources/map.png
old mode 100755
new mode 100644
diff --git a/Resources/map1.png b/Resources/map1.png
old mode 100755
new mode 100644
diff --git a/Resources/musicOff.png b/Resources/musicOff.png
old mode 100755
new mode 100644
diff --git a/Resources/musicOn.png b/Resources/musicOn.png
old mode 100755
new mode 100644
diff --git a/Resources/panel.png b/Resources/panel.png
old mode 100755
new mode 100644
diff --git a/Resources/pauseOff.png b/Resources/pauseOff.png
old mode 100755
new mode 100644
diff --git a/Resources/pauseOn.png b/Resources/pauseOn.png
old mode 100755
new mode 100644
diff --git a/Resources/redTarget.png b/Resources/redTarget.png
new file mode 100644
index 0000000..e657c8d
Binary files /dev/null and b/Resources/redTarget.png differ
diff --git a/Resources/star.png b/Resources/star.png
old mode 100755
new mode 100644
diff --git a/Resources/tank_explosion3.png b/Resources/tank_explosion3.png
deleted file mode 100644
index 71ce43b..0000000
Binary files a/Resources/tank_explosion3.png and /dev/null differ
diff --git a/Resources/target.png b/Resources/target.png
old mode 100755
new mode 100644
index a33c2ee..46bb1b3
Binary files a/Resources/target.png and b/Resources/target.png differ
diff --git a/Resources/towerOneBase.png b/Resources/towerOneBase.png
old mode 100755
new mode 100644
diff --git a/Resources/towerOneTop.png b/Resources/towerOneTop.png
old mode 100755
new mode 100644
diff --git a/Resources/towerThreeBase.png b/Resources/towerThreeBase.png
new file mode 100644
index 0000000..c60b8f5
Binary files /dev/null and b/Resources/towerThreeBase.png differ
diff --git a/Resources/towerTopTwo.png b/Resources/towerThreeTop.png
similarity index 100%
rename from Resources/towerTopTwo.png
rename to Resources/towerThreeTop.png
diff --git a/Resources/towerBaseTwo.png b/Resources/towerTwoBase.png
similarity index 100%
rename from Resources/towerBaseTwo.png
rename to Resources/towerTwoBase.png
diff --git a/Resources/towerTwoTop.png b/Resources/towerTwoTop.png
new file mode 100644
index 0000000..eca7a82
Binary files /dev/null and b/Resources/towerTwoTop.png differ
diff --git a/Resources/warriorExplosion.png b/Resources/warriorExplosion.png
new file mode 100644
index 0000000..945b4cf
Binary files /dev/null and b/Resources/warriorExplosion.png differ
diff --git a/Resources/warriorOne.png b/Resources/warriorOne.png
new file mode 100644
index 0000000..5806990
Binary files /dev/null and b/Resources/warriorOne.png differ
diff --git a/Resources/warriorTwo.png b/Resources/warriorTwo.png
new file mode 100644
index 0000000..a7ddf6c
Binary files /dev/null and b/Resources/warriorTwo.png differ
diff --git a/Resources/weapons.png b/Resources/weapons.png
new file mode 100644
index 0000000..a000596
Binary files /dev/null and b/Resources/weapons.png differ
diff --git a/cmake/Modules/FindSFML.cmake b/cmake/Modules/FindSFML.cmake
old mode 100755
new mode 100644
diff --git a/src/Castle/Building/Barracks.cpp b/src/Castle/Building/Barracks.cpp
new file mode 100644
index 0000000..1dd37f5
--- /dev/null
+++ b/src/Castle/Building/Barracks.cpp
@@ -0,0 +1,18 @@
+#include "Barracks.h"
+
+Barracks::Barracks()
+ : Building(GameConstants::instance().cBARRACKS_1_COST()) {
+}
+
+int Barracks::upgrade() {
+ if (lvl_ >= 2) {
+ return 0;
+ }
+ int minusGold = upgradeCost_;
+ ++lvl_;
+ if (lvl_ == 1) {
+ upgradeCost_ = GameConstants::instance().cBARRACKS_2_COST();
+ }
+
+ return minusGold;
+}
diff --git a/src/Castle/Building/Barracks.h b/src/Castle/Building/Barracks.h
new file mode 100644
index 0000000..e28da4b
--- /dev/null
+++ b/src/Castle/Building/Barracks.h
@@ -0,0 +1,15 @@
+#ifndef TOWERDEFENSE_BARRACKS_H
+#define TOWERDEFENSE_BARRACKS_H
+
+
+#include "Building.h"
+
+class Barracks: public Building {
+public:
+ Barracks();
+
+ int upgrade() override;
+};
+
+
+#endif //TOWERDEFENSE_BARRACKS_H
diff --git a/src/Castle/Building/Building.cpp b/src/Castle/Building/Building.cpp
new file mode 100644
index 0000000..96db708
--- /dev/null
+++ b/src/Castle/Building/Building.cpp
@@ -0,0 +1,14 @@
+#include "Building.h"
+
+Building::Building(int upgradeCost)
+ : upgradeCost_(upgradeCost),
+ lvl_(0) {
+}
+
+unsigned char Building::getLvl() const {
+ return lvl_;
+}
+
+int Building::getUpgradeCost() const {
+ return upgradeCost_;
+}
diff --git a/src/Castle/Building/Building.h b/src/Castle/Building/Building.h
new file mode 100644
index 0000000..9ee2ce0
--- /dev/null
+++ b/src/Castle/Building/Building.h
@@ -0,0 +1,24 @@
+#ifndef TOWERDEFENSE_BUILDING_H
+#define TOWERDEFENSE_BUILDING_H
+
+
+#include "../../GameContext.h"
+#include "../../GameConstants.h"
+
+class Building {
+public:
+ virtual ~Building() = default;
+
+ virtual int upgrade() = 0;
+ unsigned char getLvl() const;
+ int getUpgradeCost() const;
+
+protected:
+ explicit Building(int upgradeCost);
+
+ int upgradeCost_;
+ unsigned char lvl_;
+};
+
+
+#endif //TOWERDEFENSE_BUILDING_H
diff --git a/src/Castle/Building/Farm.cpp b/src/Castle/Building/Farm.cpp
new file mode 100644
index 0000000..d5633ca
--- /dev/null
+++ b/src/Castle/Building/Farm.cpp
@@ -0,0 +1,26 @@
+#include
+#include "Farm.h"
+#include "../../GameConstants.h"
+
+Farm::Farm()
+ : Building(GameConstants::instance().cFARM_COST()),
+ working(GameConstants::instance().cFARM_TIME_CYCLE()) {
+ lvl_ = 1;
+}
+
+int Farm::getBenefits(const sf::Time& dt) {
+ working -= dt.asMilliseconds();
+ if (working <= 0) {
+ working = GameConstants::instance().cFARM_TIME_CYCLE();
+ return lvl_ * GameConstants::instance().cFARM_LVL_BENEFITS();
+ }
+ return 0;
+}
+
+int Farm::upgrade() {
+ int minusGold = upgradeCost_;
+ ++lvl_;
+ upgradeCost_ = static_cast(log2(GameConstants::instance().cFARM_INC_COST_BASE() + lvl_) *
+ GameConstants::instance().cFARM_COST());
+ return minusGold;
+}
diff --git a/src/Castle/Building/Farm.h b/src/Castle/Building/Farm.h
new file mode 100644
index 0000000..c550ed5
--- /dev/null
+++ b/src/Castle/Building/Farm.h
@@ -0,0 +1,19 @@
+#ifndef TOWERDEFENSE_FARM_H
+#define TOWERDEFENSE_FARM_H
+
+
+#include
+#include "Building.h"
+
+class Farm: public Building {
+public:
+ Farm();
+ int getBenefits(const sf::Time& dt);
+ int upgrade() override;
+
+private:
+ sf::Int32 working;
+};
+
+
+#endif //TOWERDEFENSE_FARM_H
diff --git a/src/Castle/Building/Weapons.cpp b/src/Castle/Building/Weapons.cpp
new file mode 100644
index 0000000..0776bf5
--- /dev/null
+++ b/src/Castle/Building/Weapons.cpp
@@ -0,0 +1,19 @@
+#include "Weapons.h"
+
+Weapons::Weapons()
+ : Building(GameConstants::instance().cWEAPONS_1_COST()) {
+}
+
+int Weapons::upgrade() {
+ if (lvl_ >= 3) {
+ return 0;
+ }
+ int minusGold = upgradeCost_;
+ ++lvl_;
+ if (lvl_ == 1) {
+ upgradeCost_ = GameConstants::instance().cWEAPONS_2_COST();
+ } else if (lvl_ == 2) {
+ upgradeCost_ = GameConstants::instance().cWEAPONS_3_COST();
+ }
+ return minusGold;
+}
diff --git a/src/Castle/Building/Weapons.h b/src/Castle/Building/Weapons.h
new file mode 100644
index 0000000..dcff3b6
--- /dev/null
+++ b/src/Castle/Building/Weapons.h
@@ -0,0 +1,15 @@
+#ifndef TOWERDEFENSE_WEAPONS_H
+#define TOWERDEFENSE_WEAPONS_H
+
+
+#include "Building.h"
+
+class Weapons: public Building {
+public:
+ Weapons();
+
+ int upgrade() override;
+};
+
+
+#endif //TOWERDEFENSE_WEAPONS_H
diff --git a/src/Castle/Castle.cpp b/src/Castle/Castle.cpp
new file mode 100644
index 0000000..744cb58
--- /dev/null
+++ b/src/Castle/Castle.cpp
@@ -0,0 +1,183 @@
+#include "Castle.h"
+#include "../Units/Warrior/WarriorLvlOne.h"
+#include "../Units/Warrior/WarriorLvlTwo.h"
+#include "../Units/Tower/TowerLvlZero.h"
+
+Castle::Castle()
+ : enemy_(nullptr),
+ gold_(GameConstants::instance().cCASTLE_INIT_GOLD()),
+ health_(GameConstants::instance().cCASTLE_HP()),
+ towers_(),
+ warriors_(),
+ numWarriorsToWave_(0),
+ numWarriorsInBuffer_(0),
+ forDurationState_(0),
+ warriorsBuffer_(),
+ farm_(),
+ barracks_(),
+ weapons_(),
+ makingWave_(false),
+ waveDuration_(0) {}
+
+int Castle::getGold() const {
+ return gold_;
+}
+
+int Castle::getHealth() const {
+ return health_;
+}
+
+const std::vector>& Castle::getTowers() const {
+ return towers_;
+}
+
+std::list>& Castle::getWarriors() {
+ return warriors_;
+}
+
+const std::list>& Castle::getWarriorsBuffer() const {
+ return warriorsBuffer_;
+}
+
+void Castle::upgradeTower(int index) {
+ gold_ -= Tower::upgrade(towers_[index]);
+}
+
+void Castle::upgradeBuilding(char type) {
+ switch (type) {
+ case 'f':
+ gold_ -= farm_.upgrade();
+ break;
+ case 'b':
+ gold_ -= barracks_.upgrade();
+ break;
+ case 'w':
+ gold_ -= weapons_.upgrade();
+ break;
+ }
+}
+
+void Castle::addWarrior(Type type, const Map::LogicMap& logicMap) {
+ if (numWarriorsInBuffer_ >= GameConstants::instance().cWARRIORS_BUFFER_SIZE()) {
+ return;
+ }
+ switch (type) {
+ case Type::lvlOne:
+ warriorsBuffer_.push_back(std::make_shared(logicMap.start, logicMap));
+ break;
+ case Type::lvlTwo:
+ warriorsBuffer_.push_back(std::make_shared(logicMap.start, logicMap));
+ break;
+ }
+ gold_ -= warriorsBuffer_.back()->getCost();
+ ++numWarriorsInBuffer_;
+}
+
+void Castle::updateCastle(const sf::Time& dTime) {
+ gold_ += farm_.getBenefits(dTime);
+
+ for (auto warrior = warriors_.begin(); warrior != warriors_.end();) {
+ (*warrior)->update(dTime);
+ if (!(*warrior)->isAlive() || (*warrior)->isFinished()) {
+ if ((*warrior)->isFinished()) {
+ enemy_->takeDamage((*warrior)->getHp());
+ }
+ warrior = warriors_.erase(warrior);
+ }
+ else {
+ ++warrior;
+ }
+ }
+
+ for (const auto& tower : towers_) {
+ tower->update(dTime);
+ }
+ if (makingWave_) {
+ makeWave(dTime);
+ }
+}
+
+void Castle::takeDamage(int damage) {
+ health_ -= damage;
+}
+
+void Castle::setEnemy(const std::shared_ptr& castle) {
+ enemy_ = castle;
+}
+
+void Castle::addTower(const sf::Vector2f& position, std::list>& warriors, std::vector>& bullets) {
+ towers_.push_back(std::make_shared(position, warriors, bullets));
+}
+
+void Castle::makeWave(const sf::Time& dTime) {
+ waveDuration_ -= dTime.asMilliseconds();
+ if (waveDuration_ <= 0) {
+ waveDuration_ = GameConstants::instance().cCASTLE_WAVE_DURATION();
+ if (numWarriorsToWave_ > 0) {
+ --numWarriorsToWave_;
+ warriors_.push_back(warriorsBuffer_.front());
+ warriorsBuffer_.pop_front();
+ } else {
+ makingWave_ = false;
+ }
+ }
+}
+
+void Castle::letsMakingWave() {
+ numWarriorsToWave_ += forDurationState_;
+ forDurationState_ = 0;
+ makingWave_ = true;
+}
+
+void Castle::dropBuffer() {
+ forDurationState_ += numWarriorsInBuffer_;
+ numWarriorsInBuffer_ = 0;
+}
+
+std::string Castle::generateWaveString(const Castle& player) {
+ std::string value;
+
+ auto buffIterator = player.warriorsBuffer_.begin();
+ for (size_t i = 0; i < player.numWarriorsToWave_; i++) {
+ buffIterator++;
+ }
+
+ for (;buffIterator != player.warriorsBuffer_.end(); buffIterator++) {
+ if ((*buffIterator) != nullptr) {
+ switch ((*buffIterator)->getType()) {
+ case Type::lvlOne:
+ value.push_back('1');
+ break;
+ case Type::lvlTwo:
+ value.push_back('2');
+ break;
+ }
+ }
+ }
+
+ return value;
+}
+
+size_t Castle::getWarriorsInBuffer() const {
+ return numWarriorsInBuffer_;
+}
+
+bool Castle::checkValidUpgradeTower(const Type& towerLvl, unsigned char weaponsLvl) {
+ return ((weaponsLvl == 3) || (towerLvl == Type::lvlZero && weaponsLvl >= 1) ||
+ (towerLvl == Type::lvlOne && weaponsLvl >= 2));
+}
+
+const Farm& Castle::getFarm() const {
+ return farm_;
+}
+
+const Barracks& Castle::getBarracks() const {
+ return barracks_;
+}
+const Weapons& Castle::getWeapons() const {
+ return weapons_;
+}
+
+size_t Castle::getWarriorsToWave() const {
+ return numWarriorsToWave_;
+}
diff --git a/src/Castle/Castle.h b/src/Castle/Castle.h
new file mode 100644
index 0000000..bf0d0d4
--- /dev/null
+++ b/src/Castle/Castle.h
@@ -0,0 +1,65 @@
+#ifndef TOWERDEFENSE_CASTLE_H
+#define TOWERDEFENSE_CASTLE_H
+
+#include
+#include
+#include "../Units/Tower/Tower.h"
+#include "../Units/Warrior/Warrior.h"
+#include "Building/Farm.h"
+#include "Building/Barracks.h"
+#include "Building/Weapons.h"
+#include "../GameConstants.h"
+
+
+class Castle {
+public:
+ Castle();
+
+ void updateCastle(const sf::Time& dTime);
+ void upgradeTower(int index);
+ void upgradeBuilding(char type);
+ void addWarrior(Type type, const Map::LogicMap& logicMap);
+ void addTower(const sf::Vector2f& position, std::list>& warriors, std::vector>& bullets);
+ void takeDamage(int damage);
+ void setEnemy(const std::shared_ptr& castle);
+ void letsMakingWave();
+ void dropBuffer();
+ void makeWave(const sf::Time& dTime);
+
+ static std::string generateWaveString(const Castle& player);
+ static bool checkValidUpgradeTower(const Type& towerLvl, unsigned char weaponsLvl);
+
+ int getGold() const;
+ int getHealth() const;
+ const std::vector>& getTowers() const;
+ std::list>& getWarriors();
+ const std::list>& getWarriorsBuffer() const;
+ size_t getWarriorsInBuffer() const;
+ size_t getWarriorsToWave() const;
+ const Farm& getFarm() const;
+ const Barracks& getBarracks() const;
+ const Weapons& getWeapons() const;
+
+private:
+ int gold_;
+ int health_;
+ std::shared_ptr enemy_;
+ std::vector> towers_;
+ std::list> warriors_;
+ size_t numWarriorsInBuffer_;
+ size_t numWarriorsToWave_;
+ size_t forDurationState_;
+ std::list> warriorsBuffer_;
+
+ Farm farm_;
+ Barracks barracks_;
+ Weapons weapons_;
+
+ bool makingWave_;
+ sf::Int32 waveDuration_;
+
+
+};
+
+
+#endif //TOWERDEFENSE_CASTLE_H
diff --git a/src/ConnectGameState.cpp b/src/ConnectGameState.cpp
new file mode 100644
index 0000000..97942e8
--- /dev/null
+++ b/src/ConnectGameState.cpp
@@ -0,0 +1,90 @@
+#include "ConnectGameState.h"
+#include "Graphics/Button.h"
+#include "Graphics/TextBox.h"
+#include "Graphics/Label.h"
+#include "Game.h"
+#include "Constants.h"
+
+ConnectGameState::ConnectGameState(StateManager &stack, States::Context context) : State(stack, context) {
+ mapSprite.setTileNumber(16);
+ texture.loadFromFile("Resources/map1.png");
+ texture.setSmooth(true);
+ sf::IntRect rect{ TILE_SIZE * (16 % 15), TILE_SIZE * (16 / 15), TILE_SIZE, TILE_SIZE };
+ mapSprite.setTexture(texture, rect);
+
+ context.multiplayer->connect();
+
+ if (!context.multiplayer->isConnected()) {
+ std::cout << "[warning] no server connection" << std::endl;
+ }
+
+ auto textbox_new = std::make_shared(getContext().fontHolder->get(Fonts::font1));
+ auto textbox_join = std::make_shared(getContext().fontHolder->get(Fonts::font1));
+
+ textNew.setFont(context.fontHolder->get(Fonts::font1));
+ textJoin.setFont(context.fontHolder->get(Fonts::font1));
+ textNew.setString("New game:");
+ textJoin.setString("Joind game:");
+ textNew.setPosition(350, 150);
+ textJoin.setPosition(350, 250);
+
+ container.addWidget(textbox_new);
+ container.addWidget(textbox_join);
+
+ textbox_new->setDimensons(350, 200, 500, 50);
+ textbox_new->setInd(0);
+ textbox_new->setString("Game name");
+ textbox_join->setDimensons(350, 300, 500, 50);
+ textbox_join->setInd(0);
+ textbox_join->setString("Game id");
+
+ textbox_new->setCallback([this, textbox_new](int ind) {
+ getContext().multiplayer->outcoming.emplace_back(0, 'n', textbox_new->getString(), sf::microseconds(0));
+ });
+
+ textbox_join->setCallback([this, textbox_join](int ind) {
+ getContext().multiplayer->outcoming.emplace_back(0, 'j', textbox_join->getString(), sf::microseconds(0));
+ });
+}
+
+bool ConnectGameState::handleEvent(const sf::Event &event) {
+ container.handleWidgetsEvent(event);
+ return false;
+}
+
+bool ConnectGameState::update(sf::Time dt) {
+ container.updateWidgets(dt);
+ for (auto &&event: getContext().multiplayer->incoming) {
+ switch (event.type) {
+ case 'n': {
+ std::cout << "[success] game id " << event.value << std::endl;
+ gameID = event.value;
+ break;
+ }
+
+ case 'j': {
+ *getContext().p_id = atoi(event.value.c_str());
+ std::cout << "[success] in game. your id " << *getContext().p_id << std::endl;
+ popState();
+ pushState(States::ID::Game);
+ break;
+ }
+
+ default:
+ break;
+ }
+ }
+
+}
+
+void ConnectGameState::draw() {
+ getContext().window->clear(sf::Color(0, 165, 80, 0));
+ for (int i = 0; i < 20; i++)
+ for (int j = 0; j < 20; j++)
+ {
+ mapSprite.setPosition(static_cast(j * TILE_SIZE), static_cast(i * TILE_SIZE));
+ getContext().window->draw(mapSprite);
+ }
+
+ getContext().window->draw(container);
+}
\ No newline at end of file
diff --git a/src/ConnectGameState.h b/src/ConnectGameState.h
new file mode 100644
index 0000000..a950a21
--- /dev/null
+++ b/src/ConnectGameState.h
@@ -0,0 +1,29 @@
+#ifndef TOWERDEFENSE_CONNECTGAMESTATE_H
+#define TOWERDEFENSE_CONNECTGAMESTATE_H
+
+#include "Graphics/Gui.h"
+#include "State.h"
+#include "Tile.h"
+
+class ConnectGameState: public State {
+public:
+ explicit ConnectGameState(StateManager& stack, States::Context context);
+
+ bool handleEvent(const sf::Event& event) override ;
+ bool update(sf::Time dt) override;
+ void draw() override;
+
+ void initButtons();
+
+private:
+ sf::Texture texture;
+ Tile mapSprite;
+
+ std::string gameID;
+ gui::Gui container;
+ sf::Text textNew;
+ sf::Text textJoin;
+};
+
+
+#endif //TOWERDEFENSE_CONNECTGAMESTATE_H
\ No newline at end of file
diff --git a/src/Constants.h b/src/Constants.h
new file mode 100644
index 0000000..674db96
--- /dev/null
+++ b/src/Constants.h
@@ -0,0 +1,10 @@
+//
+// Created by Falcon on 20.04.2018.
+//
+
+#ifndef TOWERDEFENSE_CONSTANTS_H
+#define TOWERDEFENSE_CONSTANTS_H
+
+#define TILE_SIZE 64
+
+#endif //TOWERDEFENSE_CONSTANTS_H
diff --git a/src/Game.cpp b/src/Game.cpp
index ce4827d..bdee769 100644
--- a/src/Game.cpp
+++ b/src/Game.cpp
@@ -2,24 +2,68 @@
#include "MenuState.h"
#include "PauseState.h"
#include "GameState.h"
+#include "ConnectGameState.h"
+#include "Multiplayer/MultiplayerFacade/ClientMultiplayerFacade.h"
+#include "Multiplayer/MultiplayerFacade/ServerMultiplayerFacade.h"
+#include "GameOverState.h"
+#include "WinState.h"
+#include
-Game::Game() : window({1000, 1000}, "Tower Defense", sf::Style::Titlebar |
- sf::Style::Default, sf::ContextSettings{0, 0, 8, 1, 1, 0, false}),
- context(window, font, textureHolder, fontHolder, cursor),
+Game::Game() : window({1216, 768}, "Tower Defense", sf::Style::Titlebar |
+ sf::Style::Default, sf::ContextSettings{0, 0, 8, 1, 1, 0}),
+ context(window, font, textureHolder, fontHolder, cursor, new mp::ClientMultiplayerFacade),
stateManager(context) {
+ std::cout << "start game constructor" << std::endl;
loadAllResources();
+ std::cout << "load resources" << std::endl;
registerStates();
- stateManager.pushState(States::ID::Game);
+ std::cout << "register state" << std::endl;
+ stateManager.pushState(States::ID::Menu);
+ std::cout << "start game" << std::endl;
+
+// window.setVerticalSyncEnabled(true);
+}
+
+
+Game::Game(mp::player &first, mp::player &second)
+ : context(window, font, textureHolder, fontHolder, cursor, new mp::ServerMultiplayerFacade(first, second)),
+ stateManager(context)
+{
+ registerStates();
+ stateManager.pushState(States::ID::Game); // TODO MultiplayerGame
}
void Game::run() {
- const sf::Time frameTime = sf::seconds(1.f / 30.f);
+ const sf::Time frameTime = sf::seconds(1.f / 60.f);
sf::Clock clock;
- sf::Time passedTIme = sf::Time::Zero;
+ sf::Time passedTime = sf::Time::Zero;
+ auto mp = context.multiplayer;
while (window.isOpen()) {
- input();
- update(frameTime);
+ sf::Time elapsedTime = clock.restart();
+ passedTime += elapsedTime ;
+ while (passedTime > frameTime) {
+ passedTime -= frameTime;
+ input();
+ update(frameTime);
+
+ mp->incoming.clear();
+ if (mp->isConnected()) {
+ try {
+ mp->sendEvents();
+ mp->askEvents();
+ for (auto &&item : mp->incoming) {
+ if (item.type == 's' && item.value == "stop")
+ window.close();
+ }
+ } catch (const std::exception &e) {
+ std::cout << e.what() << std::endl;
+ }
+ } else {
+ mp->outcoming.clear();
+ }
+ }
+
draw();
}
}
@@ -35,7 +79,54 @@ void Game::input() {
}
void Game::loadAllResources() {
- fontHolder.load(Fonts::font1, "../Resources/sansation.ttf");
+ fontHolder.load(Fonts::font1, "Resources/sansation.ttf");
+
+ textureHolder.load(Textures::cursor, "Resources/cursor.png");
+ textureHolder.load(Textures::panel, "Resources/panel.png");
+ textureHolder.load(Textures::button, "Resources/button.png");
+ textureHolder.load(Textures::map, "Resources/map1.png");
+ textureHolder.load(Textures::target, "Resources/target.png");
+ textureHolder.load(Textures::gold, "Resources/diamond.png");
+ textureHolder.load(Textures::star, "Resources/star.png");
+ textureHolder.load(Textures::exit, "Resources/exit.png");
+ textureHolder.load(Textures::lives, "Resources/heart.png");
+ textureHolder.load(Textures::pauseOn, "Resources/pauseOn.png");
+ textureHolder.load(Textures::pauseOff, "Resources/pauseOff.png");
+ textureHolder.load(Textures::audioOff, "Resources/audioOff.png");
+ textureHolder.load(Textures::audioOn, "Resources/audioOn.png");
+ textureHolder.load(Textures::musicOff, "Resources/musicOff.png");
+ textureHolder.load(Textures::musicOn, "Resources/musicOn.png");
+ textureHolder.load(Textures::warriorOne, "Resources/enemyOne.png");
+ textureHolder.load(Textures::warriorTwo, "Resources/enemy.png");
+ textureHolder.load(Textures::blood, "Resources/blood.png");
+ textureHolder.load(Textures::warriorExplosion, "Resources/warriorExplosion.png");
+ textureHolder.load(Textures::towerZeroRed, "Resources/redTarget.png");
+ textureHolder.load(Textures::towerZeroBlue, "Resources/blueTarget.png");
+ textureHolder.load(Textures::castle1, "Resources/RedCastle.png");
+ textureHolder.load(Textures::castle2, "Resources/BlueCastle.png");
+ textureHolder.load(Textures::towerOneTop, "Resources/towerOneTop.png");
+ textureHolder.load(Textures::towerOneBase, "Resources/towerOneBase.png");
+ textureHolder.load(Textures::towerTwoTop, "Resources/towerTwoTop.png");
+ textureHolder.load(Textures::towerTwoBase, "Resources/towerTwoBase.png");
+ textureHolder.load(Textures::towerThreeTop, "Resources/towerThreeTop.png");
+ textureHolder.load(Textures::towerThreeBase, "Resources/towerThreeBase.png");
+ textureHolder.load(Textures::bulletOne, "Resources/bulletOne.png");
+ textureHolder.load(Textures::bulletTwo, "Resources/bulletTwo.png");
+ textureHolder.load(Textures::bulletThree, "Resources/bulletThree.png");
+ textureHolder.load(Textures::explosionOne, "Resources/explosionOne.png");
+ textureHolder.load(Textures::explosionTwo, "Resources/explosionTwo.png");
+ textureHolder.load(Textures::explosionThree, "Resources/explosionThree.png");
+ textureHolder.load(Textures::warriorIconOne, "Resources/warriorOne.png");
+ textureHolder.load(Textures::warriorIconTwo, "Resources/warriorTwo.png");
+ textureHolder.load(Textures::addWarriorOne, "Resources/addWarriorOne.png");
+ textureHolder.load(Textures::addWarriorTwo, "Resources/addWarrior.png");
+ textureHolder.load(Textures::addBarraks, "Resources/addBarraks.png");
+ textureHolder.load(Textures::addFarm, "Resources/addFarm.png");
+ textureHolder.load(Textures::addWeapons, "Resources/addWeapons.png");
+ textureHolder.load(Textures::farm, "Resources/farm.png");
+ textureHolder.load(Textures::weapons, "Resources/weapons.png");
+ textureHolder.load(Textures::barraks, "Resources/barraks.png");
+ textureHolder.load(Textures::logo, "Resources/logo.png");
}
@@ -45,10 +136,60 @@ void Game::update(sf::Time frameTime) {
void Game::draw() {
window.clear(sf::Color(210, 210, 210));
+// std::thread t1(&StateManager::draw, stateManager);
+// t1.join();
stateManager.draw();
window.display();
}
void Game::registerStates() {
+ stateManager.registerState(States::ID::Menu);
+ stateManager.registerState(States::ID::ConnectGame);
stateManager.registerState(States::ID::Game);
-}
\ No newline at end of file
+ stateManager.registerState(States::ID::GameOverState);
+ stateManager.registerState(States::ID::WinState);
+}
+
+void Game::server_run(bool use_validation) {
+ const sf::Time frameTime = sf::seconds(1.f / 60.f);
+ sf::Clock clock;
+ sf::Time passedTime = sf::Time::Zero;
+
+ std::cout << "start multi game" << std::endl;
+
+ auto& mp = context.multiplayer;
+ while (true) {
+ if (!mp->isConnected()) {
+ mp->outcoming.emplace_back(0, 's', "stop", sf::microseconds(0));
+ mp->sendEvents();
+
+ break;
+ }
+
+ if (use_validation) {
+ sf::Time elapsedTime = clock.restart();
+ passedTime += elapsedTime ;
+ while (passedTime > frameTime) {
+ passedTime -= frameTime;
+ update(frameTime);
+
+ try {
+ mp->incoming.clear();
+ mp->sendEvents();
+ mp->askEvents();
+ } catch (const std::exception &e) {
+ std::cout << e.what() << std::endl;
+ }
+ }
+ } else {
+ try {
+ mp->incoming.clear();
+ mp->askEvents();
+ mp->outcoming = mp->incoming;
+ mp->sendEvents();
+ } catch (const std::exception &e) {
+ std::cout << e.what() << std::endl;
+ }
+ }
+ }
+}
diff --git a/src/Game.h b/src/Game.h
index ac59af5..b32f393 100644
--- a/src/Game.h
+++ b/src/Game.h
@@ -8,13 +8,18 @@
#include "GameContext.h"
#include "ResourceManager/ResourcesHolder.h"
#include "ResourceManager/ResourcesIdentifier.h"
+#include "Multiplayer/Entities/Player.h"
+//std::vector& incoming_events;
+//std::vector& outcoming_events;
class Game {
public:
Game();
+ Game(mp::player &first, mp::player &second);
void run();
+ void server_run(bool use_validation);
private:
void input();
@@ -26,7 +31,6 @@ class Game {
TextureHolder textureHolder;
FontHolder fontHolder;
- int color;
sf::Font font;
sf::Sprite cursor;
sf::RenderWindow window;
diff --git a/src/GameConstants.cpp b/src/GameConstants.cpp
new file mode 100644
index 0000000..6a939ba
--- /dev/null
+++ b/src/GameConstants.cpp
@@ -0,0 +1,276 @@
+#include
+#include
+#include "GameConstants.h"
+
+bool GameConstants::initialized_ = false;
+
+GameConstants &GameConstants::instance() {
+
+ static GameConstants gameConstants;
+ if (initialized_) {
+ return gameConstants;
+ }
+ initialized_ = true;
+
+ std::ifstream fin("../src/game_config.cfg");
+ if (!fin.is_open()) {
+ throw std::runtime_error(std::string("Config file doesn't open."));
+ }
+
+ std::string name;
+ while (fin >> name) {
+ if (name == "BARRACKS_1_COST") {
+ fin >> gameConstants.BARRACKS_1_COST;
+ } else if (name == "BARRACKS_2_COST") {
+ fin >> gameConstants.BARRACKS_2_COST;
+ } else if (name == "BARRACKS_3_COST") {
+ fin >> gameConstants.BARRACKS_3_COST;
+ } else if (name == "FARM_COST") {
+ fin >> gameConstants.FARM_COST;
+ } else if (name == "FARM_INC_COST_BASE") {
+ fin >> gameConstants.FARM_INC_COST_BASE;
+ } else if (name == "FARM_LVL_BENEFITS") {
+ fin >> gameConstants.FARM_LVL_BENEFITS;
+ } else if (name == "FARM_TIME_CYCLE") {
+ fin >> gameConstants.FARM_TIME_CYCLE;
+ } else if (name == "WEAPONS_1_COST") {
+ fin >> gameConstants.WEAPONS_1_COST;
+ } else if (name == "WEAPONS_2_COST") {
+ fin >> gameConstants.WEAPONS_2_COST;
+ } else if (name == "WEAPONS_3_COST") {
+ fin >> gameConstants.WEAPONS_3_COST;
+ } else if (name == "CASTLE_HP") {
+ fin >> gameConstants.CASTLE_HP;
+ } else if (name == "CASTLE_INIT_GOLD") {
+ fin >> gameConstants.CASTLE_INIT_GOLD;
+ } else if (name == "CASTLE_WAVE_DURATION") {
+ fin >> gameConstants.CASTLE_WAVE_DURATION;
+ } else if (name == "WARRIORS_BUFFER_SIZE") {/*____________________________________*/
+ fin >> gameConstants.WARRIORS_BUFFER_SIZE;
+ } else if (name == "BULLET_1_DAMAGE") {
+ fin >> gameConstants.BULLET_1_DAMAGE;
+ } else if (name == "BULLET_1_VELOCITY") {
+ fin >> gameConstants.BULLET_1_VELOCITY;
+ } else if (name == "BULLET_2_DAMAGE") {
+ fin >> gameConstants.BULLET_2_DAMAGE;
+ } else if (name == "BULLET_2_VELOCITY") {
+ fin >> gameConstants.BULLET_2_VELOCITY;
+ } else if (name == "BULLET_3_DAMAGE") {
+ fin >> gameConstants.BULLET_3_DAMAGE;
+ } else if (name == "BULLET_3_VELOCITY") {
+ fin >> gameConstants.BULLET_3_VELOCITY;
+ } else if (name == "BULLET_3_AOE") {
+ fin >> gameConstants.BULLET_3_AOE;/*___________________________________*/
+ } else if (name == "TOWER_0_UP_COST") {
+ fin >> gameConstants.TOWER_0_UP_COST;
+ } else if (name == "TOWER_1_UP_COST") {
+ fin >> gameConstants.TOWER_1_UP_COST;
+ } else if (name == "TOWER_1_RANGE") {
+ fin >> gameConstants.TOWER_1_RANGE;
+ } else if (name == "TOWER_1_COOLDOWN") {
+ fin >> gameConstants.TOWER_1_COOLDOWN;
+ } else if (name == "TOWER_2_UP_COST") {
+ fin >> gameConstants.TOWER_2_UP_COST;
+ } else if (name == "TOWER_2_RANGE") {
+ fin >> gameConstants.TOWER_2_RANGE;
+ } else if (name == "TOWER_2_COOLDOWN") {
+ fin >> gameConstants.TOWER_2_COOLDOWN;
+ } else if (name == "TOWER_3_RANGE") {
+ fin >> gameConstants.TOWER_3_RANGE;
+ } else if (name == "TOWER_3_COOLDOWN") {
+ fin >> gameConstants.TOWER_3_COOLDOWN;
+ } else if (name == "WARRIOR_1_COST") {
+ fin >> gameConstants.WARRIOR_1_COST;
+ } else if (name == "WARRIOR_1_VELOCITY") {
+ fin >> gameConstants.WARRIOR_1_VELOCITY;
+ } else if (name == "WARRIOR_1_HP") {
+ fin >> gameConstants.WARRIOR_1_HP;
+ } else if (name == "WARRIOR_2_COST") {
+ fin >> gameConstants.WARRIOR_2_COST;
+ } else if (name == "WARRIOR_2_VELOCITY") {
+ fin >> gameConstants.WARRIOR_2_VELOCITY;
+ } else if (name == "WARRIOR_2_HP") {
+ fin >> gameConstants.WARRIOR_2_HP;
+ } else if (name == "WAVE_TIMER") {
+ fin >> gameConstants.WAVE_TIMER;
+ } else if (name == "SELECTOR_WAIT_TIME") {
+ fin >> gameConstants.SELECTOR_WAIT_TIME;
+ } else if (name == "DEBUG_MODE") {
+ fin >> gameConstants.DEBUG_MODE;
+ } else if (name == "CONNECTION_PORT") {
+ fin >> gameConstants.CONNECTION_PORT;
+ } else if (name == "IP_ADDR_SERVER") {
+ fin >> gameConstants.IP_ADDR_SERVER;
+ } else {
+ throw std::runtime_error(std::string("Unknown config parameter"));
+ }
+
+ }
+ fin.close();
+
+ return gameConstants;
+}
+
+int GameConstants::cBARRACKS_1_COST() const {
+ return BARRACKS_1_COST;
+}
+
+int GameConstants::cBARRACKS_2_COST() const {
+ return BARRACKS_2_COST;
+}
+
+int GameConstants::cBARRACKS_3_COST() const {
+ return BARRACKS_3_COST;
+}
+
+int GameConstants::cFARM_COST() const {
+ return FARM_COST;
+}
+
+int GameConstants::cFARM_INC_COST_BASE() const {
+ return FARM_INC_COST_BASE;
+}
+
+int GameConstants::cFARM_LVL_BENEFITS() const {
+ return FARM_LVL_BENEFITS;
+}
+
+int GameConstants::cFARM_TIME_CYCLE() const {
+ return FARM_TIME_CYCLE;
+}
+
+int GameConstants::cWEAPONS_1_COST() const {
+ return WEAPONS_1_COST;
+}
+
+int GameConstants::cWEAPONS_2_COST() const {
+ return WEAPONS_2_COST;
+}
+
+int GameConstants::cWEAPONS_3_COST() const {
+ return WEAPONS_3_COST;
+}
+
+int GameConstants::cCASTLE_HP() const {
+ return CASTLE_HP;
+}
+
+int GameConstants::cCASTLE_INIT_GOLD() const {
+ return CASTLE_INIT_GOLD;
+}
+
+int GameConstants::cCASTLE_WAVE_DURATION() const {
+ return CASTLE_WAVE_DURATION;
+}
+
+int GameConstants::cWARRIORS_BUFFER_SIZE() const {
+ return WARRIORS_BUFFER_SIZE;
+}
+
+int GameConstants::cBULLET_1_DAMAGE() const {
+ return BULLET_1_DAMAGE;
+}
+
+int GameConstants::cBULLET_1_VELOCITY() const {
+ return BULLET_1_VELOCITY;
+}
+
+int GameConstants::cBULLET_2_DAMAGE() const {
+ return BULLET_2_DAMAGE;
+}
+
+int GameConstants::cBULLET_2_VELOCITY() const {
+ return BULLET_2_VELOCITY;
+}
+
+int GameConstants::cBULLET_3_DAMAGE() const {
+ return BULLET_3_DAMAGE;
+}
+
+int GameConstants::cBULLET_3_VELOCITY() const {
+ return BULLET_3_VELOCITY;
+}
+
+int GameConstants::cBULLET_3_AOE() const {
+ return BULLET_3_AOE;
+}
+
+int GameConstants::cTOWER_0_UP_COST() const {
+ return TOWER_0_UP_COST;
+}
+
+int GameConstants::cTOWER_1_UP_COST() const {
+ return TOWER_1_UP_COST;
+}
+
+int GameConstants::cTOWER_1_RANGE() const {
+ return TOWER_1_RANGE;
+}
+
+int GameConstants::cTOWER_1_COOLDOWN() const {
+ return TOWER_1_COOLDOWN;
+}
+
+int GameConstants::cTOWER_2_UP_COST() const {
+ return TOWER_2_UP_COST;
+}
+
+int GameConstants::cTOWER_2_RANGE() const {
+ return TOWER_2_RANGE;
+}
+
+int GameConstants::cTOWER_2_COOLDOWN() const {
+ return TOWER_2_COOLDOWN;
+}
+
+int GameConstants::cTOWER_3_RANGE() const {
+ return TOWER_3_RANGE;
+}
+
+int GameConstants::cTOWER_3_COOLDOWN() const {
+ return TOWER_3_COOLDOWN;
+}
+
+int GameConstants::cWARRIOR_1_COST() const {
+ return WARRIOR_1_COST;
+}
+
+int GameConstants::cWARRIOR_1_VELOCITY() const {
+ return WARRIOR_1_VELOCITY;
+}
+
+int GameConstants::cWARRIOR_1_HP() const {
+ return WARRIOR_1_HP;
+}
+
+int GameConstants::cWARRIOR_2_COST() const {
+ return WARRIOR_2_COST;
+}
+
+int GameConstants::cWARRIOR_2_VELOCITY() const {
+ return WARRIOR_2_VELOCITY;
+}
+
+int GameConstants::cWARRIOR_2_HP() const {
+ return WARRIOR_2_HP;
+}
+
+int GameConstants::cWAVE_TIMER() const {
+ return WAVE_TIMER;
+}
+
+int GameConstants::cSELECTOR_WAIT_TIME() const {
+ return SELECTOR_WAIT_TIME;
+}
+
+int GameConstants::cDEBUG_MODE() const {
+ return DEBUG_MODE;
+}
+
+int GameConstants::cCONNECTION_PORT() const {
+ return CONNECTION_PORT;
+}
+
+const std::string &GameConstants::cIP_ADDR_SERVER() const {
+ return IP_ADDR_SERVER;
+}
diff --git a/src/GameConstants.h b/src/GameConstants.h
new file mode 100644
index 0000000..3186764
--- /dev/null
+++ b/src/GameConstants.h
@@ -0,0 +1,111 @@
+#ifndef SERVER_GAMECONSTANTS_H
+#define SERVER_GAMECONSTANTS_H
+
+
+class GameConstants {
+public:
+ static GameConstants& instance();
+
+ int cBARRACKS_1_COST() const;
+ int cBARRACKS_2_COST() const;
+ int cBARRACKS_3_COST() const;
+ int cFARM_COST() const;
+ int cFARM_INC_COST_BASE() const;
+ int cFARM_LVL_BENEFITS() const;
+ int cFARM_TIME_CYCLE() const;
+ int cWEAPONS_1_COST() const;
+ int cWEAPONS_2_COST() const;
+ int cWEAPONS_3_COST() const;
+ int cCASTLE_HP() const;
+ int cCASTLE_INIT_GOLD() const;
+ int cCASTLE_WAVE_DURATION() const;
+ int cWARRIORS_BUFFER_SIZE() const;
+ int cBULLET_1_DAMAGE() const;
+ int cBULLET_1_VELOCITY() const;
+ int cBULLET_2_DAMAGE() const;
+ int cBULLET_2_VELOCITY() const;
+ int cBULLET_3_DAMAGE() const;
+ int cBULLET_3_VELOCITY() const;
+ int cBULLET_3_AOE() const;
+ int cTOWER_0_UP_COST() const;
+ int cTOWER_1_UP_COST() const;
+ int cTOWER_1_RANGE() const;
+ int cTOWER_1_COOLDOWN() const;
+ int cTOWER_2_UP_COST() const;
+ int cTOWER_2_RANGE() const;
+ int cTOWER_2_COOLDOWN() const;
+ int cTOWER_3_RANGE() const;
+ int cTOWER_3_COOLDOWN() const;
+ int cWARRIOR_1_COST() const;
+ int cWARRIOR_1_VELOCITY() const;
+ int cWARRIOR_1_HP() const;
+ int cWARRIOR_2_COST() const;
+ int cWARRIOR_2_VELOCITY() const;
+ int cWARRIOR_2_HP() const;
+ int cWAVE_TIMER() const;
+
+ // server
+
+ int cSELECTOR_WAIT_TIME() const;
+ int cDEBUG_MODE() const;
+ int cCONNECTION_PORT() const;
+ const std::string &cIP_ADDR_SERVER() const;
+
+private:
+ GameConstants(){};
+ GameConstants(const GameConstants&) = delete;
+ GameConstants& operator=(const GameConstants&) = delete;
+
+ static bool initialized_;
+
+ int BARRACKS_1_COST;
+ int BARRACKS_2_COST;
+ int BARRACKS_3_COST;
+ int FARM_COST;
+ int FARM_INC_COST_BASE;
+ int FARM_LVL_BENEFITS;
+ int FARM_TIME_CYCLE;
+ int WEAPONS_1_COST;
+ int WEAPONS_2_COST;
+ int WEAPONS_3_COST;
+ int CASTLE_HP;
+ int CASTLE_INIT_GOLD;
+ int CASTLE_WAVE_DURATION;
+ int WARRIORS_BUFFER_SIZE;
+
+ int BULLET_1_DAMAGE;
+ int BULLET_1_VELOCITY;
+ int BULLET_2_DAMAGE;
+ int BULLET_2_VELOCITY;
+ int BULLET_3_DAMAGE;
+ int BULLET_3_VELOCITY;
+ int BULLET_3_AOE;
+
+ int TOWER_0_UP_COST;
+ int TOWER_1_UP_COST;
+ int TOWER_1_RANGE;
+ int TOWER_1_COOLDOWN;
+ int TOWER_2_UP_COST;
+ int TOWER_2_RANGE;
+ int TOWER_2_COOLDOWN;
+ int TOWER_3_RANGE;
+ int TOWER_3_COOLDOWN;
+
+ int WARRIOR_1_COST;
+ int WARRIOR_1_VELOCITY;
+ int WARRIOR_1_HP;
+ int WARRIOR_2_COST;
+ int WARRIOR_2_VELOCITY;
+ int WARRIOR_2_HP;
+
+ int WAVE_TIMER;
+
+ int SELECTOR_WAIT_TIME;
+ int DEBUG_MODE;
+ int CONNECTION_PORT;
+ std::string IP_ADDR_SERVER;
+};
+
+
+
+#endif //SERVER_GAMECONSTANTS_H
diff --git a/src/GameContext.h b/src/GameContext.h
index 525cc44..6af7e26 100644
--- a/src/GameContext.h
+++ b/src/GameContext.h
@@ -3,11 +3,13 @@
#include "ResourceManager/ResourcesIdentifier.h"
#include "ResourceManager/ResourcesHolder.h"
+#include "Multiplayer/MultiplayerFacade/AbstractMultiplayerFacade.h"
enum class Type {
lvlZero,
lvlOne,
lvlTwo,
+ lvlThree,
};
namespace sf {
@@ -31,17 +33,22 @@ namespace Player {
namespace States {
struct Context {
- explicit Context(sf::RenderWindow &window
- , sf::Font &font
- , TextureHolder &textureHolder
- , FontHolder &fontHolder
- , sf::Sprite &cursor)
-
- : window(&window)
- , font(&font)
- , textureHolder(&textureHolder)
- , fontHolder(&fontHolder)
- , cursor(&cursor)
+ explicit Context(
+ sf::RenderWindow &window,
+ sf::Font &font,
+ TextureHolder &textureHolder,
+ FontHolder &fontHolder,
+ sf::Sprite &cursor,
+ mp::AbstractMultiplayerFacade *p_mult
+ )
+
+ : window(&window),
+ font(&font),
+ textureHolder(&textureHolder),
+ fontHolder(&fontHolder),
+ cursor(&cursor),
+ p_id(new int(2)),
+ multiplayer(p_mult)
{};
@@ -51,7 +58,10 @@ namespace States {
FontHolder *fontHolder;
SoundManager *soundManager;
sf::Sprite *cursor;
+
+ std::shared_ptr p_id;
+ std::shared_ptr multiplayer;
};
}
-#endif //TOWERDEFENSE_GAMECONTEXT_H
+#endif //TOWERDEFENSE_GAMECONTEXT_H
\ No newline at end of file
diff --git a/src/GameOverState.cpp b/src/GameOverState.cpp
new file mode 100644
index 0000000..a9675d5
--- /dev/null
+++ b/src/GameOverState.cpp
@@ -0,0 +1,66 @@
+#include "GameOverState.h"
+#include "Constants.h"
+
+#include
+#include
+
+GameOverState::GameOverState(StateManager &stack, States::Context context)
+ : State(stack, context)
+{
+
+ texture.loadFromFile("Resources/map1.png");
+ texture.setSmooth(true);
+ sf::IntRect rect{ TILE_SIZE * (16 % 15), TILE_SIZE * (16 / 15), TILE_SIZE, TILE_SIZE };
+ mapSprite.setTexture(texture, rect);
+
+ sf::RenderWindow &window = *context.window;
+ sf::Font &font = *context.font;
+
+// sf::RenderWindow &window = *context.window;
+// sf::Font &font = *context.font;
+
+ gameOvetText.setString("YOU LOSE");
+ gameOvetText.setColor(sf::Color::White);
+ gameOvetText.setCharacterSize(100);
+ gameOvetText.setFont(context.fontHolder->get(Fonts::font1));
+ gameOvetText.setPosition(350.f, 200.f);
+
+ enterText.setString("ENTER Menu");
+ enterText.setColor(sf::Color::Black);
+ enterText.setCharacterSize(30);
+ enterText.setFont(context.fontHolder->get(Fonts::font1));
+ enterText.setPosition(500.f, 400.f);
+}
+
+bool GameOverState::handleEvent(const sf::Event &event)
+{
+ if (event.type == sf::Event::KeyPressed
+ && event.key.code == sf::Keyboard::Return)
+ {
+ popState();
+ pushState(States::ID::Menu);
+ }
+
+ return false;
+}
+
+bool GameOverState::update(sf::Time dt)
+{
+ return false;
+}
+
+void GameOverState::draw()
+{
+ getContext().window->clear(sf::Color(0, 165, 80, 0));
+ for (int i = 0; i < 20; i++)
+ for (int j = 0; j < 20; j++)
+ {
+ mapSprite.setPosition(static_cast(j * TILE_SIZE), static_cast(i * TILE_SIZE));
+ getContext().window->draw(mapSprite);
+ }
+
+ sf::RenderWindow &window = *getContext().window;
+ window.setView(window.getDefaultView());
+ window.draw(gameOvetText);
+ window.draw(enterText);
+}
\ No newline at end of file
diff --git a/src/GameOverState.h b/src/GameOverState.h
new file mode 100644
index 0000000..52820c1
--- /dev/null
+++ b/src/GameOverState.h
@@ -0,0 +1,21 @@
+#pragma once
+
+#include "State.h"
+#include
+#include "Tile.h"
+
+class GameOverState : public State
+{
+public:
+ explicit GameOverState(StateManager &stack, States::Context context);
+
+ bool handleEvent(const sf::Event &event) override;
+ bool update(sf::Time dt) override;
+ void draw() override;
+
+private:
+ sf::Text gameOvetText, enterText, scoreText;
+ sf::Texture texture;
+ Tile mapSprite;
+};
+
diff --git a/src/GameState.cpp b/src/GameState.cpp
index 478d63b..4e8782f 100644
--- a/src/GameState.cpp
+++ b/src/GameState.cpp
@@ -1,22 +1,506 @@
#include "GameState.h"
#include "Game.h"
+#include "Units/Warrior/WarriorLvlTwo.h"
+#include "Units/Tower/TowerLvlOne.h"
+#include "Graphics/Gui.h"
+#include "Graphics/Button.h"
+#include "Graphics/HUD.h"
+#include "Graphics/GraphicsUnits/GraphicsCastle.h"
+#include "Graphics/GraphicsUnits/GraphicsBullet.h"
+
+#define DELAY 300
GameState::GameState(StateManager &stack, States::Context context) :
+ lComponent(),
State(stack, context),
- gameData()
+ gameData(),
+ map(*context.window),
+ clock(sf::Time::Zero),
+ gComponent(context, *lComponent.getPlayer1(), *lComponent.getPlayer2()),
+ hud(context, lComponent.getPlayer1(), lComponent.getPlayer2()),
+ printCost(false){
+ std::cout << "start counstructor" << std::endl;
+ you.setString("You");
+ you.setFont(context.fontHolder->get(Fonts::font1));
+ you.setCharacterSize(50);
+ foe.setString("Foe");
+ foe.setFont(context.fontHolder->get(Fonts::font1));
+ foe.setCharacterSize(50);
+ if (*context.p_id == 1) {
+ curPlayer = lComponent.getPlayer1();
+ curPlayerRoad = 0;
+ you.setColor(sf::Color(215, 50, 50));
+ foe.setColor(sf::Color(40, 146, 224));
+ you.setPosition(10.f, 350.f);
+ foe.setPosition(1120.f, 350.f);
+ } else {
+ curPlayer = lComponent.getPlayer2();
+ curPlayerRoad = 1;
+ foe.setPosition(10.f, 350.f);
+ foe.setColor(sf::Color(215, 50, 50));
+ you.setColor(sf::Color(40, 146, 224));
+ you.setPosition(1120.f, 350.f);
+ }
+ timer.setFont(context.fontHolder->get(Fonts::font1));
+ timer.setPosition(990.f, 715.f);
+ map.analyze(towers1, towers2);
+ std::cout << "Map analyze" << std::endl;
+ map.getRoadRect(roadRect);
+ std::cout << "Get road rect" << std::endl;
+ initTower();
+ std::cout << "Init Tower" << std::endl;
+ initHUD();
+ std::cout << "Init HUD" << std::endl;
+ castle1.setTexture(context.textureHolder->get(Textures::castle1));
+ castle1.setScale(1.1, 1.1);
+ castle1.setPosition(-180.f, 173.f);
+ castle2.setTexture(context.textureHolder->get(Textures::castle2));
+ castle2.setScale(1.1, 1.1);
+ castle2.setPosition(940.f ,173.f);
+}
-{
+void GameState::initTower() {
+ sf::Texture b = getContext().textureHolder->get(Textures::target);
+ sf::IntRect rect{ TILE_SIZE, TILE_SIZE, TILE_SIZE, TILE_SIZE};
+ sf::Vector2f p;
+ for (int i = 0; i < towers1.size(); i++) {
+ lComponent.getPlayer1()->addTower(towers1[i], lComponent.getPlayer2()->getWarriors(), lComponent.getBullets());
+ if (*getContext().p_id == 1) {
+ auto bt = std::make_shared();
+ bt->setTexture(b);
+ bt->setTextureRect(rect);
+ p = towers1[i];
+ p.x -= TILE_SIZE / 2;
+ p.y -= TILE_SIZE / 2;
+ bt->setPosition(p);
+ bt->setCost(true);
+ bt->setInd(i);
+ bt->setCallback([this](int ind) {
+ if ((lComponent.getPlayer1()->getGold() >= lComponent.getPlayer1()->getTowers().at(ind)->getPrice()) &&
+ (Castle::checkValidUpgradeTower(lComponent.getPlayer1()->getTowers().at(ind)->getType(),
+ lComponent.getPlayer1()->getWeapons().getLvl()))) {
+ getContext().multiplayer->outcoming.emplace_back(1, 't', std::to_string(ind),
+ clock + sf::milliseconds(DELAY));
+ std::cout << ind << std::endl;
+ }
+ });
+ bt->setCostCallback([this](int ind) {
+ printCost = true;
+ if (lComponent.getPlayer1()->getTowers().at(ind)->getPrice() == -1) {
+ printCost = false;
+ }
+ sf::Vector2f pos = lComponent.getPlayer1()->getTowers().at(ind)->getPosition();
+ cost.setFont(getContext().fontHolder->get(Fonts::font1));
+ cost.setString(std::to_string(lComponent.getPlayer1()->getTowers().at(ind)->getPrice()));
+ cost.setPosition(pos.x - TILE_SIZE, pos.y - TILE_SIZE);
+// cost.setOutlineThickness(1.f);
+ if (lComponent.getPlayer1()->getGold() >= lComponent.getPlayer1()->getTowers().at(ind)->getPrice() &&
+ (Castle::checkValidUpgradeTower(lComponent.getPlayer1()->getTowers().at(ind)->getType(),
+ lComponent.getPlayer1()->getWeapons().getLvl()))) {
+ cost.setColor(sf::Color::Green);
+ } else {
+ cost.setColor(sf::Color::Red);
+ }
+ });
+ container.addWidget(bt);
+ }
+ }
+
+ for (int i = 0; i < towers2.size(); i++) {
+ lComponent.getPlayer2()->addTower(towers2[i], lComponent.getPlayer1()->getWarriors(), lComponent.getBullets());
+ auto bt = std::make_shared();
+ if (*getContext().p_id == 2) {
+ bt->setTexture(b);
+ bt->setTextureRect(rect);
+ p = towers2[i];
+ p.x -= TILE_SIZE / 2;
+ p.y -= TILE_SIZE / 2;
+ bt->setPosition(p);
+ bt->setInd(i);
+ bt->setCost(true);
+ bt->setCallback([this](int ind) {
+ if ((lComponent.getPlayer2()->getGold() >= lComponent.getPlayer2()->getTowers().at(ind)->getPrice()) &&
+ (Castle::checkValidUpgradeTower(lComponent.getPlayer2()->getTowers().at(ind)->getType(),
+ lComponent.getPlayer2()->getWeapons().getLvl()))) {
+ getContext().multiplayer->outcoming.emplace_back(2, 't', std::to_string(ind),
+ clock + sf::milliseconds(DELAY));
+ std::cout << ind << std::endl;
+ }
+ });
+ bt->setCostCallback([this](int ind) {
+ std::cout << ind << std::endl;
+ printCost = true;
+ if (lComponent.getPlayer2()->getTowers().at(ind)->getPrice() == -1) {
+ printCost = false;
+ }
+// cost.setOutlineThickness(1.f);
+ sf::Vector2f pos = lComponent.getPlayer2()->getTowers().at(ind)->getPosition();
+ cost.setFont(getContext().fontHolder->get(Fonts::font1));
+ cost.setString(std::to_string(lComponent.getPlayer2()->getTowers().at(ind)->getPrice()));
+ cost.setPosition(pos.x - TILE_SIZE / 2, pos.y - TILE_SIZE);
+ if (lComponent.getPlayer2()->getGold() >= lComponent.getPlayer2()->getTowers().at(ind)->getPrice() &&
+ (Castle::checkValidUpgradeTower(lComponent.getPlayer2()->getTowers().at(ind)->getType(),
+ lComponent.getPlayer2()->getWeapons().getLvl()))) {
+ cost.setColor(sf::Color::Green);
+ } else {
+ cost.setColor(sf::Color::Red);
+ }
+ getContext().window->draw(cost);
+ });
+ container.addWidget(bt);
+ }
+ }
}
-bool GameState::handleEvent(const sf::Event &event) {
+void GameState::initHUD() {
+ std::cout << "start init HUD" << std::endl;
+ hud.init();
+ sf::IntRect rect{0, 0, TILE_SIZE, TILE_SIZE};
+ auto addLvlOne = std::make_shared();
+ auto addLvlTwo = std::make_shared();
+ addLvlOne->setCost(true);
+ addLvlTwo->setCost(true);
+
+ std::cout << "1" << std::endl;
+
+ addLvlOne->setCallback([this](int ind) {
+
+ if (curPlayer->getBarracks().getLvl() >= 1
+ && curPlayer->getGold() >= GameConstants::instance().cWARRIOR_1_COST()) {
+ std::cout << "button warrior id 1" << std::endl;
+ curPlayer->addWarrior(Type::lvlOne, roadRect[curPlayerRoad]);
+ }
+ });
+
+ addLvlOne->setCostCallback([this](int ind){
+ printCost = true;
+ cost.setFont(getContext().fontHolder->get(Fonts::font1));
+ cost.setString(std::to_string(GameConstants::instance().cWARRIOR_1_COST()));
+ cost.setPosition(860.f, 705.f - TILE_SIZE / 2);
+// cost.setOutlineThickness(1.f);
+ if (curPlayer->getGold() >= GameConstants::instance().cWARRIOR_1_COST() &&
+ (curPlayer->getBarracks().getLvl() >= 1)) {
+ cost.setColor(sf::Color::Green);
+ } else {
+ cost.setColor(sf::Color::Red);
+ }
+ });
+
+ std::cout << "2" << std::endl;
+
+ addLvlOne->setTexture(getContext().textureHolder->get(Textures::addWarriorOne));
+ addLvlOne->setTextureRect(rect);
+ addLvlOne->setPosition(860.f, 705.f);
+ addLvlOne->setCost(true);
+
+ addLvlTwo->setCallback([this](int ind) {
+ if (curPlayer->getBarracks().getLvl() >= 2
+ && curPlayer->getGold() >= GameConstants::instance().cWARRIOR_2_COST()) {
+ std::cout << "button warrior id 2" << std::endl;
+ curPlayer->addWarrior(Type::lvlTwo, roadRect[curPlayerRoad]);
+ }
+ });
+
+ addLvlTwo->setCostCallback([this](int ind){
+ printCost = true;
+ cost.setFont(getContext().fontHolder->get(Fonts::font1));
+ cost.setString(std::to_string(GameConstants::instance().cWARRIOR_2_COST()));
+ cost.setPosition(920.f, 705.f - TILE_SIZE / 2);
+// cost.setOutlineThickness(1.f);
+ if (curPlayer->getGold() >= GameConstants::instance().cWARRIOR_2_COST() &&
+ (curPlayer->getBarracks().getLvl() >= 2)) {
+ cost.setColor(sf::Color::Green);
+ } else {
+ cost.setColor(sf::Color::Red);
+ }
+ });
+
+ std::cout << "3" << std::endl;
+
+ addLvlTwo->setTexture(getContext().textureHolder->get(Textures::addWarriorTwo));
+ addLvlTwo->setTextureRect(rect);
+ addLvlTwo->setPosition(920.f, 705.f);
+
+ std::cout << "4" << std::endl;
+
+ buttons.addWidget(addLvlOne);
+ buttons.addWidget(addLvlTwo);
+
+ std::cout << "5" << std::endl;
+
+ auto addFarm = std::make_shared();
+ auto addBarraks = std::make_shared();
+ auto addWeapons = std::make_shared();
+
+ std::cout << "6" << std::endl;
+
+ addFarm->setTexture(getContext().textureHolder->get(Textures::addFarm));
+ addFarm->setTextureRect(rect);
+ addFarm->setPosition(280.f, 705.f);
+
+ std::cout << "7" << std::endl;
+
+ addBarraks->setTexture(getContext().textureHolder->get(Textures::addBarraks));
+ addBarraks->setTextureRect(rect);
+ addBarraks->setPosition(220.f, 705.f);
+
+ std::cout << "8" << std::endl;
+
+ addWeapons->setTexture(getContext().textureHolder->get(Textures::addWeapons));
+ addWeapons->setTextureRect(rect);
+ addWeapons->setPosition(160.f, 705.f);
+
+ addWeapons->setCost(true);
+ addBarraks->setCost(true);
+ addFarm->setCost(true);
+
+ std::cout << "9" << std::endl;
+
+ addFarm->setCallback([this](int ind) {
+ if (curPlayer->getGold() >= curPlayer->getFarm().getUpgradeCost()) {
+ std::cout << "farm" << std::endl;
+ getContext().multiplayer->outcoming.emplace_back(*getContext().p_id, 'c', "f",
+ clock + sf::milliseconds(DELAY));
+ }
+ });
+ addFarm->setCostCallback([this](int ind) {
+ printCost = true;
+ cost.setFont(getContext().fontHolder->get(Fonts::font1));
+ cost.setString(std::to_string(curPlayer->getFarm().getUpgradeCost()));
+ cost.setPosition(290.f, 705.f - TILE_SIZE / 2);
+// cost.setOutlineThickness(1.f);
+ if (curPlayer->getGold() >= curPlayer->getFarm().getUpgradeCost()) {
+ cost.setColor(sf::Color::Green);
+ } else {
+ cost.setColor(sf::Color::Red);
+ }
+ });
+
+ std::cout << "10" << std::endl;
+
+ addBarraks->setCallback([this](int ind) {
+ if (curPlayer->getGold() >= curPlayer->getBarracks().getUpgradeCost()) {
+ std::cout << "barraks" << std::endl;
+ getContext().multiplayer->outcoming.emplace_back(*getContext().p_id, 'c', "b",
+ clock + sf::milliseconds(DELAY));
+ }
+ });
+
+ addBarraks->setCostCallback([this](int ind) {
+ printCost = true;
+ if (curPlayer->getBarracks().getLvl() == 2) {
+ printCost = false;
+ }
+ cost.setFont(getContext().fontHolder->get(Fonts::font1));
+ cost.setString(std::to_string(curPlayer->getBarracks().getUpgradeCost()));
+
+ cost.setPosition(220.f, 705.f - TILE_SIZE / 2);
+// cost.setOutlineThickness(1.f);
+ if (curPlayer->getGold() >= curPlayer->getBarracks().getUpgradeCost()) {
+ cost.setColor(sf::Color::Green);
+ } else {
+ cost.setColor(sf::Color::Red);
+ }
+ });
+
+ std::cout << "11" << std::endl;
+
+ addWeapons->setCallback([this](int ind) {
+
+ if (curPlayer->getGold() >= curPlayer->getWeapons().getUpgradeCost()) {
+ std::cout << "weapons" << std::endl;
+ getContext().multiplayer->outcoming.emplace_back(*getContext().p_id, 'c', "w",
+ clock + sf::milliseconds(DELAY));
+ }
+ });
+
+
+ addWeapons->setCostCallback([this](int ind) {
+ printCost = true;
+ if (curPlayer->getWeapons().getLvl() == 3) {
+ printCost = false;
+ }
+ cost.setFont(getContext().fontHolder->get(Fonts::font1));
+ cost.setString(std::to_string(curPlayer->getWeapons().getUpgradeCost()));
+ cost.setPosition(160.f, 705.f - TILE_SIZE / 2);
+// cost.setOutlineThickness(1.f);
+ if (curPlayer->getGold() >= curPlayer->getWeapons().getUpgradeCost()) {
+ cost.setColor(sf::Color::Green);
+ } else {
+ cost.setColor(sf::Color::Red);
+ }
+ });
+
+ std::cout << "12" << std::endl;
+
+ buttons.addWidget(addFarm);
+ buttons.addWidget(addBarraks);
+ buttons.addWidget(addWeapons);
+ std::cout << "end init hud" << std::endl;
+}
+
+bool GameState::handleEvent(const sf::Event& event) {
+// std::cout << "handle event" << std::endl;
+ printCost = false;
+ container.handleWidgetsEvent(event);
+ buttons.handleWidgetsEvent(event);
+ hud.handleEvent(event);
+ auto action = hud.getAction();
+
+ if (action == gui::HUD::Action::Exit) {
+ popState();
+ pushState(States::ID::GameOverState);
+ hud.setAction(gui::HUD::Action::None);
+ }
}
bool GameState::update(sf::Time dt) {
+ timer.setString("00:" + std::to_string(int(waveTimer - clock.asSeconds()) / 10) + std::to_string(int(waveTimer - clock.asSeconds()) % 10));
+ for (auto&& event : getContext().multiplayer->incoming) {
+ events.emplace_back(event.id, event.type, event.value, event.time);
+ }
+
+ int id = *getContext().p_id;
+ if (id == 1) {
+ if (lComponent.getPlayer1()->getHealth() < 0) {
+ popState();
+ pushState(States::ID::GameOverState); // Win Game
+ }
+
+ if (lComponent.getPlayer2()->getHealth() < 0) {
+ popState();
+ pushState(States::ID::WinState);
+ }
+ }
+
+ if (id == 2) {
+ if (lComponent.getPlayer2()->getHealth() < 0) {
+ popState();
+ pushState(States::ID::GameOverState); // Win Game
+ }
+
+ if (lComponent.getPlayer1()->getHealth() < 0) {
+ popState();
+ pushState(States::ID::WinState);
+ }
+ }
+
+ if (waveTimer <= clock.asSeconds()) {
+ waveTimer += gameConst.cWAVE_TIMER();
+ if (curPlayer->getWarriorsInBuffer() > 0) {
+ getContext().multiplayer->outcoming.emplace_back(*getContext().p_id, 'w',
+ Castle::generateWaveString(*curPlayer),
+ clock + sf::milliseconds(DELAY));
+ curPlayer->dropBuffer();
+ }
+ }
+
+ for (auto&& event : getContext().multiplayer->outcoming) {
+ events.emplace_back(event.id, event.type, event.value, event.time);
+ }
+
+ if (!getContext().multiplayer->isConnected())
+ getContext().multiplayer->outcoming.clear();
+ clock += dt;
+ manageEvents();
+ hud.update(dt);
+ lComponent.update(dt);
+ gComponent.update(dt, getContext(), lComponent.getBullets());
}
void GameState::draw() {
+ map.draw();
+ getContext().window->draw(hud);
+ getContext().window->draw(buttons);
+ gComponent.draw(getContext());
+ getContext().window->draw(castle1);
+ getContext().window->draw(castle2);
+ if (printCost) {
+ getContext().window->draw(cost);
+ }
+ getContext().window->draw(timer);
+ getContext().window->draw(you);
+ getContext().window->draw(foe);
+}
+
+void GameState::manageEvents() {
+ Castle* player = nullptr;
+
+ for(auto event = events.begin(); event != events.end();) {
+ if (event->time > clock) {
+ ++event;
+ continue;
+ }
+ std::cout << "pr event " << event->id << " " << event->type << " " << event->value << std::endl;
+ if (event->id == 1) {
+ player = lComponent.getPlayer1().get();
+ } else {
+ player = lComponent.getPlayer2().get();
+ }
+ switch (event->type) {
+ case 't': {
+ int index = stoi(event->value);
+ if (player->getGold() >= player->getTowers().at(index).get()->getPrice()) {
+ if (Castle::checkValidUpgradeTower(player->getTowers().at(index).get()->getType(),
+ player->getWeapons().getLvl())) {
+ std::cout << "gold: " << player->getGold() << " |cost: " << player->getTowers().at(index).get()->getPrice() << std::endl;
+ player->upgradeTower(index);
+ }
+ }
+ break;
+ }
+ case 'w':
+ std::cout << "Wave go!" << std::endl;
+ if (event->id != *getContext().p_id) {
+ int rect_num = 0;
+ if (*getContext().p_id == 2) {
+ rect_num = 0;
+ } else {
+ rect_num = 1;
+ }
+ for (auto type : event->value) {
+ switch (type) {
+ case '1':
+ if (player->getGold() >= gameConst.cWARRIOR_1_COST() && player->getBarracks().getLvl() >= 1) {
+ player->addWarrior(Type::lvlOne, roadRect[rect_num]);
+ }
+ break;
+
+ case '2':
+ if (player->getGold() >= gameConst.cWARRIOR_2_COST() && player->getBarracks().getLvl() >= 2) {
+ player->addWarrior(Type::lvlTwo, roadRect[rect_num]);
+ }
+ break;
+ }
+ }
+ player->dropBuffer();
+ }
+ player->letsMakingWave();
+ break;
+
+ case 'c':
+ int upgradeCost = 0;
+ switch (event->value[0]) {
+ case 'f':
+ upgradeCost = player->getFarm().getUpgradeCost();
+ break;
+ case 'b':
+ upgradeCost = player->getBarracks().getUpgradeCost();
+ break;
+ case 'w':
+ upgradeCost = player->getWeapons().getUpgradeCost();
+ break;
+ }
+ if (upgradeCost != 0 && player->getGold() >= upgradeCost) {
+ player->upgradeBuilding(event->value[0]);
+ }
+ break;
+ }
+ event = events.erase(event);
+ }
}
+
diff --git a/src/GameState.h b/src/GameState.h
index 390c917..4dd4403 100644
--- a/src/GameState.h
+++ b/src/GameState.h
@@ -2,27 +2,66 @@
#define TOWERDEFENSE_GAMESTATE_H
#include
-
+#include
#include "ResourceManager/ResourcesHolder.h"
#include "ResourceManager/ResourcesIdentifier.h"
-
#include "State.h"
#include "Graphics/Gui.h"
+#include "Map.h"
+#include "Units/Warrior/Warrior.h"
+#include "Graphics/Button.h"
+#include "Graphics/HUD.h"
+#include "Graphics/GraphicsUnits/GraphicsUnitManager.h"
+#include "Units/LogicUnitsManager.h"
+#include "GameConstants.h"
+
class GameState : public State {
public:
explicit GameState(StateManager& stack, States::Context context);
- ~GameState() = default;
bool handleEvent(const sf::Event &event) override;
bool update(sf::Time dt) override;
void draw() override;
+ void manageEvents();
+
+ GameConstants& gameConst = GameConstants::instance();
+
private:
+ void initTower();
+ void initHUD();
+
+ std::vector events;
+ sf::Time clock;
+
+ float waveTimer;
+
Player::GameData gameData;
gui::Gui containter;
+ Map map;
+
+ LogicUnitsManager lComponent;
+ GraphicsUnitManager gComponent;
+
+ gui::HUD hud;
+ std::vector towers1;
+ std::vector towers2;
+ gui::Gui container;
+ gui::Gui buttons;
+ std::vector roadRect;
+
+ std::shared_ptr curPlayer;
+ int curPlayerRoad;
+ sf::Sprite castle1;
+ sf::Sprite castle2;
+ sf::Text cost;
+ bool printCost;
+ sf::Text timer;
+ sf::Text you;
+ sf::Text foe;
};
-#endif //TOWERDEFENSE_GAMESTATE_H
+#endif //TOWERDEFENSE_GAMESTATE_H
\ No newline at end of file
diff --git a/src/GameStates.h b/src/GameStates.h
index 8f3c4f6..23f9a0a 100644
--- a/src/GameStates.h
+++ b/src/GameStates.h
@@ -5,10 +5,12 @@ namespace States {
enum class ID {
None = 0,
Game,
+ MultiplayerGame,
+ ConnectGame,
Menu,
Pause,
- GameOver,
- Win
+ GameOverState,
+ WinState
};
}
diff --git a/src/Graphics/Button.cpp b/src/Graphics/Button.cpp
index ae75ed7..de7e950 100644
--- a/src/Graphics/Button.cpp
+++ b/src/Graphics/Button.cpp
@@ -4,21 +4,48 @@ using namespace gui;
Button::Button() : callback(),
toggle(false),
- selected(false)
+ selected(false),
+ isCost(false)
{}
+void Button::setSprite(sf::Sprite newSprite) {
+ this->sprite = newSprite;
+}
+
void Button::setCallback(Callback callback) {
this->callback = std::move(callback);
}
+void Button::setCostCallback(Callback callback) {
+ this->cost = std::move(callback);
+}
+
+
+void Button::setCost(bool cost) {
+ isCost = cost;
+}
+
+void Button::setPrintCost(bool print) {
+ printCost = print;
+}
+
+void Button::setCostText(sf::Text cost) {
+ costText = cost;
+}
+
void Button::setTexture(const sf::Texture& texture) {
sprite.setTexture(texture);
changeTexture(Type::Normal);
centerText();
}
+void Button::setTextureRect(sf::IntRect rect) {
+ sprite.setTextureRect(rect);
+}
+
void Button::setText(const std::string& text) {
this->text.setString(text);
+ this->text.setScale(2.f, 2.f);
centerText();
}
@@ -27,12 +54,16 @@ void Button::setFont(const sf::Font& font) {
centerText();
}
+void Button::setInd(const int i) {
+ ind = i;
+}
+
void Button::handleEvent(const sf::Event& event) {
sf::FloatRect rect;
rect.left = getPosition().x;
rect.top = getPosition().y;
- rect.width = sprite.getLocalBounds().width * 2;
- rect.height = sprite.getLocalBounds().height * 2;
+ rect.width = sprite.getLocalBounds().width * sprite.getScale().x;
+ rect.height = sprite.getLocalBounds().height * sprite.getScale().y;
switch (event.type) {
case sf::Event::MouseButtonPressed:
@@ -49,12 +80,11 @@ void Button::handleEvent(const sf::Event& event) {
case sf::Event::MouseMoved:
if (rect.contains(static_cast(event.mouseMove.x),
static_cast(event.mouseMove.y))) {
- if (!selected) {
- select();
- }
- } else {
- if (selected) {
- deselect();
+ if (isCost) {
+// std::cout << "Tower " << ind << std::endl;
+ cost(ind);
+ } else {
+// std::cout << "Not is cost" << std::endl;
}
}
break;
@@ -64,7 +94,7 @@ void Button::handleEvent(const sf::Event& event) {
void Button::update(sf::Time dt) {}
void Button::select() {
- changeTexture(Type::Selected);
+ changeTexture(Type::Normal);
selected = true;
}
@@ -74,17 +104,14 @@ void Button::deselect() {
}
void Button::activate() {
- changeTexture(Type::Pressed);
-
if (callback) {
- callback();
+ callback(ind);
}
deactivate();
}
void Button::deactivate() {
- changeTexture(Type::Selected);
}
void Button::draw(sf::RenderTarget& target, sf::RenderStates states) const {
@@ -101,7 +128,7 @@ void Button::changeTexture(Type type) {
void Button::centerText() {
sf::FloatRect rect = text.getGlobalBounds();
text.setOrigin(rect.left, rect.top);
- text.setPosition({sprite.getLocalBounds().width + rect.width,
- sprite.getLocalBounds().height + rect.height / 2});
+ text.setPosition({sprite.getLocalBounds().width + 35,
+ sprite.getLocalBounds().height + rect.height});
}
\ No newline at end of file
diff --git a/src/Graphics/Button.h b/src/Graphics/Button.h
index 248299c..ab73014 100644
--- a/src/Graphics/Button.h
+++ b/src/Graphics/Button.h
@@ -8,7 +8,7 @@
namespace gui {
class Button : public Widget {
public:
- using Callback = std::function;
+ using Callback = std::function;
enum Type {
Normal = 0,
@@ -18,13 +18,19 @@ namespace gui {
explicit Button();
+ void setSprite(sf::Sprite newSprite);
void setCallback(Callback callback);
void setTexture(const sf::Texture& texture);
+ void setTextureRect(sf::IntRect rect);
void setText(const std::string& text);
void setFont(const sf::Font& font);
-
+ void setInd(const int i);
void handleEvent(const sf::Event& event) override ;
void update(sf::Time dt) override ;
+ void setCostCallback(Callback callback);
+ void setCost(bool cost);
+ void setPrintCost(bool print);
+ void setCostText(sf::Text cost);
private:
void select();
@@ -37,13 +43,18 @@ namespace gui {
void centerText();
Callback callback;
+ Callback cost;
sf::Sprite sprite;
sf::Text text;
+ sf::Text costText;
+ bool printCost;
+ bool isCost;
bool selected;
bool toggle;
+ int ind;
};
}
-#endif //TOWERDEFENSE_BUTTON_H
+#endif //TOWERDEFENSE_BUTTON_H
\ No newline at end of file
diff --git a/src/Graphics/GraphicsUnits/GraphicsBullet.cpp b/src/Graphics/GraphicsUnits/GraphicsBullet.cpp
new file mode 100644
index 0000000..ad3a893
--- /dev/null
+++ b/src/Graphics/GraphicsUnits/GraphicsBullet.cpp
@@ -0,0 +1,71 @@
+#include "GraphicsBullet.h"
+#include
+
+#define RAD_IN_DEGREE (180 / M_PI)
+
+GraphicsBullet::GraphicsBullet(std::shared_ptr bullet, States::Context& context)
+ : explosionTime_(100),
+ exploded_(false),
+ finished_(false),
+ bullet_(bullet) {
+ switch (bullet->getType()) {
+ case Type::lvlOne:
+ sprite_.setTexture(context.textureHolder->get(Textures::bulletOne));
+ explosion_.setTexture(context.textureHolder->get(Textures::explosionOne));
+ explosion_.setScale({0.5, 0.5});
+ break;
+ case Type::lvlTwo:
+ sprite_.setTexture(context.textureHolder->get(Textures::bulletTwo));
+ sprite_.setScale({0.75, 0.75});
+ explosion_.setTexture(context.textureHolder->get(Textures::explosionTwo));
+ explosion_.setScale({0.75, 0.75});
+ break;
+ case Type::lvlThree:
+ sprite_.setTexture(context.textureHolder->get(Textures::bulletThree));
+ explosion_.setTexture(context.textureHolder->get(Textures::explosionThree));
+ break;
+ }
+ sprite_.setOrigin(sprite_.getTextureRect().width / 2, sprite_.getTextureRect().height / 2);
+ explosion_.setOrigin(explosion_.getTextureRect().width / 2, explosion_.getTextureRect().height / 2);
+}
+
+bool GraphicsBullet::update(const sf::Time& dTime) {
+ if (bullet_ == nullptr) {
+ return false;
+ }
+ if (bullet_->isDisappeared()) {
+ finished_ = true;
+ return true;
+ }
+ if (!exploded_) {
+ if (bullet_->isExploded()) {
+ exploded_ = true;
+ explosion_.setPosition(bullet_->getPosition());
+ return true;
+ }
+ sprite_.setPosition(bullet_->getPosition());
+ sprite_.setRotation(static_cast(-bullet_->getAngle() * RAD_IN_DEGREE + 180));
+ } else {
+ explosionTime_ -= dTime.asMilliseconds();
+ if (explosionTime_ < 0) {
+ finished_ = true;
+ }
+ }
+ return false;
+}
+
+void GraphicsBullet::draw(States::Context& context) {
+ if (!exploded_) {
+ context.window->draw(sprite_);
+ } else {
+ context.window->draw(explosion_);
+ }
+}
+
+bool GraphicsBullet::isFinished() const {
+ return finished_;
+}
+
+bool GraphicsBullet::isExploded() const {
+ return exploded_;
+}
diff --git a/src/Graphics/GraphicsUnits/GraphicsBullet.h b/src/Graphics/GraphicsUnits/GraphicsBullet.h
new file mode 100644
index 0000000..cf2f070
--- /dev/null
+++ b/src/Graphics/GraphicsUnits/GraphicsBullet.h
@@ -0,0 +1,27 @@
+#ifndef SERVER_GRAPHICSBULLET_H
+#define SERVER_GRAPHICSBULLET_H
+
+
+#include "../../GameContext.h"
+#include "../../Units/Bullet/Bullet.h"
+
+class GraphicsBullet {
+public:
+ GraphicsBullet(std::shared_ptr bullet, States::Context& context);
+ bool update(const sf::Time& dTime);
+ void draw(States::Context& context);
+
+ bool isFinished() const;
+ bool isExploded() const;
+
+private:
+ std::shared_ptr bullet_;
+ sf::Sprite sprite_;
+ sf::Sprite explosion_;
+ sf::Int32 explosionTime_;
+ bool exploded_;
+ bool finished_;
+};
+
+
+#endif //SERVER_GRAPHICSBULLET_H
diff --git a/src/Graphics/GraphicsUnits/GraphicsCastle.cpp b/src/Graphics/GraphicsUnits/GraphicsCastle.cpp
new file mode 100644
index 0000000..00e595e
--- /dev/null
+++ b/src/Graphics/GraphicsUnits/GraphicsCastle.cpp
@@ -0,0 +1,47 @@
+#include "GraphicsCastle.h"
+#include "../../Castle/Castle.h"
+
+GraphicsCastle::GraphicsCastle(States::Context& context, Castle& castle)
+ : castle_(castle),
+ gWarriors_(),
+ gTower_(std::make_unique(context)) {
+ for (auto warrior: castle.getWarriors()) {
+ gWarriors_.push_back(std::make_shared(warrior, context));
+ }
+ numAliveWarriors_ = gWarriors_.size();
+}
+
+void GraphicsCastle::update(const sf::Time& dTime, States::Context& context) {
+ size_t numRealWarriors = castle_.getWarriors().size();
+ if (numRealWarriors != 0 || numAliveWarriors_ != 0) {
+ }
+ if (numRealWarriors > numAliveWarriors_) {
+ auto realWarriorsIterator = castle_.getWarriors().end();
+ size_t i = 0;
+ for (; i < numRealWarriors - numAliveWarriors_; ++i) {
+ realWarriorsIterator--;
+ gWarriors_.push_back(std::make_shared(*realWarriorsIterator, context));
+ }
+ numAliveWarriors_ += i;
+ }
+ for (auto gWarrior = gWarriors_.begin(); gWarrior != gWarriors_.end();) {
+ if ((*gWarrior)->update(dTime)) {
+ --numAliveWarriors_;
+ }
+
+ if ((*gWarrior)->isFinished()) {
+ gWarrior = gWarriors_.erase(gWarrior);
+ } else {
+ ++gWarrior;
+ }
+ }
+}
+
+void GraphicsCastle::draw(States::Context& context, int id) {
+ for (const auto &gWarrior: gWarriors_) {
+ gWarrior->draw(context);
+ }
+ for (const auto &tower: castle_.getTowers()) {
+ gTower_->draw(context, tower, id);
+ }
+}
\ No newline at end of file
diff --git a/src/Graphics/GraphicsUnits/GraphicsCastle.h b/src/Graphics/GraphicsUnits/GraphicsCastle.h
new file mode 100644
index 0000000..6fe1d03
--- /dev/null
+++ b/src/Graphics/GraphicsUnits/GraphicsCastle.h
@@ -0,0 +1,26 @@
+#ifndef SERVER_GRAPHICSCASTLE_H
+#define SERVER_GRAPHICSCASTLE_H
+
+
+#include
+#include "../../GameContext.h"
+#include "GraphicsWarrior.h"
+#include "GraphicsTower.h"
+
+class Castle;
+
+class GraphicsCastle {
+public:
+ GraphicsCastle(States::Context& context, Castle& castle);
+ void update(const sf::Time& dTime, States::Context& context);
+ void draw(States::Context& context, int id);
+
+private:
+ Castle& castle_;
+ std::list> gWarriors_;
+ std::unique_ptr gTower_;
+ size_t numAliveWarriors_;
+};
+
+
+#endif //SERVER_GRAPHICSCASTLE_H
diff --git a/src/Graphics/GraphicsUnits/GraphicsTower.cpp b/src/Graphics/GraphicsUnits/GraphicsTower.cpp
new file mode 100644
index 0000000..f84abc7
--- /dev/null
+++ b/src/Graphics/GraphicsUnits/GraphicsTower.cpp
@@ -0,0 +1,78 @@
+#include
+#include
+#include "GraphicsTower.h"
+
+GraphicsTower::GraphicsTower(States::Context &context) {
+ towerZeroRed_.setTexture(context.textureHolder->get(Textures::towerZeroRed));
+ towerZeroRed_.setOrigin(towerZeroRed_.getTextureRect().width / 2, towerZeroRed_.getTextureRect().height / 2);
+ towerZeroBlue_.setTexture(context.textureHolder->get(Textures::towerZeroBlue));
+ towerZeroBlue_.setOrigin(towerZeroBlue_.getTextureRect().width / 2, towerZeroBlue_.getTextureRect().height / 2);
+
+ towerTopLvlOne_.setTexture(context.textureHolder->get(Textures::towerOneTop));
+ towerTopLvlOne_.setOrigin(towerTopLvlOne_.getTextureRect().width / 2, towerTopLvlOne_.getTextureRect().height / 2);
+ towerBaseLvlOne_.setTexture(context.textureHolder->get(Textures::towerOneBase));
+ towerBaseLvlOne_.setOrigin(towerBaseLvlOne_.getTextureRect().width / 2, towerBaseLvlOne_.getTextureRect().height / 2);
+
+ towerTopLvlTwo_.setTexture(context.textureHolder->get(Textures::towerTwoTop));
+ towerTopLvlTwo_.setOrigin(towerTopLvlTwo_.getTextureRect().width / 2, towerTopLvlTwo_.getTextureRect().height / 2);
+ towerBaseLvlTwo_.setTexture(context.textureHolder->get(Textures::towerTwoBase));
+ towerBaseLvlTwo_.setOrigin(towerBaseLvlTwo_.getTextureRect().width / 2, towerBaseLvlTwo_.getTextureRect().height / 2);
+
+ towerTopLvlThree_.setTexture(context.textureHolder->get(Textures::towerThreeTop));
+ towerTopLvlThree_.setOrigin(towerTopLvlThree_.getTextureRect().width / 2, towerTopLvlThree_.getTextureRect().height / 2);
+ towerBaseLvlThree_.setTexture(context.textureHolder->get(Textures::towerThreeBase));
+ towerBaseLvlThree_.setOrigin(towerBaseLvlThree_.getTextureRect().width / 2, towerBaseLvlThree_.getTextureRect().height / 2);
+}
+
+void GraphicsTower::draw(States::Context& context, const std::shared_ptr& tower, int id) {
+ if (tower == nullptr) {
+ return;
+ }
+ switch (tower->getType()) {
+ case Type::lvlZero:
+ if (id == 1) {
+ towerZeroRed_.setPosition(tower->getPosition());
+ context.window->draw(towerZeroRed_);
+ } else {
+ towerZeroBlue_.setPosition(tower->getPosition());
+ context.window->draw(towerZeroBlue_);
+ }
+ break;
+ case Type::lvlOne:
+ towerBaseLvlOne_.setPosition(tower->getPosition());
+ if (id == 1) {
+ towerBaseLvlOne_.setColor(red_);
+ } else {
+ towerBaseLvlOne_.setColor(blue_);
+ }
+ towerTopLvlOne_.setPosition(tower->getPosition());
+ towerTopLvlOne_.setRotation(tower->getAngle());
+ context.window->draw(towerBaseLvlOne_);
+ context.window->draw(towerTopLvlOne_);
+ break;
+ case Type::lvlTwo:
+ towerBaseLvlTwo_.setPosition(tower->getPosition());
+ if (id == 1) {
+ towerBaseLvlTwo_.setColor(red_);
+ } else {
+ towerBaseLvlTwo_.setColor(blue_);
+ }
+ towerTopLvlTwo_.setPosition(tower->getPosition());
+ towerTopLvlTwo_.setRotation(tower->getAngle());
+ context.window->draw(towerBaseLvlTwo_);
+ context.window->draw(towerTopLvlTwo_);
+ break;
+ case Type::lvlThree:
+ towerBaseLvlThree_.setPosition(tower->getPosition());
+ if (id == 1) {
+ towerBaseLvlThree_.setColor(red_);
+ } else {
+ towerBaseLvlThree_.setColor(blue_);
+ }
+ towerTopLvlThree_.setPosition(tower->getPosition());
+ towerTopLvlThree_.setRotation(tower->getAngle());
+ context.window->draw(towerBaseLvlThree_);
+ context.window->draw(towerTopLvlThree_);
+ break;
+ }
+}
\ No newline at end of file
diff --git a/src/Graphics/GraphicsUnits/GraphicsTower.h b/src/Graphics/GraphicsUnits/GraphicsTower.h
new file mode 100644
index 0000000..d6d0d3c
--- /dev/null
+++ b/src/Graphics/GraphicsUnits/GraphicsTower.h
@@ -0,0 +1,29 @@
+#ifndef SERVER_GRAPHICSTOWER_H
+#define SERVER_GRAPHICSTOWER_H
+
+
+#include
+#include "../../GameContext.h"
+#include "../../Units/Tower/Tower.h"
+
+class GraphicsTower {
+public:
+ explicit GraphicsTower(States::Context& context);
+ void draw(States::Context& context, const std::shared_ptr& tower, int id);
+
+private:
+ sf::Sprite towerZeroRed_;
+ sf::Sprite towerZeroBlue_;
+ sf::Sprite towerTopLvlOne_;
+ sf::Sprite towerBaseLvlOne_;
+ sf::Sprite towerTopLvlTwo_;
+ sf::Sprite towerBaseLvlTwo_;
+ sf::Sprite towerTopLvlThree_;
+ sf::Sprite towerBaseLvlThree_;
+
+ const sf::Color red_ = sf::Color(255, 136, 138);
+ const sf::Color blue_ = sf::Color(91, 171, 232);
+};
+
+
+#endif //SERVER_GRAPHICSTOWER_H
diff --git a/src/Graphics/GraphicsUnits/GraphicsUnitManager.cpp b/src/Graphics/GraphicsUnits/GraphicsUnitManager.cpp
new file mode 100644
index 0000000..89a276f
--- /dev/null
+++ b/src/Graphics/GraphicsUnits/GraphicsUnitManager.cpp
@@ -0,0 +1,42 @@
+#include "GraphicsUnitManager.h"
+
+
+GraphicsUnitManager::GraphicsUnitManager(States::Context& context ,Castle& castle1, Castle& castle2)
+ : gCastle1(std::make_shared(GraphicsCastle(context, castle1))),
+ gCastle2(std::make_shared(GraphicsCastle(context, castle2))),
+ gBullets(),
+ intactBulletsCounter(0) {}
+
+void GraphicsUnitManager::update(const sf::Time& dt, States::Context& context, const std::vector>& bullets) {
+ gCastle1->update(dt, context);
+ gCastle2->update(dt, context);
+
+ if (bullets.size() > intactBulletsCounter) {
+ auto realBulletsIterator = bullets.end();
+ for (size_t i = 0; i < bullets.size() - intactBulletsCounter; ++i) {
+ realBulletsIterator--;
+ gBullets.push_back(std::make_shared(GraphicsBullet(*realBulletsIterator, context)));
+ }
+ intactBulletsCounter = bullets.size();
+ }
+
+ for (auto gBullet = gBullets.begin(); gBullet != gBullets.end();) {
+ if ((*gBullet)->isFinished()) {
+ gBullet = gBullets.erase(gBullet);
+ } else {
+
+ if ((*gBullet)->update(dt)) {
+ --intactBulletsCounter;
+ }
+ ++gBullet;
+ }
+ }
+}
+
+void GraphicsUnitManager::draw(States::Context& context) {
+ gCastle1->draw(context, 1);
+ gCastle2->draw(context, 2);
+ for (const auto &gBullet: gBullets) {
+ gBullet->draw(context);
+ }
+}
\ No newline at end of file
diff --git a/src/Graphics/GraphicsUnits/GraphicsUnitManager.h b/src/Graphics/GraphicsUnits/GraphicsUnitManager.h
new file mode 100644
index 0000000..c2087f5
--- /dev/null
+++ b/src/Graphics/GraphicsUnits/GraphicsUnitManager.h
@@ -0,0 +1,25 @@
+#ifndef SERVER_GRAPHICSUNITMANAGER_H
+#define SERVER_GRAPHICSUNITMANAGER_H
+
+
+#include "../../Castle/Castle.h"
+#include "GraphicsCastle.h"
+#include "GraphicsBullet.h"
+
+class GraphicsUnitManager {
+public:
+ GraphicsUnitManager(States::Context& context, Castle& castle1, Castle& castle2);
+
+ void update(const sf::Time &dt, States::Context& context, const std::vector>& bullets);
+ void draw(States::Context& context);
+
+private:
+ std::shared_ptr gCastle1;
+ std::shared_ptr gCastle2;
+
+ std::vector> gBullets;
+ size_t intactBulletsCounter;
+};
+
+
+#endif //SERVER_GRAPHICSUNITMANAGER_H
diff --git a/src/Graphics/GraphicsUnits/GraphicsWarrior.cpp b/src/Graphics/GraphicsUnits/GraphicsWarrior.cpp
new file mode 100644
index 0000000..f9da614
--- /dev/null
+++ b/src/Graphics/GraphicsUnits/GraphicsWarrior.cpp
@@ -0,0 +1,106 @@
+#include
+#include
+#include "GraphicsWarrior.h"
+
+#define FRAMES 4
+#define DEATH_DURATION 2000 //msec
+#define FINISHING_DURATION 200 //msec
+#define ANIMATION_SPEED 10
+
+
+GraphicsWarrior::GraphicsWarrior(std::shared_ptr& warrior, States::Context& context)
+ : warrior_(warrior),
+ deathDuration_(DEATH_DURATION),
+ finishedDuration_(FINISHING_DURATION),
+ died_(false),
+ finishing_(false),
+ finished_(false) {
+ switch (warrior_->getType()) {
+ case Type::lvlOne:
+ sprite_.setTexture(context.textureHolder->get(Textures::warriorOne));
+ break;
+ case Type::lvlTwo:
+ sprite_.setTexture(context.textureHolder->get(Textures::warriorTwo));
+ break;
+ }
+ sprite_.setScale({0.5, 0.5});
+ warriorSpriteRect_.first = sprite_.getTextureRect().width / FRAMES;
+ warriorSpriteRect_.second = sprite_.getTextureRect().height;
+ sprite_.setTextureRect(sf::IntRect(0, 0, warriorSpriteRect_.first, warriorSpriteRect_.second));
+ sprite_.setOrigin(warriorSpriteRect_.first / 2, warriorSpriteRect_.second / 2);
+ deadSprite_.setTexture(context.textureHolder->get(Textures::blood));
+ deadSprite_.setOrigin(deadSprite_.getTextureRect().width / 2, deadSprite_.getTextureRect().height / 2);
+ explosionSprite_.setTexture(context.textureHolder->get(Textures::warriorExplosion));
+ explosionSprite_.setOrigin(deadSprite_.getTextureRect().width / 2, deadSprite_.getTextureRect().height / 2);
+}
+
+bool GraphicsWarrior::update(const sf::Time& dTime) {
+ if (!finishing_ && !died_ && warrior_ != nullptr) {
+ if (!warrior_->isAlive()) {
+ deadSprite_.setPosition(warrior_->getPosition());
+ died_ = true;
+ warrior_.reset();
+ return true;
+ }
+ if (warrior_->isFinished()) {
+ explosionSprite_.setPosition(warrior_->getPosition());
+ if (warrior_.get()->getType() == Type::lvlTwo) {
+ explosionSprite_.setScale({1.5, 1.5});
+ }
+ finishing_ = true;
+ warrior_.reset();
+ return true;
+ }
+ lifeAnimation(dTime);
+ } else if (died_) {
+ deathAnimation(dTime);
+ } else {
+ finishedAnimation(dTime);
+ }
+ return false;
+
+}
+
+void GraphicsWarrior::draw(const States::Context& context) {
+ if (died_) {
+ context.window->draw(deadSprite_);
+ } else if (finishing_) {
+ context.window->draw(explosionSprite_);
+ } else {
+ context.window->draw(sprite_);
+ }
+}
+
+bool GraphicsWarrior::isFinished() const {
+ return finished_;
+}
+
+void GraphicsWarrior::lifeAnimation(const sf::Time& dTime) {
+ currentFrame_ += ANIMATION_SPEED * dTime.asSeconds();
+ if (currentFrame_ >= FRAMES)
+ currentFrame_ -= FRAMES;
+ sprite_.setTextureRect(sf::IntRect(warriorSpriteRect_.first * static_cast(currentFrame_), 0,
+ warriorSpriteRect_.first, warriorSpriteRect_.second));
+ sprite_.setPosition(warrior_->getPosition());
+ sprite_.setRotation(warrior_->getDirection());
+}
+
+void GraphicsWarrior::deathAnimation(const sf::Time& dTime) {
+ deathDuration_ -= dTime.asMilliseconds();
+ if (deathDuration_ <= 0) {
+ finished_ = true;
+ return;
+ }
+}
+
+bool GraphicsWarrior::isDied() const {
+ return died_;
+}
+
+void GraphicsWarrior::finishedAnimation(const sf::Time& dTime) {
+ finishedDuration_ -= dTime.asMilliseconds();
+ if (finishedDuration_ <= 0) {
+ finished_ = true;
+ return;
+ }
+}
diff --git a/src/Graphics/GraphicsUnits/GraphicsWarrior.h b/src/Graphics/GraphicsUnits/GraphicsWarrior.h
new file mode 100644
index 0000000..656b238
--- /dev/null
+++ b/src/Graphics/GraphicsUnits/GraphicsWarrior.h
@@ -0,0 +1,37 @@
+#ifndef SERVER_GRAPHICSWARRIOR_H
+#define SERVER_GRAPHICSWARRIOR_H
+
+
+#include
+#include
+#include "../../GameContext.h"
+#include "../../Units/Warrior/Warrior.h"
+
+class GraphicsWarrior {
+public:
+ explicit GraphicsWarrior(std::shared_ptr& warrior, States::Context& context);
+ bool update(const sf::Time& dTime);
+ void draw(const States::Context& context);
+
+ bool isFinished() const;
+ bool isDied() const;
+
+private:
+ void lifeAnimation(const sf::Time& dTime);
+ void deathAnimation(const sf::Time& dTime);
+ void finishedAnimation(const sf::Time& dTime);
+
+ std::shared_ptr warrior_;
+ sf::Sprite sprite_;
+ std::pair warriorSpriteRect_;//
+ sf::Sprite deadSprite_;
+ sf::Sprite explosionSprite_;
+ sf::Int32 deathDuration_;
+ sf::Int32 finishedDuration_;
+ float currentFrame_;
+ bool died_;
+ bool finishing_;
+ bool finished_;
+};
+
+#endif //SERVER_GRAPHICSWARRIOR_H
diff --git a/src/Graphics/HUD.cpp b/src/Graphics/HUD.cpp
index 99044b7..98b23e3 100644
--- a/src/Graphics/HUD.cpp
+++ b/src/Graphics/HUD.cpp
@@ -1,5 +1,179 @@
+#include "HUD.h"
+#include "../StateManager.h"
+#include "../ResourceManager/ResourcesHolder.h"
+#include "../ResourceManager/ResourcesIdentifier.h"
+
+using namespace gui;
+
+HUD::HUD(States::Context context, std::shared_ptr player1, std::shared_ptr player2)
+ : context(context),
+ gold(context.textureHolder->get(Textures::gold), context.fontHolder->get(Fonts::font1)),
+ livePlayer(context.textureHolder->get(Textures::lives), context.fontHolder->get(Fonts::font1)),
+ liveFoe(context.textureHolder->get(Textures::lives), context.fontHolder->get(Fonts::font1)),
+ levelBarraks(context.textureHolder->get(Textures::barraks), context.fontHolder->get(Fonts::font1)),
+ levelFarm(context.textureHolder->get(Textures::farm), context.fontHolder->get(Fonts::font1)),
+ levelWeapons(context.textureHolder->get(Textures::weapons), context.fontHolder->get(Fonts::font1)){
+
+ if (*context.p_id == 1) {
+ player = player1;
+ foe = player2;
+ } else {
+ player = player2;
+ foe = player1;
+ }
+
+ auto exit = std::make_shared();
+
+ exit->setTexture(context.textureHolder->get(Textures::exit), context.textureHolder->get(Textures::exit));
+ exit->setPosition({1120.f, 5.f});
+ exit->setCallback([this]
+ {
+ action = Action::Exit;
+
+ });
+
+ container.addWidget(exit);
+}
+
+void HUD::init()
+{
+ std::cout << "HUD::init()" << std::endl;
+
+ sf::IntRect rect{ TILE_SIZE * (15), TILE_SIZE * (0), TILE_SIZE, TILE_SIZE };
+ for (int i = 0; i < 10; i++) {
+ sf::RectangleShape tmp;
+ tmp.setPosition(350.f + i * 50.f, 710.f);
+ tmp.setSize(sf::Vector2f(50, 50));
+ tmp.setTexture(&context.textureHolder->get(Textures::map));
+ tmp.setTextureRect(rect);
+ buffer.push_back(tmp);
+ }
+
+ gold.setTexture(context.textureHolder->get(Textures::gold));
+ gold.setPosition(785.f, 0.f);
+
+ if (*context.p_id == 1) {
+ livePlayer.setPosition(0.f, 5.f);
+ liveFoe.setPosition(970.f, 5.f);
+ } else {
+ liveFoe.setPosition(0.f, 5.f);
+ livePlayer.setPosition(970.f, 5.f);
+ }
+
+ livePlayer.setTexture(context.textureHolder->get(Textures::lives));
+ livePlayer.setScale({1.f / 3.f, 1.f / 3.f});
+ liveFoe.setTexture(context.textureHolder->get(Textures::lives));
+ liveFoe.setScale({1.f / 3.f, 1.f / 3.f});
+
+ totalGold.setFont(context.fontHolder->get(Fonts::font1));
+ totalGold.setString(std::to_string(player->getGold()));
+ totalGold.setPosition(835.f, 10.f);
//
-// Created by Falcon on 11.04.2018.
-//
+ totalPlayerLives.setFont(context.fontHolder->get(Fonts::font1));
+ totalFoeLives.setFont(context.fontHolder->get(Fonts::font1));
+ totalPlayerLives.setString(std::to_string(player->getHealth()));
+ totalFoeLives.setString(std::to_string(foe->getHealth()));
+ totalLevelFarm.setFont(context.fontHolder->get(Fonts::font1));
+ totalLevelBarraks.setFont(context.fontHolder->get(Fonts::font1));
+ totalLevelWeapons.setFont(context.fontHolder->get(Fonts::font1));
-#include "HUD.h"
+ totalLevelBarraks.setString(std::to_string(player->getBarracks().getLvl()));
+ totalLevelFarm.setString(std::to_string(player->getFarm().getLvl()));
+ totalLevelWeapons.setString(std::to_string(player->getWeapons().getLvl()));
+
+ totalLevelWeapons.setPosition(285.f, 10.f);
+ totalLevelFarm.setPosition(590.f, 10.f);
+ totalLevelBarraks.setPosition(425.f, 10.f);
+
+ levelFarm.setTexture(context.textureHolder->get(Textures::farm));
+ levelBarraks.setTexture(context.textureHolder->get(Textures::barraks));
+ levelWeapons.setTexture(context.textureHolder->get(Textures::weapons));
+
+ levelBarraks.setPosition(370.f, 5.f);
+ levelFarm.setPosition(520.f, 5.f);
+ levelWeapons.setPosition(220.f, 5.f);
+
+ totalLevelFarm.setString(std::to_string(player->getFarm().getLvl()));
+ totalLevelWeapons.setString(std::to_string(player->getWeapons().getLvl()));
+
+ if (*context.p_id == 1) {
+ totalFoeLives.setPosition(50.f, 10.f);
+ totalPlayerLives.setPosition(1020.f, 10.f);
+ } else {
+ totalPlayerLives.setPosition(50.f, 10.f);
+ totalFoeLives.setPosition(1020.f, 10.f);
+ }
+}
+
+void HUD::handleEvent(const sf::Event &event)
+{
+ container.handleWidgetsEvent(event);
+}
+
+void HUD::update(sf::Time dt)
+{
+ totalGold.setString(std::to_string(player->getGold()));
+ totalPlayerLives.setString(std::to_string(foe->getHealth()));
+ totalFoeLives.setString(std::to_string(player->getHealth()));
+
+ totalLevelBarraks.setString(std::to_string(player->getBarracks().getLvl()));
+ totalLevelFarm.setString(std::to_string(player->getFarm().getLvl()));
+ totalLevelWeapons.setString(std::to_string(player->getWeapons().getLvl()));
+}
+
+
+
+
+void gui::HUD::setAction(Action action)
+{
+ this->action = action;
+}
+
+const HUD::Action HUD::getAction() const
+{
+ return action;
+}
+
+void HUD::draw(sf::RenderTarget &target, sf::RenderStates states) const
+{
+ states.transform *= getTransform();
+ target.draw(gold);
+ target.draw(livePlayer);
+ target.draw(liveFoe);
+ target.draw(totalGold);
+ target.draw(totalPlayerLives);
+ target.draw(totalFoeLives);
+ target.draw(container);
+ target.draw(totalLevelWeapons);
+ target.draw(totalLevelBarraks);
+ target.draw(totalLevelFarm);
+ target.draw(levelFarm);
+ target.draw(levelWeapons);
+ target.draw(levelBarraks);
+
+ for (auto i : buffer) {
+ target.draw(i);
+ }
+
+ auto p = 0.f;
+
+ size_t i = 0;
+ for (auto warrior : player->getWarriorsBuffer()) {
+ if (i++ < player->getWarriorsToWave()) {
+ continue;
+ }
+ sf::Sprite tmp;
+ sf::IntRect rect{ 0, 0, TILE_SIZE, TILE_SIZE };
+ tmp.setTextureRect(rect);
+ if (warrior->getType() == Type::lvlOne) {
+ tmp.setTexture(context.textureHolder->get(Textures::warriorIconOne));
+ } else {
+ tmp.setTexture(context.textureHolder->get(Textures::warriorIconTwo));
+ }
+ tmp.setPosition(355.f + p, 715.f);
+
+ tmp.setScale(1.f / 2.f, 1.f / 2.f);
+ p += 50.f;
+ target.draw(tmp);
+ }
+}
\ No newline at end of file
diff --git a/src/Graphics/HUD.h b/src/Graphics/HUD.h
index 5da6a90..37f0bfd 100644
--- a/src/Graphics/HUD.h
+++ b/src/Graphics/HUD.h
@@ -1,14 +1,75 @@
-//
-// Created by Falcon on 11.04.2018.
-//
+#pragma once
-#ifndef TOWERDEFENSE_HUD_H
-#define TOWERDEFENSE_HUD_H
+#include "Widget.h"
+#include "Button.h"
+#include "Icon.h"
+#include "Gui.h"
+#include "../GameContext.h"
+//#include "Tower.h"
+#include "../Castle/Castle.h"
+#include "Label.h"
+namespace gui
+{
+ class HUD : public Widget
+ {
+ public:
+ enum class Action
+ {
+ None,
+ Audio,
+ Music,
+ Pause,
+ Forward,
+ Upgrade,
+ Sell,
+ Exit
+ };
-class HUD {
+ HUD(States::Context context, std::shared_ptr player1, std::shared_ptr player2);
-};
+ void init();
+ void handleEvent(const sf::Event &event) override;
+ void update(sf::Time dt) override;
+
+ void setAction(Action action);
+ const Action getAction() const;
+
+ private:
+ virtual void draw(sf::RenderTarget &target, sf::RenderStates states) const override;
+
+ Action action;
+
+ Gui container;
+ States::Context context;
+ //Player::GameData *gameData;
+ std::shared_ptr player;
+ std::shared_ptr foe;
+ sf::Texture texture;
+ sf::Font font;
+
+
+ Label gold;
+ Label livePlayer;
+ Label liveFoe;
+
+ Label levelBarraks;
+ Label levelFarm;
+ Label levelWeapons;
+
+// Label star;
+
+ sf::Text totalGold;
+ sf::Text totalPlayerLives;
+ sf::Text totalFoeLives;
+ sf::Text totalLevelBarraks;
+ sf::Text totalLevelFarm;
+ sf::Text totalLevelWeapons;
+ sf::Text currentLevel;
+ sf::Text score;
+ std::vector buffer;
+ sf::RectangleShape background;
+ };
+}
-#endif //TOWERDEFENSE_HUD_H
diff --git a/src/Graphics/Icon.cpp b/src/Graphics/Icon.cpp
index d7fd193..99e4234 100644
--- a/src/Graphics/Icon.cpp
+++ b/src/Graphics/Icon.cpp
@@ -2,69 +2,85 @@
using namespace gui;
-Icon::Icon() : callback(),
- toggle(false),
- selected(false)
-{}
+Icon::Icon()
+ : callback()
+ , toggle(false)
+ , selected(false)
+{
+}
-void Icon::setCallback(Callback callback) {
+void Icon::setCallback(Callback callback)
+{
this->callback = std::move(callback);
}
-void Icon::setTexture(const sf::Texture& texture1, const sf::Texture& texture2) {
+void Icon::setTexture(const sf::Texture &texture1, const sf::Texture &texture2)
+{
sprite1.setTexture(texture1);
sprite2.setTexture(texture2);
sprite = sprite1;
changeTexture(Type::Normal);
}
-void Icon::handleEvent(const sf::Event &event) {
+
+
+void Icon::handleEvent(const sf::Event &event)
+{
sf::FloatRect rect;
rect.left = getPosition().x;
- rect.top = getPosition().y;
- rect.width = sprite.getLocalBounds().width;
+ rect.top = getPosition().y;
+ rect.width = sprite.getLocalBounds().width;
rect.height = sprite.getLocalBounds().height;
- switch (event.type) {
+ switch (event.type)
+ {
case sf::Event::MouseButtonPressed:
case sf::Event::MouseButtonReleased:
- if (rect.contains(static_cast(event.mouseButton.x),
- static_cast(event.mouseButton.y))) {
- if (event.type == sf::Event::MouseButtonPressed) {
+ if (rect.contains(static_cast(event.mouseButton.x), static_cast(event.mouseButton.y)))
+ {
+ if (event.type == sf::Event::MouseButtonPressed)
+ {
activate();
}
}
break;
}
-
}
-void Icon::update(sf::Time dt) {}
+void Icon::update(sf::Time dt)
+{
+}
-void Icon::activate() {
- if (callback) {
+void Icon::activate()
+{
+ if (callback)
callback();
- }
- if (toggle) {
+ if (toggle)
+ {
deactivate();
- } else {
+ } else
+ {
sprite = sprite2;
toggle = true;
}
}
-void Icon::deactivate() {
+void Icon::deactivate()
+{
sprite = sprite1;
toggle = false;
}
-void Icon::draw(sf::RenderTarget &target, sf::RenderStates states) const {
+void Icon::draw(sf::RenderTarget &target, sf::RenderStates states) const
+{
states.transform *= getTransform();
target.draw(sprite, states);
target.draw(text, states);
}
-void Icon::changeTexture(Type type) {
+void Icon::changeTexture(Type type)
+{
sf::IntRect textureRect(190 * type, 0, 50, 50);
sprite.setTextureRect(textureRect);
-}
\ No newline at end of file
+}
+
diff --git a/src/Graphics/Icon.h b/src/Graphics/Icon.h
index 4a90ba4..219966b 100644
--- a/src/Graphics/Icon.h
+++ b/src/Graphics/Icon.h
@@ -1,15 +1,18 @@
-#ifndef TOWERDEFENSE_ICON_H
-#define TOWERDEFENSE_ICON_H
+#pragma once
#include
#include "Widget.h"
-namespace gui {
- class Icon : public Widget {
+namespace gui
+{
+ class Icon : public Widget
+ {
+ public:
using Callback = std::function;
- enum Type {
+ enum Type
+ {
Normal = 0,
Selected,
Pressed
@@ -18,29 +21,25 @@ namespace gui {
explicit Icon();
void setCallback(Callback callback);
- void setTexture(const sf::Texture& texture1,
- const sf::Texture& texture2);
- void handleEvent(const sf::Event& event) override ;
+ void setTexture(const sf::Texture &texture1, const sf::Texture &texture2);
+ void handleEvent(const sf::Event &event) override;
void update(sf::Time dt) override;
private:
void activate();
void deactivate();
- virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const override;
+ virtual void draw(sf::RenderTarget &target, sf::RenderStates states) const override;
void changeTexture(Type type);
- Callback callback;
+
+ Callback callback;
sf::Sprite sprite;
sf::Sprite sprite1;
sf::Sprite sprite2;
- sf::Text text;
+ sf::Text text;
bool selected;
bool toggle;
-
};
-}
-
-
-#endif //TOWERDEFENSE_ICON_H
+}
\ No newline at end of file
diff --git a/src/Graphics/Label.cpp b/src/Graphics/Label.cpp
index 9231da1..9c9ac43 100644
--- a/src/Graphics/Label.cpp
+++ b/src/Graphics/Label.cpp
@@ -2,7 +2,10 @@
using namespace gui;
-Label::Label() {}
+Label::Label(sf::Texture texture, sf::Font &font) {
+ sprite.setTexture(texture);
+ text.setFont(font);
+}
void Label::handleEvent(const sf::Event &event) {
sf::FloatRect rect = sprite.getGlobalBounds();
diff --git a/src/Graphics/Label.h b/src/Graphics/Label.h
index b913512..db9d045 100644
--- a/src/Graphics/Label.h
+++ b/src/Graphics/Label.h
@@ -5,8 +5,8 @@
namespace gui {
class Label : public Widget {
- Label();
-
+ public:
+ Label(sf::Texture texture, sf::Font &font);
void handleEvent(const sf::Event& event) override;
void update(sf::Time dt) override ;
diff --git a/src/Graphics/TextBox.cpp b/src/Graphics/TextBox.cpp
new file mode 100644
index 0000000..812883f
--- /dev/null
+++ b/src/Graphics/TextBox.cpp
@@ -0,0 +1,83 @@
+#include "TextBox.h"
+
+#include
+
+using namespace gui;
+
+Textbox::Textbox(sf::Font &font): font(font), is_focused(false) {
+ text = sf::Text("", font);
+ background.setFillColor(sf::Color::White);
+ text.setColor(sf::Color::Black);
+}
+
+void Textbox::update(sf::Time dt) { }
+
+void Textbox::draw(sf::RenderTarget& target, sf::RenderStates states) const {
+ target.draw(background, states);
+ target.draw(text, states);
+}
+
+void Textbox::setDimensons(float newX, float newY, float newWidth, float newHeight) {
+ x = newX;
+ y = newY;
+ width = newWidth;
+ height = newHeight;
+ text.setPosition(x, y-height/5);
+ text.setCharacterSize(height);
+ background.setPosition(x, y);
+ background.setSize(sf::Vector2f(width, height));
+}
+
+void Textbox::setString(const std::string &newString) {
+ string = newString;
+ text.setString(string);
+}
+
+const std::string & Textbox::getString() {
+ return string;
+}
+
+void Textbox::handleEvent(const sf::Event &event) {
+ sf::FloatRect rect;
+ rect.left = x;
+ rect.top = y;
+ rect.width = width;
+ rect.height = height;
+
+ if (event.type == sf::Event::MouseButtonPressed)
+ is_focused = rect.contains(event.mouseButton.x, event.mouseButton.y);
+
+ if (is_focused && !string.empty() && event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Return) {
+ is_focused = false;
+ // todo прочекать строку, чтобы не было пробелов и прочих гадостей
+ callback(ind);
+ string.clear();
+ }
+
+ if (is_focused && event.type == sf::Event::TextEntered) {
+ enterText(event.text.unicode);
+ }
+
+
+}
+
+bool Textbox::enterText(sf::Uint32 unicode) {
+ if(unicode == 8)
+ string = string.substr(0, string.length()-1); // delete key
+ else if(unicode == 10)
+ return true; // return key
+ else
+ if (string.size() <= 10) {
+ string += (char) unicode;
+ }
+ text.setString(string);
+ return false;
+}
+
+void Textbox::setCallback(Textbox::Callback callback) {
+ this->callback = std::move(callback);
+}
+
+void Textbox::setInd(const int i) {
+ ind = i;
+}
diff --git a/src/Graphics/TextBox.h b/src/Graphics/TextBox.h
new file mode 100644
index 0000000..c3632eb
--- /dev/null
+++ b/src/Graphics/TextBox.h
@@ -0,0 +1,43 @@
+#pragma once
+
+#include
+#include
+#include
+#include
+#include "Widget.h"
+namespace gui {
+ class Textbox : public Widget {
+ public:
+ using Callback = std::function;
+
+ explicit Textbox(sf::Font &font);
+
+ void draw(sf::RenderTarget& target, sf::RenderStates states) const override;
+ void update(sf::Time dt) override ;
+ void handleEvent(const sf::Event& event) override ;
+
+ void setDimensons(float newX, float newY, float newWidth, float newHeight);
+ void setString(const std::string &newString);
+ void setInd(int i);
+ void setCallback(Callback callback);
+
+ const std::string & getString();
+
+ private:
+ bool is_focused;
+
+ float x;
+ float y;
+ float width;
+ float height;
+ std::string string;
+ sf::Font &font;
+ sf::RectangleShape background;
+ sf::Text text;
+
+ int ind;
+ Callback callback;
+
+ bool enterText(sf::Uint32 unicode);
+ };
+}
\ No newline at end of file
diff --git a/src/Map.cpp b/src/Map.cpp
new file mode 100644
index 0000000..7505594
--- /dev/null
+++ b/src/Map.cpp
@@ -0,0 +1,316 @@
+#include "Map.h"
+#include
+
+
+Map::Map(sf::RenderWindow &window) : window(window) {
+ std::ifstream fin("Resources/map.csv");
+ texture.loadFromFile("Resources/map1.png");
+ fin >> count;
+ fin >> height >> width;
+ map.resize(height, std::vector(width));
+ int tileNumber;
+
+ for (int i = 0; i < height; i++) {
+ for (int j = 0; j < width; j++) {
+ fin >> tileNumber;
+ map[i][j].setTileNumber(tileNumber);
+ if (tileNumber == 13 || tileNumber == 14) {
+ map[i][j].setTileNumber(tileNumber);
+ tileNumber = 16;
+ }
+ sf::IntRect rect{ TILE_SIZE * (tileNumber % 15), TILE_SIZE * (tileNumber / 15), TILE_SIZE, TILE_SIZE };
+ map[i][j].setTexture(texture, rect);
+ map[i][j].setPosition(static_cast(j * TILE_SIZE), static_cast(i * TILE_SIZE));
+ }
+ }
+
+ for (int i = 0; i < count; i++) {
+ std::pair tmp;
+ fin >> tmp.second >> tmp.first;
+ start.push_back(tmp);
+ }
+ fin.close();
+}
+
+
+void Map::analyze(std::vector& towers1, std::vector& towers2) {
+ for (int i = 0; i < height; i++) {
+ for (int j = 0; j < width; j++) {
+ if (map[i][j].getTileNumber() == 13 || map[i][j].getTileNumber() == 14) {
+ sf::Vector2f tmp((j + 0.5) * TILE_SIZE, (i + 0.5) * TILE_SIZE);
+ if (map[i][j].getTileNumber() == 13) {
+ towers1.push_back(tmp);
+ } else {
+ towers2.push_back(tmp);
+ }
+ }
+ }
+ }
+
+ //std::cout << width << " " << height << " " << start.first << " " << start.second << std::endl;
+ int move = 0; // 1 - down, 2 - up, 3 - right, 4 - left, 0 - default
+
+ for (auto s: start) {
+ std::cout << "start.x "<< s.first << " start.y " << s.second << ";" << std::endl;
+ LogicMap tmpRoadRect;
+ if (s.first == 0) {
+ move = 3;
+ } else if (s.first == (width - 1)) {
+ move = 4;
+ } else if (s.second == 0) {
+ move = 1;
+ } else if (s.second == (height - 1)) {
+ move = 2;
+ }
+ if ((s.first == 0) && (s.second == 3)) {
+ move = 2;
+ }
+
+ if ((s.first == 17) && (s.second == 8)) {
+ move = 1;
+ }
+
+ std::cout << move << std::endl;
+
+ std::pair this1, this2;
+ this1.first = s.second;
+ this1.second = s.first;
+ this2.first = s.second;
+ this2.second = s.first;
+
+ std::pair rect;
+ rect.first.height = 0;
+ rect.first.width = 0;
+
+
+ std::cout << s.first << " " << s.second << " " << move << std::endl;
+ if (move == 1 || move == 2) {
+ this2.second = this1.second + 1;
+ rect.first.width = TILE_SIZE;
+ sf::Vector2f st((s.first + 1) * TILE_SIZE, (s.second) * TILE_SIZE);
+ if (move == 1) {
+ rect.first.top = (s.second) * TILE_SIZE;
+ rect.first.left = (s.first + 0.5) * TILE_SIZE;
+ rect.first.width = TILE_SIZE;
+ rect.second = DOWN;
+ }
+ tmpRoadRect.start = st;
+ } else if (move == 3 || move == 4) {
+ if (move == 3) {
+ rect.first.top = (s.second + 0.5) * TILE_SIZE;
+ rect.first.left = (s.first - 0.5) * TILE_SIZE;
+ rect.first.width = 0.5 * TILE_SIZE;
+ }
+ this2.first = s.second + 1;
+ rect.first.height = TILE_SIZE;
+ sf::Vector2f st((s.first) * TILE_SIZE, (s.second + 1) * TILE_SIZE);
+ tmpRoadRect.start = st;
+ }
+
+ std::pair point;
+// sf::Vector2f s((start.first + 1) * TILE_SIZE, (start.second) * TILE_SIZE);
+// roadRect.start = s;
+ while ((this1.first == s.second || (this1.first != height && this1.first != -1)) &&
+ (this1.second == s.first || (this1.second != width && this1.second != -1)) &&
+ (map[this1.first][this1.second].getTileNumber() != 16 || map[this2.first][this2.second].getTileNumber() != 16)) {
+ //std::cout << "(" << this1.first + 1 << ";" << this1.second + 1 << ") " << " (" << this2.first + 1 << ";"
+ // << this2.second + 1 << ")" << std::endl;
+ switch (move) {
+ case 1:
+ if (map[this1.first][this1.second].getTileNumber() == 18) {
+ std::cout << "!1!" << std::endl;
+ rect.second = DOWN;
+ tmpRoadRect.road.push_back(rect);
+ rect.first.top = (this1.first - 0.5) * TILE_SIZE;
+ rect.first.left = (this1.second + 0.5) * TILE_SIZE;
+ this1.first--;
+ this1.second++;
+ move = 3;
+ rect.first.width = 0.5 * TILE_SIZE;
+ rect.first.height = TILE_SIZE;
+ } else if (map[this2.first][this2.second].getTileNumber() == 19) {
+ std::cout << "!2!" << std::endl;
+ rect.second = DOWN;
+ tmpRoadRect.road.push_back(rect);
+ this1.first--;
+ this2.second--;
+ move = 4;
+ rect.first.width = 0.5 * TILE_SIZE;
+ rect.first.height = TILE_SIZE;
+ } else {
+ std::cout << "!3!" << std::endl;
+ rect.first.height += TILE_SIZE;
+ this1.first++;
+ this2.first++;
+ }
+ break;
+ case 2:
+ if (map[this1.first][this1.second].getTileNumber() == 3) {
+ std::cout << "!4!" << std::endl;
+ rect.second = UP;
+ rect.first.top = (this1.first + 1) * TILE_SIZE;
+ rect.first.left = (this1.second + 0.5) * TILE_SIZE;
+ tmpRoadRect.road.push_back(rect);
+ rect.first.top = (this1.first + 0.5) * TILE_SIZE;
+ rect.first.left = (this1.second + 0.5) * TILE_SIZE;
+ this2.first++;
+ this1.second++;
+ move = 3;
+ rect.first.width = 0.5 * TILE_SIZE;
+ rect.first.height = TILE_SIZE;
+ } else if (map[this2.first][this2.second].getTileNumber() == 4) {
+ std::cout << "!5!" << std::endl;
+ rect.second = UP;
+ rect.first.top = (this1.first + 1) * TILE_SIZE;
+ rect.first.left = (this1.second + 0.5) * TILE_SIZE;
+ tmpRoadRect.road.push_back(rect);
+ this2.first++;
+ this2.second--;
+ move = 4;
+ rect.first.width = 0.5 * TILE_SIZE;
+ rect.first.height = TILE_SIZE;
+ } else {
+ std::cout << "!6!" << std::endl;
+ rect.first.height += TILE_SIZE;
+ this1.first--;
+ this2.first--;
+ }
+ break;
+
+ case 3:
+ if (map[this1.first][this1.second].getTileNumber() == 4) {
+ std::cout << "!7!" << std::endl;
+ rect.second = RIGHT;
+ tmpRoadRect.road.push_back(rect);
+ this1.first++;
+ this1.second--;
+ rect.first.left = (this1.second + 0.5) * TILE_SIZE;
+ rect.first.top = (this1.first - 0.5) * TILE_SIZE;
+ move = 1;
+ rect.first.width = TILE_SIZE;
+ rect.first.height = 0.5 * TILE_SIZE;
+ } else if (map[this2.first][this2.second].getTileNumber() == 19) {
+ std::cout << "!8!" << std::endl;
+ rect.second = RIGHT;
+ tmpRoadRect.road.push_back(rect);
+ this1.second--;
+ this2.first--;
+ move = 2;
+ rect.first.width = TILE_SIZE;
+ rect.first.height = 0.5 * TILE_SIZE;
+ } else {
+ std::cout << "!9!" << std::endl;
+ rect.first.width += TILE_SIZE;
+ this1.second++;
+ this2.second++;
+ }
+ break;
+ case 4:
+ if (map[this1.first][this1.second].getTileNumber() == 3) {
+ std::cout << "!10!" << std::endl;
+ rect.first.top = (this1.first + 0.5) * TILE_SIZE;
+ rect.first.left = (this1.second + 1) * TILE_SIZE;
+ rect.second = LEFT;
+ tmpRoadRect.road.push_back(rect);
+ rect.first.top = (this1.first + 0.5) * TILE_SIZE;
+ rect.first.left = (this1.second + 0.5) * TILE_SIZE;
+ this1.first++;
+ this2.second++;
+ move = 1;
+ rect.first.width = TILE_SIZE;
+ rect.first.height = 0.5 * TILE_SIZE;
+ } else if (map[this2.first][this2.second].getTileNumber() == 18) {
+ std::cout << "!11!" << std::endl;
+ rect.first.top = (this1.first + 0.5) * TILE_SIZE;
+ rect.first.left = (this1.second + 1) * TILE_SIZE;
+ rect.second = LEFT;
+ tmpRoadRect.road.push_back(rect);
+ this2.second++;
+ this2.first--;
+ move = 2;
+ rect.first.width = TILE_SIZE;
+ rect.first.height = 0.5 * TILE_SIZE;
+ } else {
+ std::cout << "!12!" << std::endl;
+ rect.first.width += TILE_SIZE;
+ this1.second--;
+ this2.second--;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (move == 1 || move == 3) {
+ if (move == 1) {
+ rect.second = DOWN;
+ } else if (move == 3) {
+ rect.second = RIGHT;
+ }
+ tmpRoadRect.finish.top = (this1.first) * TILE_SIZE;
+ tmpRoadRect.finish.left = (this1.second + 0.5) * TILE_SIZE;
+ tmpRoadRect.finish.height = TILE_SIZE;
+ tmpRoadRect.finish.width = TILE_SIZE;
+ tmpRoadRect.road.push_back(rect);
+ } else if (move == 2) {
+ tmpRoadRect.finish.top = (this1.first) * TILE_SIZE;
+ tmpRoadRect.finish.left = (this1.second + 0.5) * TILE_SIZE;
+ tmpRoadRect.finish.height = TILE_SIZE;
+ tmpRoadRect.finish.width = TILE_SIZE;
+ rect.second = UP;
+ rect.first.top = (this1.first + 1) * TILE_SIZE;
+ rect.first.left = (this1.second + 0.5) * TILE_SIZE;
+ tmpRoadRect.road.push_back(rect);
+ } else if (move == 4) {
+ rect.second = LEFT;
+ tmpRoadRect.finish.top = (this1.first + 0.5) * TILE_SIZE;
+ tmpRoadRect.finish.left = (this1.second) * TILE_SIZE;
+ tmpRoadRect.finish.height = TILE_SIZE;
+ tmpRoadRect.finish.width = TILE_SIZE;
+ rect.first.top = (this1.first + 0.5) * TILE_SIZE;
+ rect.first.left = (this1.second + 0.5) * TILE_SIZE;
+ tmpRoadRect.road.push_back(rect);
+ }
+ std::cout << tmpRoadRect.start.x << " !! " << tmpRoadRect.start.y;
+ roadRect.push_back(tmpRoadRect);
+ }
+}
+
+void Map::draw() {
+ for (auto row : map) {
+ for(auto tile : row) {
+ window.draw(tile);
+ }
+ }
+
+// for (auto roadRects : roadRect) {
+// for (auto roads : roadRects.road) {
+// sf::RectangleShape r(sf::Vector2f(roads.first.width, roads.first.height));
+// r.setPosition(roads.first.left, roads.first.top);
+// r.setOutlineColor(sf::Color::Black);
+// r.setOutlineThickness(0.5);
+// if (roads.second == UP) {
+// r.setFillColor(sf::Color::Red);
+// } else if (roads.second == DOWN) {
+// r.setFillColor(sf::Color::Green);
+// } else if (roads.second == LEFT) {
+// r.setFillColor(sf::Color::Blue);
+// } else if (roads.second == RIGHT) {
+// r.setFillColor(sf::Color::White);
+// }
+//
+// //sf::Rect r(i.left, i.top, i.width, i.height);
+// window.draw(r);
+// }
+// sf::RectangleShape f(sf::Vector2f(roadRects.finish.width, roadRects.finish.height));
+// f.setPosition(roadRects.finish.left, roadRects.finish.top);
+// f.setFillColor(sf::Color::Black);
+// window.draw(f);
+// }
+
+}
+
+ void Map::getRoadRect(std::vector& road) const {
+ road = roadRect;
+}
diff --git a/src/Map.h b/src/Map.h
new file mode 100644
index 0000000..362d20a
--- /dev/null
+++ b/src/Map.h
@@ -0,0 +1,56 @@
+//
+// Created by Falcon on 20.04.2018.
+//
+
+#ifndef TOWERDEFENSE_MAP_H
+#define TOWERDEFENSE_MAP_H
+
+#include
+
+#include
+#include
+
+#include "Constants.h"
+#include "Tile.h"
+
+class Map {
+public:
+ Map(sf::RenderWindow &window);
+ void draw();
+ void analyze(std::vector& towers1, std::vector& towers2);
+
+
+ enum Direction {
+ UP,
+ DOWN,
+ LEFT,
+ RIGHT
+ };
+
+ struct LogicMap {
+ std::vector> road;
+ sf::FloatRect finish;
+ sf::Vector2f start;
+ };
+
+private:
+
+ std::vector roadRect;
+public:
+ void getRoadRect(std::vector&) const;
+
+private:
+ sf::RenderWindow &window;
+ sf::Texture texture;
+ std::vector> map;
+ int count;
+ int width;
+ int height;
+ std::vector> start;
+ std::vector t1;
+ std::vector t2;
+
+};
+
+
+#endif //TOWERDEFENSE_MAP_H
diff --git a/src/MenuState.cpp b/src/MenuState.cpp
index e08842a..baade04 100644
--- a/src/MenuState.cpp
+++ b/src/MenuState.cpp
@@ -1 +1,72 @@
#include "MenuState.h"
+#include "Graphics/Button.h"
+#include "Game.h"
+#include "Constants.h"
+
+MenuState::MenuState(StateManager &stack, States::Context context): State(stack, context) {
+ mapSprite.setTileNumber(16);
+ texture.loadFromFile("Resources/map1.png");
+ texture.setSmooth(true);
+ sf::IntRect rect{ TILE_SIZE * (16 % 15), TILE_SIZE * (16 / 15), TILE_SIZE, TILE_SIZE };
+ mapSprite.setTexture(texture, rect);
+
+ name.setFont(context.fontHolder->get(Fonts::font1));
+ name.setPosition({static_cast(470),
+ static_cast(150)});
+ name.setScale(2.f, 2.f);
+ name.setString("DATTACK");
+ logo.setTexture(context.textureHolder->get(Textures::logo));
+ logo.setPosition(270.f, -20.f);
+ logo.setScale(1.f / 2, 1.f / 2);
+ initButtons();
+}
+
+bool MenuState::handleEvent(const sf::Event &event) {
+ container.handleWidgetsEvent(event);
+ return false;
+}
+
+void MenuState::initButtons() {
+ sf::Sprite buttonSprite;
+ sf::Texture buttonTexture = getContext().textureHolder->get(Textures::button);
+ sf::IntRect rect{ 0, 0, 618, 185};
+ //buttonSprite.setTextureRect(rect);
+ //buttonSprite.setTexture(buttonTexture);
+ //buttonSprite.setPosition(100.f, 100.f);
+ //getContext().window->draw(buttonSprite);
+ sf::RenderWindow& window = *getContext().window;
+ auto play = std::make_shared();
+ play->setTexture(getContext().textureHolder->get(Textures::button));
+ play->setTextureRect(rect);
+ play->setPosition({static_cast(window.getSize().x / 3 - 100),
+ static_cast(window.getSize().y / 2)});
+ //play->setScale(1.0f, 1.0f);
+ play->setFont(getContext().fontHolder->get(Fonts::font1));
+ play->setText("Play");
+ play->setInd(0);
+ play->setCallback([this](int ind) {
+ popState();
+ pushState(States::ID::ConnectGame);
+ });
+
+ container.addWidget(play);
+}
+
+
+bool MenuState::update(sf::Time dt) {
+
+}
+
+void MenuState::draw() {
+ getContext().window->clear(sf::Color(0, 165, 80, 0));
+ for (int i = 0; i < 20; i++)
+ for (int j = 0; j < 20; j++)
+ {
+ mapSprite.setPosition(static_cast(j * TILE_SIZE), static_cast(i * TILE_SIZE));
+ getContext().window->draw(mapSprite);
+ }
+
+ //getContext().window->draw(name);
+ getContext().window->draw(container);
+ getContext().window->draw(logo);
+}
\ No newline at end of file
diff --git a/src/MenuState.h b/src/MenuState.h
index dd2b457..bb0aa09 100644
--- a/src/MenuState.h
+++ b/src/MenuState.h
@@ -1,9 +1,26 @@
#ifndef TOWERDEFENSE_MENUSTATE_H
#define TOWERDEFENSE_MENUSTATE_H
+#include "Graphics/Gui.h"
+#include "State.h"
+#include "Tile.h"
-class MenuState {
+class MenuState : public State {
+public:
+ explicit MenuState(StateManager& stack, States::Context context);
+ bool handleEvent(const sf::Event& event) override ;
+ bool update(sf::Time dt) override;
+ void draw() override;
+
+ void initButtons();
+private:
+ sf::Texture texture;
+ Tile mapSprite;
+
+ gui::Gui container;
+ sf::Text name;
+ sf::Sprite logo;
};
diff --git a/src/Multiplayer/ConnectionFacade/AbstractConnectionFacade.cpp b/src/Multiplayer/ConnectionFacade/AbstractConnectionFacade.cpp
new file mode 100644
index 0000000..5e1e19e
--- /dev/null
+++ b/src/Multiplayer/ConnectionFacade/AbstractConnectionFacade.cpp
@@ -0,0 +1,7 @@
+//
+// Created by silvman on 16.05.18.
+//
+
+#include "AbstractConnectionFacade.h"
+
+mp::AbstractConnectionFacade::~AbstractConnectionFacade() { }
\ No newline at end of file
diff --git a/src/Multiplayer/ConnectionFacade/AbstractConnectionFacade.h b/src/Multiplayer/ConnectionFacade/AbstractConnectionFacade.h
new file mode 100644
index 0000000..494e82e
--- /dev/null
+++ b/src/Multiplayer/ConnectionFacade/AbstractConnectionFacade.h
@@ -0,0 +1,25 @@
+//
+// Created by silvman on 16.05.18.
+//
+
+#ifndef SERVER_ABSTRACTCONNECTIONFACADE_H
+#define SERVER_ABSTRACTCONNECTIONFACADE_H
+
+
+#include "../Entities/Event.h"
+
+namespace mp {
+ class AbstractConnectionFacade {
+ public:
+ virtual void connect() = 0;
+ virtual bool hasNewData() = 0;
+ virtual bool isConnected() = 0;
+ virtual void getData(std::vector &to) = 0;
+ virtual void sendData(std::vector& from) = 0;
+
+ virtual ~AbstractConnectionFacade();
+ };
+}
+
+
+#endif //SERVER_ABSTRACTCONNECTIONFACADE_H
diff --git a/src/Multiplayer/ConnectionFacade/ClientConnectionFacade.cpp b/src/Multiplayer/ConnectionFacade/ClientConnectionFacade.cpp
new file mode 100644
index 0000000..ddef2ab
--- /dev/null
+++ b/src/Multiplayer/ConnectionFacade/ClientConnectionFacade.cpp
@@ -0,0 +1,62 @@
+//
+// Created by silvman on 16.05.18.
+//
+
+#include
+#include "ClientConnectionFacade.h"
+#include "../../GameConstants.h"
+
+bool mp::ClientConnectionFacade::hasNewData() {
+ if(selector_.wait(sf::milliseconds(GameConstants::instance().cSELECTOR_WAIT_TIME())))
+ return selector_.isReady(socket_);
+
+ return false;
+}
+
+void mp::ClientConnectionFacade::getData(std::vector &to) {
+ sf::Packet packet;
+ if (socket_.receive(packet) == sf::Socket::Done) {
+ // парсинг пакета на отдельные эвенты
+ std::string data = (char *)packet.getData();
+ parseEventString(data, to);
+
+ if (GameConstants::instance().cDEBUG_MODE()) for (auto &&event : to)
+ std::cout << "[get event] " << event.type << " " << event.value << std::endl;
+
+ } else {
+ throw std::logic_error(msg::error_accepting_events);
+ }
+}
+
+void mp::ClientConnectionFacade::sendData(std::vector &from) {
+ sf::Packet packet;
+ std::string message;
+ encodeEventsToString(message, from);
+
+ if (GameConstants::instance().cDEBUG_MODE()) for (auto &&event : from) {
+ std::cout << "[out event] " << event.type << " " << event.value << std::endl;
+ }
+
+ std::cout << message << std::endl;
+ packet.append(message.c_str(), message.size() + 1);
+
+ if (socket_.send(packet) == sf::Socket::Done) {
+ from.clear();
+ } else {
+ throw std::logic_error(msg::error_sending_events);
+ }
+}
+
+void mp::ClientConnectionFacade::connect() {
+ std::cout << msg::waiting_connection << std::endl;
+ if (socket_.connect(GameConstants::instance().cIP_ADDR_SERVER(),
+ (unsigned short)GameConstants::instance().cCONNECTION_PORT()) == sf::Socket::Status::Done) {
+ connected_ = true;
+ selector_.add(socket_);
+ std::cout << msg::connected << std::endl;
+ }
+}
+
+bool mp::ClientConnectionFacade::isConnected() {
+ return connected_;
+}
\ No newline at end of file
diff --git a/src/Multiplayer/ConnectionFacade/ClientConnectionFacade.h b/src/Multiplayer/ConnectionFacade/ClientConnectionFacade.h
new file mode 100644
index 0000000..f584ac7
--- /dev/null
+++ b/src/Multiplayer/ConnectionFacade/ClientConnectionFacade.h
@@ -0,0 +1,40 @@
+//
+// Created by silvman on 16.05.18.
+//
+
+#ifndef SERVER_CLIENTCONNECTIONFACADE_H
+#define SERVER_CLIENTCONNECTIONFACADE_H
+
+#include "AbstractConnectionFacade.h"
+
+namespace mp {
+ class ClientConnectionFacade : public AbstractConnectionFacade {
+ private:
+ struct msg {
+ static constexpr const char *waiting_connection = "[client:process] connecting to server";
+ static constexpr const char *error_sending_events = "[client:fail] server didn't accept events";
+ static constexpr const char *error_accepting_events = "[client:fail] can't accept events";
+ static constexpr const char *connected = "[client:success] connected to server";
+ };
+
+ sf::TcpSocket socket_;
+ sf::SocketSelector selector_;
+ bool connected_ = false;
+
+ public:
+ void connect() override;
+ bool hasNewData() override;
+ bool isConnected() override;
+
+ /*
+ * Эти два метода кидаются исключениями std::logic_error в случаях,
+ * когда с соединением что-то не так
+ */
+ void getData(std::vector &to) override;
+ void sendData(std::vector &from) override;
+
+ };
+}
+
+
+#endif //SERVER_CLIENTCONNECTIONFACADE_H
diff --git a/src/Multiplayer/ConnectionFacade/ServerConnectionFacade.cpp b/src/Multiplayer/ConnectionFacade/ServerConnectionFacade.cpp
new file mode 100644
index 0000000..423b3e3
--- /dev/null
+++ b/src/Multiplayer/ConnectionFacade/ServerConnectionFacade.cpp
@@ -0,0 +1,74 @@
+//
+// Created by silvman on 16.05.18.
+//
+
+#include "ServerConnectionFacade.h"
+#include "../../GameConstants.h"
+
+bool mp::ServerConnectionFacade::hasNewData() {
+ if (selector_.wait(sf::milliseconds(GameConstants::instance().cSELECTOR_WAIT_TIME())))
+ return first_.hasNewData(selector_) || second_.hasNewData(selector_);
+
+ return false;
+}
+
+void mp::ServerConnectionFacade::getData(std::vector &to) {
+ if (first_.hasNewData(selector_)) {
+ try {
+ first_.getEvents();
+ to.insert(to.end(), first_.from_client.begin(), first_.from_client.end()); // сращиваем 2 вектора
+ first_.from_client.clear(); // очищаем после получения данных
+ } catch (const std::exception &e) {
+ selector_.remove(first_.getSocket());
+ }
+ }
+
+ if (second_.hasNewData(selector_)) {
+ try {
+ second_.getEvents();
+ to.insert(to.end(), second_.from_client.begin(), second_.from_client.end()); // сращиваем 2 вектора
+ second_.from_client.clear(); // очищаем после получения данных
+ } catch (const std::exception &e) {
+ selector_.remove(second_.getSocket());
+ }
+ }
+}
+
+void mp::ServerConnectionFacade::sendData(std::vector &from) {
+ for (auto &&event : from) {
+ switch (event.id) {
+ case 1: {
+ second_.to_send.push_back(event);
+ break;
+ }
+
+ case 2: {
+ first_.to_send.push_back(event);
+ break;
+ }
+
+ case 0: { // broadcasting
+ second_.to_send.push_back(event);
+ first_.to_send.push_back(event);
+
+ break;
+ }
+
+ default:
+ break;
+ }
+ }
+
+ first_.sendEvents();
+ second_.sendEvents();
+
+ from.clear(); // TODO нужна проверка на отправленность
+}
+
+void mp::ServerConnectionFacade::connect() {
+ // does nothing as the connection comes from the master process
+}
+
+bool mp::ServerConnectionFacade::isConnected() {
+ return first_.isAvailable() && second_.isAvailable(); // грубая проверка подключения с обоими игроками
+}
diff --git a/src/Multiplayer/ConnectionFacade/ServerConnectionFacade.h b/src/Multiplayer/ConnectionFacade/ServerConnectionFacade.h
new file mode 100644
index 0000000..26ea856
--- /dev/null
+++ b/src/Multiplayer/ConnectionFacade/ServerConnectionFacade.h
@@ -0,0 +1,34 @@
+//
+// Created by silvman on 16.05.18.
+//
+
+#ifndef SERVER_SERVERCONNECTIONFACADE_H
+#define SERVER_SERVERCONNECTIONFACADE_H
+
+#include "../Entities/Player.h"
+#include "AbstractConnectionFacade.h"
+
+namespace mp {
+ class ServerConnectionFacade : public AbstractConnectionFacade {
+ private:
+ mp::player& first_;
+ mp::player& second_;
+ sf::SocketSelector selector_;
+
+ public:
+ explicit ServerConnectionFacade(mp::player &first, mp::player &second) : first_(first), second_(second) {
+ selector_.add(first_.getSocket());
+ selector_.add(second_.getSocket());
+ };
+
+ bool isConnected() override;
+ void connect() override;
+ bool hasNewData() override;
+ void getData(std::vector &to) override;
+ void sendData(std::vector &from) override;
+ };
+}
+
+
+
+#endif //SERVER_SERVERCONNECTIONFACADE_H
diff --git a/src/Multiplayer/Entities/Entity.cpp b/src/Multiplayer/Entities/Entity.cpp
new file mode 100644
index 0000000..c547a9b
--- /dev/null
+++ b/src/Multiplayer/Entities/Entity.cpp
@@ -0,0 +1,15 @@
+//
+// Created by silvman on 16.05.18.
+//
+
+#include "Entity.h"
+
+int mp::entity::getId() const {
+ return id;
+}
+
+void mp::entity::setId(int id) {
+ entity::id = id;
+}
+
+mp::entity::entity(int id): id(id) { }
diff --git a/src/Multiplayer/Entities/Entity.h b/src/Multiplayer/Entities/Entity.h
new file mode 100644
index 0000000..6dd7739
--- /dev/null
+++ b/src/Multiplayer/Entities/Entity.h
@@ -0,0 +1,24 @@
+//
+// Created by silvman on 16.05.18.
+//
+
+#ifndef SERVER_ENTITY_H
+#define SERVER_ENTITY_H
+
+namespace mp {
+ class entity {
+ protected:
+ int id;
+
+ public:
+ explicit entity(int id = 0);
+ virtual ~entity() = default;
+
+ int getId() const;
+ void setId(int id);
+ };
+
+}
+
+
+#endif //SERVER_ENTITY_H
diff --git a/src/Multiplayer/Entities/Event.cpp b/src/Multiplayer/Entities/Event.cpp
new file mode 100644
index 0000000..a51b97a
--- /dev/null
+++ b/src/Multiplayer/Entities/Event.cpp
@@ -0,0 +1,75 @@
+//
+// Created by silvman on 16.05.18.
+//
+
+#include "Event.h"
+
+mp::Event::Event(int id, char type, const std::string &value, sf::Time time) :
+ id(id),
+ type(type),
+ value(value),
+ time(time) { }
+
+mp::Event::Event(const std::string &sId, const std::string &sType, const std::string &value, const std::string &sTime) :
+ id(0),
+ type('\0'),
+ value(value),
+ time()
+{
+ id = atoi(sId.c_str());
+ type = sType[0];
+
+ unsigned long long temp_time = 0;
+ for (auto &&digit : sTime) {
+ temp_time *= 10;
+ temp_time += digit - '0';
+ }
+
+ time = sf::microseconds(temp_time);
+}
+
+void mp::parseEventString(const std::string &sEvents, std::vector &vEvents) {
+ auto iterator = sEvents.begin();
+
+ std::string str_num_events;
+ for (; *iterator != ' '; ++iterator)
+ str_num_events += *iterator;
+ iterator++;
+
+ int num_events = atoi(str_num_events.c_str());
+
+ for (int i = 0; i < num_events; ++i) {
+ std::string sId;
+ std::string sType;
+ std::string sValue;
+ std::string sTime;
+
+ for (; *iterator != ' '; ++iterator)
+ sId += *iterator;
+ ++iterator;
+
+ for (; *iterator != ' '; ++iterator)
+ sType += *iterator;
+ ++iterator;
+
+ for (; *iterator != ' '; ++iterator)
+ sValue += *iterator;
+ ++iterator;
+
+ for (; *iterator != ' ' && iterator != sEvents.end(); ++iterator)
+ sTime += *iterator;
+ ++iterator;
+
+ vEvents.emplace_back(sId, sType, sValue, sTime);
+ }
+
+}
+
+void mp::encodeEventsToString(std::string &sEvents, std::vector &vEvents) {
+ sEvents.append(std::to_string(vEvents.size()) + " ");
+
+ // сборка сообщения, включающего все эвенты
+ for (auto &&e : vEvents)
+ sEvents.append(std::to_string(e.id) + " " + e.type + " " + e.value + " " + std::to_string(e.time.asMicroseconds()) + " ");
+
+}
\ No newline at end of file
diff --git a/src/Multiplayer/Entities/Event.h b/src/Multiplayer/Entities/Event.h
new file mode 100644
index 0000000..b16fab0
--- /dev/null
+++ b/src/Multiplayer/Entities/Event.h
@@ -0,0 +1,26 @@
+//
+// Created by silvman on 16.05.18.
+//
+
+#ifndef SERVER_EVENT_H
+#define SERVER_EVENT_H
+
+#include
+
+namespace mp {
+ struct Event {
+ int id;
+ char type;
+ std::string value;
+ sf::Time time;
+
+ Event(int id, char type, const std::string &value, sf::Time time);
+ Event(const std::string &sId, const std::string &sType, const std::string &value, const std::string &sTime);
+ };
+
+ void parseEventString(const std::string& sEvents, std::vector& vEvents);
+ void encodeEventsToString(std::string& sEvents, std::vector& vEvents);
+}
+
+
+#endif //SERVER_EVENT_H
diff --git a/src/Multiplayer/Entities/Game.cpp b/src/Multiplayer/Entities/Game.cpp
new file mode 100644
index 0000000..670a894
--- /dev/null
+++ b/src/Multiplayer/Entities/Game.cpp
@@ -0,0 +1,51 @@
+//
+// Created by silvman on 16.05.18.
+//
+
+#include "Game.h"
+
+bool mp::game::isReady() const {
+ return (first_connected_ && second_connected_);
+}
+
+void mp::game::join(int player_id) {
+ if (is_started_)
+ throw std::logic_error(msg::game_running);
+
+ if (!first_connected_) {
+ player_id_first_ = player_id;
+ first_connected_ = true;
+ } else if (!second_connected_) {
+ player_id_second_ = player_id;
+ second_connected_ = true;
+ }
+}
+
+const std::string &mp::game::getName() const {
+ return name_;
+}
+
+mp::game::game(const std::string &name) :
+ name_(name),
+ is_started_(false),
+ first_connected_(false),
+ second_connected_(false),
+ player_id_second_(0),
+ player_id_first_(0)
+{ }
+
+bool mp::game::isStarted() const {
+ return is_started_;
+}
+
+void mp::game::start() {
+ is_started_ = true;
+}
+
+int mp::game::getFirstId() const {
+ return player_id_first_;
+}
+
+int mp::game::getSecondId() const {
+ return player_id_second_;
+}
\ No newline at end of file
diff --git a/src/Multiplayer/Entities/Game.h b/src/Multiplayer/Entities/Game.h
new file mode 100644
index 0000000..990b0c3
--- /dev/null
+++ b/src/Multiplayer/Entities/Game.h
@@ -0,0 +1,44 @@
+//
+// Created by silvman on 16.05.18.
+//
+
+#ifndef SERVER_GAME_H
+#define SERVER_GAME_H
+
+#include "Entity.h"
+#include
+
+namespace mp {
+ class game : public entity {
+ private:
+ struct msg {
+ static constexpr const char *game_running = "[game:fail] game already running" ;
+ };
+
+ std::string name_;
+ int player_id_first_;
+ int player_id_second_;
+
+ bool first_connected_;
+ bool second_connected_;
+
+ bool is_started_;
+
+ public:
+ explicit game(const std::string& name);
+
+ bool isReady() const;
+ void join(int player_id);
+ const std::string& getName() const;
+
+ int getFirstId() const;
+
+ int getSecondId() const;
+
+
+ bool isStarted() const;
+ void start();
+ };
+}
+
+#endif //SERVER_GAME_H
diff --git a/src/Multiplayer/Entities/Player.cpp b/src/Multiplayer/Entities/Player.cpp
new file mode 100644
index 0000000..5eb3641
--- /dev/null
+++ b/src/Multiplayer/Entities/Player.cpp
@@ -0,0 +1,103 @@
+//
+// Created by silvman on 16.05.18.
+//
+
+#include
+#include "Player.h"
+
+mp::player::player(int id)
+ : entity(id), state_(notConnected) { }
+
+
+void mp::player::disconnect() {
+ state_ = notConnected;
+}
+
+mp::player::~player() {
+ socket_.disconnect();
+}
+
+bool mp::player::isAvailable() const {
+ return state_ != notAvailable;
+}
+
+void mp::player::getEvents() try {
+ sf::Packet packet;
+ if (socket_.receive(packet) == sf::Socket::Done) {
+ std::cout << msg::get_events << id << std::endl;
+ std::string data = (char *)packet.getData();
+
+ parseEventString(data, from_client);
+ } else {
+ throw std::logic_error(msg::not_get_events);
+ }
+} catch (const std::exception& e) {
+ state_ = notAvailable;
+ throw;
+}
+
+void mp::player::startGame() {
+ to_send.emplace_back(0, 'j', std::to_string(id), sf::microseconds(0));
+ sendEvents();
+}
+
+
+void mp::player::connect(sf::TcpListener &listener, sf::SocketSelector &selector) try {
+ if (listener.accept(socket_) == sf::Socket::Done) {
+ selector.add(socket_);
+ state_ = connected; // помечает, что подключено
+
+ std::cout << msg::connect_player << id << std::endl;
+
+ } else {
+ throw std::logic_error(msg::not_connect_player);
+ }
+} catch (const std::exception& e) {
+ state_ = notAvailable;
+ throw;
+}
+
+bool mp::player::hasNewData(sf::SocketSelector &selector) {
+ return selector.isReady(socket_);
+}
+
+void mp::player::sendEvents() try {
+ if (to_send.empty())
+ return;
+
+ sf::Packet packet;
+
+ std::string sEvents;
+ encodeEventsToString(sEvents, to_send);
+
+ packet.append(sEvents.c_str(), sEvents.size() + 1);
+ if (socket_.send(packet) == sf::Socket::Done) { // блокирующий вызов, может стать причиной медленной пересылки эвентов
+ for (auto &&send : to_send) {
+ std::cout << send.id << " " << send.value << std::endl;
+ }
+ to_send.clear();
+ std::cout << msg::send_events << id << std::endl;
+ } else {
+ throw std::logic_error(msg::not_send_events + id);
+ }
+
+} catch (const std::exception& e) {
+ std::cout << e.what() << std::endl;
+ state_ = notAvailable;
+}
+
+bool mp::player::isConnected() const {
+ return state_ == connected;
+}
+
+sf::TcpSocket &mp::player::getSocket() {
+ return socket_;
+}
+
+bool mp::player::isInGame() const {
+ return in_game_;
+}
+
+void mp::player::setInGame() {
+ in_game_ = true;
+}
\ No newline at end of file
diff --git a/src/Multiplayer/Entities/Player.h b/src/Multiplayer/Entities/Player.h
new file mode 100644
index 0000000..1833ab5
--- /dev/null
+++ b/src/Multiplayer/Entities/Player.h
@@ -0,0 +1,73 @@
+//
+// Created by silvman on 16.05.18.
+//
+
+#ifndef SERVER_PLAYER_H
+#define SERVER_PLAYER_H
+
+#include
+#include "Entity.h"
+#include "Event.h"
+
+namespace mp {
+ class player : public entity {
+ public:
+ enum connection_state {
+ notConnected = 0,
+ connected,
+ notAvailable
+ };
+
+ explicit player(int id = 0);
+ ~player() override;
+
+ sf::TcpSocket& getSocket();
+
+
+ void getEvents();
+ void sendEvents();
+// void resendEvents(player& to_who);
+
+ // вызывается у первого игрока для уведомления о начале игры
+ bool hasNewData(sf::SocketSelector &selector);
+
+ void disconnect();
+
+ void connect(sf::TcpListener &listener, sf::SocketSelector &selector);
+
+ void startGame();
+
+ bool isAvailable() const;
+ bool isConnected() const;
+
+ bool isInGame() const;
+ void setInGame();
+
+
+ std::vector from_client;
+ std::vector to_send;
+
+
+ private:
+ struct msg {
+ static constexpr const char *get_events = "[player:success] get events from ";
+ static constexpr const char *not_get_events = "[player:error] can't recieve events";
+ static constexpr const char *send_id = "[player:success] send id to ";
+ static constexpr const char *not_send_id = "[player:error] send id to";
+ static constexpr const char *connect_player = "[player:success] connected player " ;
+ static constexpr const char *not_connect_player = "[player:error] didn't connect player" ;
+ static constexpr const char *send_events = "[player:success] send events to " ;
+ static constexpr const char *not_send_events = "[player:error] can't send events to " ;
+ };
+
+ sf::TcpSocket socket_;
+ connection_state state_;
+ bool in_game_;
+ };
+
+}
+
+
+
+
+#endif //SERVER_PLAYER_H
diff --git a/src/Multiplayer/Manager/Manager.cpp b/src/Multiplayer/Manager/Manager.cpp
new file mode 100644
index 0000000..67206fd
--- /dev/null
+++ b/src/Multiplayer/Manager/Manager.cpp
@@ -0,0 +1,6 @@
+//
+// Created by silvman on 16.05.18.
+//
+
+#include "Manager.h"
+
diff --git a/src/Multiplayer/Manager/Manager.h b/src/Multiplayer/Manager/Manager.h
new file mode 100644
index 0000000..e7af9ae
--- /dev/null
+++ b/src/Multiplayer/Manager/Manager.h
@@ -0,0 +1,24 @@
+//
+// Created by silvman on 16.05.18.
+//
+
+#ifndef SERVER_MANAGER_H
+#define SERVER_MANAGER_H
+
+#include
+
+namespace mp {
+ template
+ class manager {
+ protected:
+ std::list entities;
+
+ public:
+ virtual std::list &getEntities();
+
+ virtual T &get_by_id(int id) = 0;
+ virtual void remove(int id) = 0;
+ };
+}
+
+#endif //SERVER_MANAGER_H
diff --git a/src/Multiplayer/Manager/PlayerManager.cpp b/src/Multiplayer/Manager/PlayerManager.cpp
new file mode 100644
index 0000000..c84bc8e
--- /dev/null
+++ b/src/Multiplayer/Manager/PlayerManager.cpp
@@ -0,0 +1,39 @@
+//
+// Created by silvman on 16.05.18.
+//
+
+#include "PlayerManager.h"
+
+mp::player_manager::player_manager(): manager(), next_id(1) { }
+
+mp::player &mp::player_manager::get_by_id(int id) {
+ for (auto &&player : entities)
+ if (player.getId() == id)
+ return player;
+
+ throw std::logic_error("[player_manager::get_by_id] id not found");
+}
+
+void mp::player_manager::remove(int id) {
+ for (auto it = entities.begin(); it != entities.end(); ++it)
+ if (it->getId() == id) {
+ entities.erase(it);
+ return;;
+ }
+
+ throw std::logic_error("[player_manager::remove] id not found");
+}
+
+mp::player_manager::~player_manager() {
+ for (auto &&item : entities) {
+ // TODO нужно ли
+ item.disconnect(); // устанавливает флаг отключенности
+ }
+}
+
+mp::player &mp::player_manager::create() {
+ entities.emplace_back(next_id);
+ next_id++;
+
+ return entities.back();
+}
\ No newline at end of file
diff --git a/src/Multiplayer/Manager/PlayerManager.h b/src/Multiplayer/Manager/PlayerManager.h
new file mode 100644
index 0000000..47651e2
--- /dev/null
+++ b/src/Multiplayer/Manager/PlayerManager.h
@@ -0,0 +1,34 @@
+//
+// Created by silvman on 16.05.18.
+//
+
+#ifndef SERVER_PLAYERMANAGER_H
+#define SERVER_PLAYERMANAGER_H
+
+#include "Manager.h"
+#include "../Entities/Player.h"
+
+namespace mp {
+ class player_manager: public manager {
+ private:
+ int next_id;
+
+ public:
+ player_manager();
+ ~player_manager();
+
+ player& get_by_id(int id) override;
+ // void add(player &&entity) override;
+ player& create();
+ void remove(int id) override;
+ };
+
+ template
+ std::list& mp::manager::getEntities() {
+ return entities;
+ }
+
+}
+
+
+#endif //SERVER_PLAYERMANAGER_H
diff --git a/src/Multiplayer/Master.cpp b/src/Multiplayer/Master.cpp
new file mode 100644
index 0000000..a69b023
--- /dev/null
+++ b/src/Multiplayer/Master.cpp
@@ -0,0 +1,124 @@
+//
+// Created by silvman on 16.05.18.
+//
+
+#include
+#include "Master.h"
+#include "Worker.h"
+#include "../GameConstants.h"
+
+mp::master::master(unsigned short port): running_(true) {
+ if (listener_.listen(port) != sf::Socket::Status::Done) {
+ running_ = false;
+ };
+ selector_.add(listener_);
+}
+
+mp::master::~master() {
+ listener_.close(); // TODO Нужно?
+}
+
+void mp::master::work() {
+ std::cout << msg::run << std::endl;
+ while (running_) try {
+ if (selector_.wait(sf::milliseconds(GameConstants::instance().cSELECTOR_WAIT_TIME()))) {
+ if (selector_.isReady(listener_)) { // подключение нового игрока
+ player& new_player = pool_players_.create(); // добавление игрока в список
+
+ try {
+ new_player.connect(listener_, selector_);
+ } catch (const std::exception& e) {
+ // если ошибка при подключении
+ std::cout << e.what();
+ pool_players_.remove(new_player.getId());
+ }
+
+ } else {
+ for (auto &&player : pool_players_.getEntities()) {
+ if (!player.isInGame() && selector_.isReady(player.getSocket())) {
+ try {
+ player.getEvents();
+ } catch (const std::exception& e) {
+ // сюда попадаем при проблемах с подключением игрока. Пока что просто удаляем его, в дальнейшем можно было бы обработать
+ std::cout << e.what() << std::endl;
+ selector_.remove(player.getSocket());
+ }
+
+ // обрабатываем создание новых игр и подключение к ним
+ proceedEvents(player);
+ player.from_client.clear();
+ }
+ }
+ }
+ } else {
+ for (auto &&game : pool_games_) {
+ if (game.isReady() && !game.isStarted()) {
+ startWorker(game);
+ }
+ }
+ }
+ } catch (const std::exception& e) {
+ std::cout << e.what() << std::endl;
+ }
+
+// wait();
+}
+
+void mp::master::proceedEvents(player &player) {
+ for (auto &&event : player.from_client) {
+ if (event.type == 'j') {
+ int pending_game_id = atoi(event.value.c_str());
+
+ try {
+ pool_games_.at(pending_game_id).join(player.getId());
+ } catch (const std::exception& e) {
+ std::cout << e.what() << std::endl;
+ break;
+ }
+
+ player.setInGame();
+ std::cout << msg::join << player.getId() << " " << pending_game_id << std::endl;
+
+ // TODO подключение по именам
+ } else if (event.type == 'n') {
+ pool_games_.emplace_back(event.value); // name - имя игры
+
+ player.to_send.emplace_back(0, 'n', std::to_string(pool_games_.size() - 1),
+ sf::microseconds(0));
+
+ std::cout << msg::add_game << event.value << std::endl;
+
+ player.sendEvents();
+ }
+ }
+
+}
+
+void mp::master::startWorker(mp::game &game) {
+ pid_t pid = fork();
+
+ switch (pid) {
+ case 0: {
+ game.start();
+ selector_.remove(pool_players_.get_by_id(game.getFirstId()).getSocket());
+ selector_.remove(pool_players_.get_by_id(game.getSecondId()).getSocket());
+ std::cout << msg::success << pid << std::endl;
+ break;
+ } // возможно, действия, связанные с обеспечением безопасности игры
+
+ case -1: {
+ std::cout << msg::error << std::endl;
+ break;
+ }
+
+ default: {
+ running_ = false; // worker не должен продолжать цикл master
+
+ worker worker(pool_players_.get_by_id(game.getFirstId()), pool_players_.get_by_id(game.getSecondId()), pid);
+ worker.work();
+
+ return;
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/src/Multiplayer/Master.h b/src/Multiplayer/Master.h
new file mode 100644
index 0000000..a2734a7
--- /dev/null
+++ b/src/Multiplayer/Master.h
@@ -0,0 +1,42 @@
+//
+// Created by silvman on 16.05.18.
+//
+
+#ifndef SERVER_MASTER_H
+#define SERVER_MASTER_H
+
+#include
+#include "Entities/Game.h"
+#include "Manager/PlayerManager.h"
+
+namespace mp {
+ class master { // TODO singleton?
+ private:
+ struct msg {
+ static constexpr const char *run = "[master:run]";
+ static constexpr const char *join = "[master:success] player join'd game ";
+ static constexpr const char *add_game = "[master:success] add game ";
+ static constexpr const char *success = "[master:success] ";
+ static constexpr const char *error = "[master:error] fork failed";
+ static constexpr const char *end = "[master:end]";
+ };
+
+ sf::TcpListener listener_;
+ sf::SocketSelector selector_;
+ std::vector pool_games_;
+ player_manager pool_players_;
+ bool running_;
+
+ void proceedEvents(player &player);
+ void startWorker(game& game);
+
+ public:
+ explicit master(unsigned short port = 55001);
+ ~master();
+
+ void work();
+ };
+}
+
+
+#endif //SERVER_MASTER_H
diff --git a/src/Multiplayer/MultiplayerFacade/AbstractMultiplayerFacade.cpp b/src/Multiplayer/MultiplayerFacade/AbstractMultiplayerFacade.cpp
new file mode 100644
index 0000000..c3e58c5
--- /dev/null
+++ b/src/Multiplayer/MultiplayerFacade/AbstractMultiplayerFacade.cpp
@@ -0,0 +1,7 @@
+//
+// Created by silvman on 16.05.18.
+//
+
+#include "AbstractMultiplayerFacade.h"
+
+mp::AbstractMultiplayerFacade::~AbstractMultiplayerFacade() { }
\ No newline at end of file
diff --git a/src/Multiplayer/MultiplayerFacade/AbstractMultiplayerFacade.h b/src/Multiplayer/MultiplayerFacade/AbstractMultiplayerFacade.h
new file mode 100644
index 0000000..35b843f
--- /dev/null
+++ b/src/Multiplayer/MultiplayerFacade/AbstractMultiplayerFacade.h
@@ -0,0 +1,31 @@
+//
+// Created by silvman on 16.05.18.
+//
+
+#ifndef SERVER_MULTIPLAYERFACADE_H
+#define SERVER_MULTIPLAYERFACADE_H
+
+#include "../ConnectionFacade/AbstractConnectionFacade.h"
+
+namespace mp {
+ class AbstractMultiplayerFacade {
+ protected:
+ std::unique_ptr connection;
+
+ public:
+ virtual ~AbstractMultiplayerFacade();
+
+ virtual bool isConnected() = 0;
+ virtual void connect() = 0;
+
+ virtual bool askEvents() = 0;
+ virtual bool sendEvents() = 0;
+
+ std::vector incoming{};
+ std::vector outcoming{};
+ };
+}
+
+
+
+#endif //SERVER_MULTIPLAYERFACADE_H
diff --git a/src/Multiplayer/MultiplayerFacade/ClientMultiplayerFacade.cpp b/src/Multiplayer/MultiplayerFacade/ClientMultiplayerFacade.cpp
new file mode 100644
index 0000000..f7e51ee
--- /dev/null
+++ b/src/Multiplayer/MultiplayerFacade/ClientMultiplayerFacade.cpp
@@ -0,0 +1,42 @@
+//
+// Created by silvman on 16.05.18.
+//
+
+#include
+#include "ClientMultiplayerFacade.h"
+#include "../ConnectionFacade/ClientConnectionFacade.h"
+
+bool mp::ClientMultiplayerFacade::askEvents() {
+ if (connection->hasNewData()) try {
+ connection->getData(incoming);
+ return true;
+ } catch (const std::exception& e) {
+ std::cout << e.what() << std::endl;
+ }
+
+ return false;
+}
+
+bool mp::ClientMultiplayerFacade::sendEvents() {
+ if (!outcoming.empty()) try {
+ connection->sendData(outcoming);
+ return true;
+ } catch (const std::exception& e) {
+ std::cout << e.what() << std::endl;
+ }
+
+ return false;
+}
+
+void mp::ClientMultiplayerFacade::connect() {
+ connection->connect();
+
+}
+
+bool mp::ClientMultiplayerFacade::isConnected() {
+ return connection->isConnected();
+}
+
+mp::ClientMultiplayerFacade::ClientMultiplayerFacade() {
+ connection = std::unique_ptr(new ClientConnectionFacade);
+}
diff --git a/src/Multiplayer/MultiplayerFacade/ClientMultiplayerFacade.h b/src/Multiplayer/MultiplayerFacade/ClientMultiplayerFacade.h
new file mode 100644
index 0000000..f92f482
--- /dev/null
+++ b/src/Multiplayer/MultiplayerFacade/ClientMultiplayerFacade.h
@@ -0,0 +1,25 @@
+//
+// Created by silvman on 16.05.18.
+//
+
+#ifndef SERVER_CLIENTMULTIPLAYERFACADE_H
+#define SERVER_CLIENTMULTIPLAYERFACADE_H
+
+#include "AbstractMultiplayerFacade.h"
+
+namespace mp {
+ class ClientMultiplayerFacade : public AbstractMultiplayerFacade {
+ public:
+ ClientMultiplayerFacade();
+
+ bool isConnected() override;
+ void connect() override ;
+
+ bool askEvents() override;
+ bool sendEvents() override;
+ };
+}
+
+
+
+#endif //SERVER_CLIENTMULTIPLAYERFACADE_H
diff --git a/src/Multiplayer/MultiplayerFacade/ServerMultiplayerFacade.cpp b/src/Multiplayer/MultiplayerFacade/ServerMultiplayerFacade.cpp
new file mode 100644
index 0000000..4243ddf
--- /dev/null
+++ b/src/Multiplayer/MultiplayerFacade/ServerMultiplayerFacade.cpp
@@ -0,0 +1,42 @@
+//
+// Created by silvman on 16.05.18.
+//
+
+#include
+#include "ServerMultiplayerFacade.h"
+#include "../ConnectionFacade/ServerConnectionFacade.h"
+
+mp::ServerMultiplayerFacade::ServerMultiplayerFacade(mp::player &first, mp::player &second) {
+ connection = std::unique_ptr(new mp::ServerConnectionFacade(first, second));
+}
+
+bool mp::ServerMultiplayerFacade::askEvents() {
+ if (connection->hasNewData()) try {
+ connection->getData(incoming);
+ return true;
+ } catch (const std::exception& e) {
+ std::cout << e.what() << std::endl;
+ }
+
+ return false;
+}
+
+bool mp::ServerMultiplayerFacade::sendEvents() {
+ if (!outcoming.empty()) try {
+ connection->sendData(outcoming);
+ return true;
+ } catch (const std::exception& e) {
+ std::cout << e.what() << std::endl;
+ }
+
+ return false;
+}
+
+void mp::ServerMultiplayerFacade::connect() {
+ connection->connect();
+}
+
+bool mp::ServerMultiplayerFacade::isConnected() {
+ return connection->isConnected();
+}
+
diff --git a/src/Multiplayer/MultiplayerFacade/ServerMultiplayerFacade.h b/src/Multiplayer/MultiplayerFacade/ServerMultiplayerFacade.h
new file mode 100644
index 0000000..0253e36
--- /dev/null
+++ b/src/Multiplayer/MultiplayerFacade/ServerMultiplayerFacade.h
@@ -0,0 +1,27 @@
+//
+// Created by silvman on 16.05.18.
+//
+
+#ifndef SERVER_SERVERMULTIPLAYERFACADE_H
+#define SERVER_SERVERMULTIPLAYERFACADE_H
+
+#include "AbstractMultiplayerFacade.h"
+#include "../Entities/Player.h"
+
+namespace mp {
+ class ServerMultiplayerFacade : public AbstractMultiplayerFacade {
+ public:
+ ServerMultiplayerFacade(mp::player& first, mp::player& second);
+
+ bool isConnected() override;
+ void connect() override ;
+
+ bool askEvents() override;
+ bool sendEvents() override;
+
+ };
+}
+
+
+
+#endif //SERVER_SERVERMULTIPLAYERFACADE_H
diff --git a/src/Multiplayer/Worker.cpp b/src/Multiplayer/Worker.cpp
new file mode 100644
index 0000000..e150343
--- /dev/null
+++ b/src/Multiplayer/Worker.cpp
@@ -0,0 +1,31 @@
+//
+// Created by silvman on 16.05.18.
+//
+
+#include
+#include "Worker.h"
+
+mp::worker::worker(player &first, player &second, pid_t pid)
+ : first_(first), second_(second), pid_(pid), game_(first, second) {
+ std::cout << msg::success << pid << std::endl;
+
+ first_.setId(1);
+ second_.setId(2);
+}
+
+void mp::worker::work() {
+ std::cout << msg::run << pid_ << std::endl;
+
+ // Отсылаем сообщения о начале игры (включает в себя айдишники)
+ try {
+ first_.startGame();
+ second_.startGame();
+ } catch (const std::exception& e) {
+ std::cout << e.what() << std::endl;
+ return;
+ }
+
+ game_.server_run(false);
+
+ std::cout << msg::end << pid_ << std::endl;
+}
\ No newline at end of file
diff --git a/src/Multiplayer/Worker.h b/src/Multiplayer/Worker.h
new file mode 100644
index 0000000..43a2f0a
--- /dev/null
+++ b/src/Multiplayer/Worker.h
@@ -0,0 +1,32 @@
+//
+// Created by silvman on 16.05.18.
+//
+
+#ifndef SERVER_WORKER_H
+#define SERVER_WORKER_H
+
+#include "../Game.h"
+#include "Entities/Player.h"
+
+namespace mp {
+ class worker {
+ struct msg {
+ static constexpr const char *success = "[worker:success] ";
+ static constexpr const char *run = "[worker:run] ";
+ static constexpr const char *end = "[worker:end] ";
+ };
+
+ pid_t pid_;
+
+ player & first_;
+ player & second_;
+ Game game_;
+
+ public:
+ worker(player &first, player &second, pid_t pid);
+
+ void work();
+ };
+}
+
+#endif //SERVER_WORKER_H
diff --git a/src/MultiplayerGameState.cpp b/src/MultiplayerGameState.cpp
new file mode 100644
index 0000000..bf54c76
--- /dev/null
+++ b/src/MultiplayerGameState.cpp
@@ -0,0 +1,5 @@
+//
+// Created by Falcon on 02.05.2018.
+//
+
+#include "MultiplayerGameState.h"
diff --git a/src/MultiplayerGameState.h b/src/MultiplayerGameState.h
new file mode 100644
index 0000000..d9b5374
--- /dev/null
+++ b/src/MultiplayerGameState.h
@@ -0,0 +1,36 @@
+#include
+
+#include "ResourceManager/ResourcesHolder.h"
+#include "ResourceManager/ResourcesIdentifier.h"
+
+#include "State.h"
+#include "Graphics/Gui.h"
+#include "Map.h"
+#include "Units/Warrior/Warrior.h"
+#include "Units/UnitsGraphics/GraphicsUnit.h"
+
+class Tower;
+class Bullet;
+
+class GameState : public State {
+public:
+ explicit GameState(StateManager& stack, States::Context context);
+ ~GameState() = default;
+
+ bool handleEvent(const sf::Event &event) override;
+ bool update(sf::Time dt) override;
+ void draw() override;
+
+private:
+ Player::GameData player1;
+ Player::GameData player2;
+ gui::Gui containter;
+ Map map;
+ std::vector roadRect;
+ std::vector warriors;
+ GraphicsUnit graphicsUnit;
+ Tower* tower;
+ std::vector bullets;
+ sf::Sprite towerSprite;
+ sf::Sprite bulletSprite;
+};
\ No newline at end of file
diff --git a/src/ResourceManager/ResourcesHolder.h b/src/ResourceManager/ResourcesHolder.h
index ddd7149..2afbd0b 100644
--- a/src/ResourceManager/ResourcesHolder.h
+++ b/src/ResourceManager/ResourcesHolder.h
@@ -44,4 +44,4 @@ void ResourceHolder::insert(Identifier id, std::unique_ptr
resourceMap.insert(std::make_pair(id, std::move(resource)));
}
-#endif //TOWERDEFENSE_RESOURCESHOLDER_H
+#endif //TOWERDEFENSE_RESOURCESHOLDER_H
\ No newline at end of file
diff --git a/src/ResourceManager/ResourcesIdentifier.h b/src/ResourceManager/ResourcesIdentifier.h
index 5d3181c..8d6334f 100644
--- a/src/ResourceManager/ResourcesIdentifier.h
+++ b/src/ResourceManager/ResourcesIdentifier.h
@@ -8,6 +8,58 @@ namespace sf {
namespace Textures {
enum id {
+ cursor = 0,
+ panel,
+ button,
+ map,
+ target,
+ towerZeroRed,
+ towerZeroBlue,
+ towerOneBase,
+ towerOneTop,
+ towerTwoBase,
+ towerTwoTop,
+ towerThreeBase,
+ towerThreeTop,
+ warriorOne,
+ warriorTwo,
+ warriorIconOne,
+ warriorIconTwo,
+ addWarriorOne,
+ addWarriorTwo,
+ addBarraks,
+ addWeapons,
+ addFarm,
+ blood,
+ warriorExplosion,
+ bulletOne,
+ bulletTwo,
+ bulletThree,
+ explosionOne,
+ explosionTwo,
+ explosionThree,
+ gold,
+ star,
+ lives,
+ pauseOn,
+ pauseOff,
+ forwardOn,
+ forwardOff,
+ fastForwardOn,
+ fastForwardOff,
+ fight,
+ play,
+ audioOff,
+ audioOn,
+ musicOff,
+ musicOn,
+ exit,
+ castle1,
+ castle2,
+ farm,
+ weapons,
+ barraks,
+ logo,
};
}
diff --git a/src/State.cpp b/src/State.cpp
index ba1fa11..c373ae3 100644
--- a/src/State.cpp
+++ b/src/State.cpp
@@ -18,6 +18,6 @@ void State::clearStates() {
stack.clearStates();
}
-States::Context State::getContext() const {
+States::Context& State::getContext() {
return context;
}
\ No newline at end of file
diff --git a/src/State.h b/src/State.h
index f217213..62ed5cc 100644
--- a/src/State.h
+++ b/src/State.h
@@ -25,7 +25,7 @@ class State : private sf::NonCopyable {
void popState();
void clearStates();
- States::Context getContext() const;
+ States::Context& getContext() ;
private:
StateManager &stack;
diff --git a/src/StateManager.cpp b/src/StateManager.cpp
index b80384c..71d0764 100644
--- a/src/StateManager.cpp
+++ b/src/StateManager.cpp
@@ -1,6 +1,7 @@
#include "StateManager.h"
#include
+#include
StateManager::StateManager(States::Context context)
: context(context)
diff --git a/src/Tile.cpp b/src/Tile.cpp
new file mode 100644
index 0000000..e682189
--- /dev/null
+++ b/src/Tile.cpp
@@ -0,0 +1,32 @@
+//
+// Created by Falcon on 21.04.2018.
+//
+
+#include "Tile.h"
+
+Tile::Tile()
+ : state(Tile::Type::None)
+{}
+
+
+void Tile::setTexture(const sf::Texture &texture, sf::IntRect rect)
+{
+ sprite.setTexture(texture);
+ sprite.setTextureRect(rect);
+}
+
+void Tile::setTileNumber(int number)
+{
+ tileNumber = number;
+}
+
+const int Tile::getTileNumber() const
+{
+ return tileNumber;
+}
+
+void Tile::draw(sf::RenderTarget &target, sf::RenderStates states) const
+{
+ states.transform *= getTransform();
+ target.draw(sprite, states);
+}
\ No newline at end of file
diff --git a/src/Tile.h b/src/Tile.h
new file mode 100644
index 0000000..1ee0791
--- /dev/null
+++ b/src/Tile.h
@@ -0,0 +1,38 @@
+//
+// Created by Falcon on 21.04.2018.
+//
+
+#ifndef TOWERDEFENSE_TILE_H
+#define TOWERDEFENSE_TILE_H
+
+#include
+
+class Tile : public sf::Drawable, public sf::Transformable
+{
+public:
+ enum class Type
+ {
+ None = 0,
+ Invalid,
+ Valid
+ };
+
+ Tile();
+
+ //void setState(Type state);
+ void setTexture(const sf::Texture &texture, sf::IntRect rect);
+ void setTileNumber(int number);
+
+ //const Type getState() const;
+ const int getTileNumber() const;
+
+private:
+ void draw(sf::RenderTarget &target, sf::RenderStates states) const override;
+
+ int tileNumber;
+ Type state;
+ sf::Sprite sprite;
+ sf::Vector2i position;
+};
+
+#endif //TOWERDEFENSE_TILE_H
diff --git a/src/Units/Bullet/Bullet.cpp b/src/Units/Bullet/Bullet.cpp
new file mode 100644
index 0000000..34327f4
--- /dev/null
+++ b/src/Units/Bullet/Bullet.cpp
@@ -0,0 +1,57 @@
+#include
+#include "Bullet.h"
+#include
+
+Bullet::Bullet(Type type, const sf::Vector2f& position, const std::shared_ptr& target, int damage, float velocity,
+ float angle)
+ : GameUnit(type, position),
+ target_(target),
+ damage_(damage),
+ velocity_(velocity),
+ angle_(angle),
+ exploded_(false),
+ disappeared_(false) {
+}
+
+void Bullet::update(const sf::Time& dTime) {
+ if (target_ == nullptr) {
+ disappeared_ = true;
+ return;
+ }
+ if (target_->isFinished() || !target_->isAlive()) {
+ disappeared_ = true;
+ target_.reset();
+ return;
+ }
+ if (!checkCollisionWithTarget()) {
+ angle_ = std::atan2((target_->getPosition().x - position_.x), (target_->getPosition().y - position_.y));
+ position_.x += velocity_ * dTime.asSeconds() * std::sin(angle_);
+ position_.y += velocity_ * dTime.asSeconds() * std::cos(angle_);
+ } else {
+ exploded_ = true;
+ damage();
+ target_.reset();
+ }
+}
+
+bool Bullet::checkCollisionWithTarget() {
+ float area = 10;
+ return (position_.x < target_->getPosition().x + area && position_.x > target_->getPosition().x - area)
+ && (position_.y < target_->getPosition().y + area && position_.y > target_->getPosition().y - area);
+}
+
+void Bullet::damage() {
+ target_->suffer(damage_);
+}
+
+float Bullet::getAngle() const {
+ return angle_;
+}
+
+bool Bullet::isExploded() const {
+ return exploded_;
+}
+
+bool Bullet::isDisappeared() const {
+ return disappeared_;
+}
\ No newline at end of file
diff --git a/src/Units/Bullet/Bullet.h b/src/Units/Bullet/Bullet.h
new file mode 100644
index 0000000..886d1c6
--- /dev/null
+++ b/src/Units/Bullet/Bullet.h
@@ -0,0 +1,34 @@
+#ifndef TOWERDEFENSE_BULLET_H
+#define TOWERDEFENSE_BULLET_H
+
+
+#include "../GameUnit.h"
+#include "../Warrior/Warrior.h"
+#include "../../GameConstants.h"
+
+class Bullet: public GameUnit {
+public:
+
+ void update(const sf::Time& dTime) override;
+
+ float getAngle() const;
+
+ bool isExploded() const;
+ bool isDisappeared() const;
+
+protected:
+ Bullet(Type type, const sf::Vector2f& position, const std::shared_ptr& target, int damage, float velocity, float angle);
+ virtual void damage();
+
+ bool checkCollisionWithTarget();
+
+ std::shared_ptr target_;
+ int damage_;
+ float velocity_;
+ float angle_;
+ bool exploded_;
+ bool disappeared_;
+};
+
+
+#endif //TOWERDEFENSE_BULLET_H
diff --git a/src/Units/Bullet/BulletLvlOne.cpp b/src/Units/Bullet/BulletLvlOne.cpp
new file mode 100644
index 0000000..9f7af08
--- /dev/null
+++ b/src/Units/Bullet/BulletLvlOne.cpp
@@ -0,0 +1,5 @@
+#include "BulletLvlOne.h"
+
+BulletLvlOne::BulletLvlOne(const sf::Vector2f &position, float angle,const std::shared_ptr& target)
+ : Bullet(Type::lvlOne, position, target, GameConstants::instance().cBULLET_1_DAMAGE(),
+ GameConstants::instance().cBULLET_1_VELOCITY(), angle) {}
diff --git a/src/Units/Bullet/BulletLvlOne.h b/src/Units/Bullet/BulletLvlOne.h
new file mode 100644
index 0000000..9a18ef6
--- /dev/null
+++ b/src/Units/Bullet/BulletLvlOne.h
@@ -0,0 +1,13 @@
+#ifndef TOWERDEFENSE_BULLETLVLONE_H
+#define TOWERDEFENSE_BULLETLVLONE_H
+
+
+#include "Bullet.h"
+
+class BulletLvlOne: public Bullet {
+public:
+ BulletLvlOne(const sf::Vector2f& position, float angle, const std::shared_ptr& target);
+};
+
+
+#endif //TOWERDEFENSE_BULLETLVLONE_H
diff --git a/src/Units/Bullet/BulletLvlThree.cpp b/src/Units/Bullet/BulletLvlThree.cpp
new file mode 100644
index 0000000..770e15c
--- /dev/null
+++ b/src/Units/Bullet/BulletLvlThree.cpp
@@ -0,0 +1,21 @@
+#include "BulletLvlThree.h"
+
+BulletLvlThree::BulletLvlThree(const sf::Vector2f &position, float angle, const std::shared_ptr& target,
+ std::list> &warriors)
+ : Bullet(Type::lvlThree, position, target, GameConstants::instance().cBULLET_3_DAMAGE(),
+ GameConstants::instance().cBULLET_3_VELOCITY(), angle),
+ warriors_(warriors),
+ rangeAOE_(GameConstants::instance().cBULLET_3_AOE()) {}
+
+void BulletLvlThree::damage() {
+ for (const auto& warrior: warriors_) {
+ if (warrior != nullptr && inRange(warrior->getPosition()) && warrior->isAlive()) {
+ warrior->suffer(damage_);
+ }
+ }
+}
+
+bool BulletLvlThree::inRange(const sf::Vector2f& pointPosition) {
+ return (pointPosition.x - position_.x) * (pointPosition.x - position_.x)
+ + (pointPosition.y - position_.y) * (pointPosition.y - position_.y) <= rangeAOE_ * rangeAOE_;
+}
\ No newline at end of file
diff --git a/src/Units/Bullet/BulletLvlThree.h b/src/Units/Bullet/BulletLvlThree.h
new file mode 100644
index 0000000..a758a69
--- /dev/null
+++ b/src/Units/Bullet/BulletLvlThree.h
@@ -0,0 +1,23 @@
+#ifndef SERVER_BULLETLVLTHREE_H
+#define SERVER_BULLETLVLTHREE_H
+
+
+#include "Bullet.h"
+#include
+
+class BulletLvlThree: public Bullet {
+public:
+ BulletLvlThree(const sf::Vector2f& position, float angle, const std::shared_ptr& target, std::list>& warriors);
+
+ void damage() override;
+
+private:
+ bool inRange(const sf::Vector2f& pointPosition);
+
+ std::list>& warriors_;
+ float rangeAOE_;
+};
+
+
+
+#endif //SERVER_BULLETLVLTHREE_H
diff --git a/src/Units/Bullet/BulletLvlTwo.cpp b/src/Units/Bullet/BulletLvlTwo.cpp
new file mode 100644
index 0000000..073df8e
--- /dev/null
+++ b/src/Units/Bullet/BulletLvlTwo.cpp
@@ -0,0 +1,6 @@
+#include "BulletLvlTwo.h"
+
+BulletLvlTwo::BulletLvlTwo(const sf::Vector2f &position, float angle, const std::shared_ptr& target)
+ : Bullet(Type::lvlTwo, position, target, GameConstants::instance().cBULLET_2_DAMAGE(),
+ GameConstants::instance().cBULLET_2_VELOCITY(), angle) {}
+
diff --git a/src/Units/Bullet/BulletLvlTwo.h b/src/Units/Bullet/BulletLvlTwo.h
new file mode 100644
index 0000000..45ad86b
--- /dev/null
+++ b/src/Units/Bullet/BulletLvlTwo.h
@@ -0,0 +1,13 @@
+#ifndef TOWERDEFENSE_BULLETLVLTWO_H
+#define TOWERDEFENSE_BULLETLVLTWO_H
+
+
+#include "Bullet.h"
+
+class BulletLvlTwo: public Bullet {
+public:
+ BulletLvlTwo(const sf::Vector2f& position, float angle, const std::shared_ptr& target);
+};
+
+
+#endif //TOWERDEFENSE_BULLETLVLTWO_H
\ No newline at end of file
diff --git a/src/Units/GameUnit.cpp b/src/Units/GameUnit.cpp
new file mode 100644
index 0000000..e1d08ee
--- /dev/null
+++ b/src/Units/GameUnit.cpp
@@ -0,0 +1,13 @@
+#include "GameUnit.h"
+
+GameUnit::GameUnit(Type type, const sf::Vector2f &position)
+ : type_(type),
+ position_(position) {}
+
+Type GameUnit::getType() const {
+ return type_;
+}
+
+const sf::Vector2f &GameUnit::getPosition() const {
+ return position_;
+}
diff --git a/src/Units/GameUnit.h b/src/Units/GameUnit.h
new file mode 100644
index 0000000..1d2ac76
--- /dev/null
+++ b/src/Units/GameUnit.h
@@ -0,0 +1,26 @@
+#ifndef TOWERDEFENSE_GAMEUNIT_H
+#define TOWERDEFENSE_GAMEUNIT_H
+
+
+#include
+#include
+#include "../GameContext.h"
+
+class GameUnit {
+public:
+ virtual ~GameUnit() = default;
+
+ virtual void update(const sf::Time& dTime) = 0;
+
+ Type getType() const;
+ const sf::Vector2f& getPosition() const;
+
+protected:
+ GameUnit(Type type, const sf::Vector2f& position);
+
+ Type type_;
+ sf::Vector2f position_;
+};
+
+
+#endif //TOWERDEFENSE_GAMEUNIT_H
diff --git a/src/Units/LogicUnitsManager.cpp b/src/Units/LogicUnitsManager.cpp
new file mode 100644
index 0000000..a956292
--- /dev/null
+++ b/src/Units/LogicUnitsManager.cpp
@@ -0,0 +1,42 @@
+#include "LogicUnitsManager.h"
+#include "../Castle/Castle.h"
+#include "Bullet/Bullet.h"
+
+LogicUnitsManager::LogicUnitsManager()
+ : player1_(std::make_shared()),
+ player2_(std::make_shared()) {
+ std::cout << "LComponentConstructor" << std::endl;
+ player1_->setEnemy(player2_);
+ player2_->setEnemy(player1_);
+}
+
+void LogicUnitsManager::update(const sf::Time& dTime) {
+ player1_->updateCastle(dTime);
+ player2_->updateCastle(dTime);
+
+ updateBullets(dTime);
+}
+
+void LogicUnitsManager::updateBullets(const sf::Time& dTime) {
+ for (auto bullet = bullets_.begin(); bullet != bullets_.end();) {
+ (*bullet)->update(dTime);
+ if (*bullet == nullptr || (*bullet)->isExploded() || (*bullet)->isDisappeared()) {
+ bullet = bullets_.erase(bullet);
+ } else {
+ ++bullet;
+ }
+ }
+}
+
+std::shared_ptr &LogicUnitsManager::getPlayer1() {
+ return player1_;
+}
+
+std::shared_ptr &LogicUnitsManager::getPlayer2() {
+ return player2_;
+}
+
+std::vector> &LogicUnitsManager::getBullets() {
+ return bullets_;
+}
+
diff --git a/src/Units/LogicUnitsManager.h b/src/Units/LogicUnitsManager.h
new file mode 100644
index 0000000..b3fbdc7
--- /dev/null
+++ b/src/Units/LogicUnitsManager.h
@@ -0,0 +1,30 @@
+#ifndef SERVER_LOGICUNITSMANAGER_H
+#define SERVER_LOGICUNITSMANAGER_H
+
+#include
+#include
+#include
+
+class Castle;
+class Bullet;
+
+class LogicUnitsManager {
+public:
+ explicit LogicUnitsManager();
+
+ void update(const sf::Time& dTime);
+
+ std::shared_ptr& getPlayer1();
+ std::shared_ptr& getPlayer2();
+ std::vector>& getBullets();
+
+private:
+ void updateBullets(const sf::Time& dTime);
+
+ std::shared_ptr player1_;
+ std::shared_ptr player2_;
+ std::vector> bullets_;
+};
+
+
+#endif //SERVER_LOGICUNITSMANAGER_H
diff --git a/src/Units/Tower/Tower.cpp b/src/Units/Tower/Tower.cpp
new file mode 100644
index 0000000..b197f83
--- /dev/null
+++ b/src/Units/Tower/Tower.cpp
@@ -0,0 +1,84 @@
+#include
+#include
+#include "Tower.h"
+#include "../Warrior/Warrior.h"
+#include "TowerLvlOne.h"
+#include "TowerLvlTwo.h"
+#include "TowerLvlThree.h"
+
+#define RAD_IN_DEGREE (180 / M_PI)
+#define COOLDOWN 10
+
+Tower::Tower(Type type, const sf::Vector2f& position, int price, float attackRange, float attackCooldown,
+ std::list>& warriors, std::vector>& bullets)
+ : GameUnit(type, position),
+ price_(price),
+ angle_(0),
+ attackRange_(attackRange),
+ attackCooldown_(attackCooldown / COOLDOWN),
+ warriors_(warriors),
+ bullets_(bullets),
+ target_(nullptr),
+ cooldown_(0) {}
+
+void Tower::update(const sf::Time& dTime) {
+ if (target_ != nullptr) {
+ if (inRange(target_->getPosition()) && target_->isAlive() && !target_->isFinished()) {
+ angle_ = aim();
+ shoot(dTime);
+ } else {
+ target_.reset();
+ }
+ } else {
+ for (const auto& warrior : warriors_) {
+ if (warrior != nullptr && inRange(warrior->getPosition()) && warrior->isAlive() && !warrior->isFinished()) {
+ target_ = warrior;
+ break;
+ }
+ }
+ }
+}
+
+int Tower::getPrice() {
+ return price_;
+}
+
+bool Tower::inRange(const sf::Vector2f& pointPosition) const {
+ return (pointPosition.x - position_.x) * (pointPosition.x - position_.x)
+ + (pointPosition.y - position_.y) * (pointPosition.y - position_.y) <= attackRange_ * attackRange_;
+}
+
+float Tower::aim() const {
+ return static_cast((std::atan2((position_.y - target_->getPosition().y),
+ (position_.x - target_->getPosition().x)) * RAD_IN_DEGREE) - 90);
+}
+
+void Tower::shoot(const sf::Time &dTime) {
+ cooldown_ -= dTime.asSeconds();
+ if (cooldown_ < 0) {
+ cooldown_ = attackCooldown_;
+ bullets_.emplace_back(makeBullet());
+ }
+}
+
+float Tower::getAngle() const {
+ return angle_;
+}
+
+int Tower::upgrade(std::shared_ptr& tower) {
+ int price = tower->getPrice();
+ switch (tower->type_) {
+ case Type ::lvlZero:
+ tower.reset(new TowerLvlOne(tower->position_, tower->warriors_, tower->bullets_));
+ break;
+ case Type::lvlOne:
+ tower.reset(new TowerLvlTwo(tower->position_, tower->warriors_, tower->bullets_));
+ break;
+ case Type::lvlTwo:
+ tower.reset(new TowerLvlThree(tower->position_, tower->warriors_, tower->bullets_));
+ break;
+ default:
+ return 0;
+ }
+ return price;
+}
\ No newline at end of file
diff --git a/src/Units/Tower/Tower.h b/src/Units/Tower/Tower.h
new file mode 100644
index 0000000..74e7025
--- /dev/null
+++ b/src/Units/Tower/Tower.h
@@ -0,0 +1,44 @@
+#ifndef TOWERDEFENSE_TOWER_H
+#define TOWERDEFENSE_TOWER_H
+
+#include
+#include
+#include
+#include "../GameUnit.h"
+#include "../../GameConstants.h"
+
+class Warrior;
+class Bullet;
+
+class Tower: public GameUnit {
+public:
+
+ void update(const sf::Time& dTime) override;
+ static int upgrade(std::shared_ptr& tower);
+ float getAngle() const;
+ int getPrice();
+
+ GameConstants& gameConst = GameConstants::instance();
+
+protected:
+ Tower(Type type, const sf::Vector2f& position, int price, float attackRange, float attackCooldown,
+ std::list>& warriors, std::vector>& bullets);
+
+
+ bool inRange(const sf::Vector2f& pointPosition) const;
+ float aim() const;
+ void shoot(const sf::Time& dTime);
+ virtual std::shared_ptr makeBullet() = 0;
+
+ int price_;
+ float angle_;
+ float attackRange_;
+ float cooldown_;
+ float attackCooldown_;
+ std::shared_ptr target_;
+ std::list>& warriors_;
+ std::vector>& bullets_;
+};
+
+
+#endif //TOWERDEFENSE_TOWER_H
\ No newline at end of file
diff --git a/src/Units/Tower/TowerLvlOne.cpp b/src/Units/Tower/TowerLvlOne.cpp
new file mode 100644
index 0000000..505e885
--- /dev/null
+++ b/src/Units/Tower/TowerLvlOne.cpp
@@ -0,0 +1,13 @@
+#include "TowerLvlOne.h"
+#include "../Bullet/BulletLvlOne.h"
+
+TowerLvlOne::TowerLvlOne(const sf::Vector2f& position, std::list>& warriors,
+ std::vector>& bullets)
+ : Tower(Type::lvlOne, position, GameConstants::instance().cTOWER_1_UP_COST(),
+ GameConstants::instance().cTOWER_1_RANGE(), GameConstants::instance().cTOWER_1_COOLDOWN(),
+ warriors, bullets) {}
+
+std::shared_ptr TowerLvlOne::makeBullet() {
+ double radAngle = angle_ * M_PI / 180 - M_PI / 2;
+ return std::make_shared(position_ + sf::Vector2f(20 * cos(radAngle), 20 * sin(radAngle)), angle_, target_);
+}
\ No newline at end of file
diff --git a/src/Units/Tower/TowerLvlOne.h b/src/Units/Tower/TowerLvlOne.h
new file mode 100644
index 0000000..8a5b22f
--- /dev/null
+++ b/src/Units/Tower/TowerLvlOne.h
@@ -0,0 +1,16 @@
+#ifndef TOWERDEFENSE_TOWERLVLONE_H
+#define TOWERDEFENSE_TOWERLVLONE_H
+
+
+#include "Tower.h"
+#include "../../Constants.h"
+#include
+class TowerLvlOne: public Tower {
+public:
+ TowerLvlOne(const sf::Vector2f& position, std::list>& warriors, std::vector>& bullets);
+
+ std::shared_ptr makeBullet() override;
+};
+
+
+#endif //TOWERDEFENSE_TOWERLVLONE_H
\ No newline at end of file
diff --git a/src/Units/Tower/TowerLvlThree.cpp b/src/Units/Tower/TowerLvlThree.cpp
new file mode 100644
index 0000000..6ee3e12
--- /dev/null
+++ b/src/Units/Tower/TowerLvlThree.cpp
@@ -0,0 +1,13 @@
+#include "TowerLvlThree.h"
+#include "../Bullet/BulletLvlThree.h"
+
+
+TowerLvlThree::TowerLvlThree(const sf::Vector2f& position, std::list>& warriors,
+ std::vector>& bullets)
+ : Tower(Type::lvlThree, position, -1, GameConstants::instance().cTOWER_3_RANGE(),
+ GameConstants::instance().cTOWER_3_COOLDOWN(), warriors, bullets) {}
+
+std::shared_ptr TowerLvlThree::makeBullet() {
+ double radAngle = angle_ * M_PI / 180 - M_PI / 2;
+ return std::make_shared