1 /* 2 * This file is part of Dune Legacy. 3 * 4 * Dune Legacy is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation, either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * Dune Legacy is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with Dune Legacy. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 #ifndef GAME_H 19 #define GAME_H 20 21 #include <misc/Random.h> 22 #include <misc/RobustList.h> 23 #include <misc/InputStream.h> 24 #include <misc/OutputStream.h> 25 #include <ObjectData.h> 26 #include <ObjectManager.h> 27 #include <CommandManager.h> 28 #include <GameInterface.h> 29 #include <INIMap/INIMapLoader.h> 30 #include <GameInitSettings.h> 31 #include <Trigger/TriggerManager.h> 32 #include <players/Player.h> 33 #include <players/HumanPlayer.h> 34 35 #include <DataTypes.h> 36 37 #include <SDL.h> 38 #include <stdarg.h> 39 #include <string> 40 #include <map> 41 #include <utility> 42 43 // forward declarations 44 class ObjectBase; 45 class InGameMenu; 46 class MentatHelp; 47 class WaitingForOtherPlayers; 48 class ObjectManager; 49 class House; 50 class Explosion; 51 52 53 #define END_WAIT_TIME (6*1000) 54 55 #define GAME_NOTHING -1 56 #define GAME_RETURN_TO_MENU 0 57 #define GAME_NEXTMISSION 1 58 #define GAME_LOAD 2 59 #define GAME_DEBRIEFING_WIN 3 60 #define GAME_DEBRIEFING_LOST 4 61 #define GAME_CUSTOM_GAME_STATS 5 62 63 64 class Game 65 { 66 public: 67 68 /** 69 Default constructor. Call initGame() or initReplay() afterwards. 70 */ 71 Game(); 72 73 74 Game(const Game& o) = delete; 75 76 /** 77 Destructor 78 */ 79 ~Game(); 80 81 /** 82 Initializes a game with the specified settings 83 \param newGameInitSettings the game init settings to initialize the game 84 */ 85 void initGame(const GameInitSettings& newGameInitSettings); 86 87 /** 88 Initializes a replay from the specified filename 89 \param filename the file containing the replay 90 */ 91 void initReplay(const std::string& filename); 92 93 94 95 friend class INIMapLoader; // loading INI Maps is done with a INIMapLoader helper object 96 97 98 /** 99 This method processes all objects in the current game. It should be executed exactly once per game tick. 100 */ 101 void processObjects(); 102 103 /** 104 This method draws a complete frame. 105 */ 106 void drawScreen(); 107 108 /** 109 This method proccesses all the user input. 110 */ 111 void doInput(); 112 113 /** 114 Returns the current game cycle number. 115 \return the current game cycle 116 */ getGameCycleCount()117 Uint32 getGameCycleCount() const { return gameCycleCount; }; 118 119 /** 120 Return the game time in milliseconds. 121 \return the current game time in milliseconds 122 */ getGameTime()123 Uint32 getGameTime() const { return gameCycleCount * GAMESPEED_DEFAULT; }; 124 125 /** 126 Get the command manager of this game 127 \return the command manager 128 */ getCommandManager()129 CommandManager& getCommandManager() { return cmdManager; }; 130 131 /** 132 Get the trigger manager of this game 133 \return the trigger manager 134 */ getTriggerManager()135 TriggerManager& getTriggerManager() { return triggerManager; }; 136 137 /** 138 Get the explosion list. 139 \return the explosion list 140 */ getExplosionList()141 RobustList<Explosion*>& getExplosionList() { return explosionList; }; 142 143 /** 144 Returns the house with the id houseID 145 \param houseID the id of the house to return 146 \return the house with id houseID 147 */ getHouse(int houseID)148 House* getHouse(int houseID) { 149 return house[houseID]; 150 } 151 152 /** 153 The current game is finished and the local house has won 154 */ 155 void setGameWon(); 156 157 /** 158 The current game is finished and the local house has lost 159 */ 160 void setGameLost(); 161 162 /** 163 Draws the cursor. 164 */ 165 void drawCursor(); 166 167 /** 168 This method sets up the view. The start position is the center point of all owned units/structures 169 */ 170 void setupView(); 171 172 /** 173 This method loads a previously saved game. 174 \param filename the name of the file to load from 175 \return true on success, false on failure 176 */ 177 bool loadSaveGame(const std::string& filename); 178 179 /** 180 This method loads a previously saved game. 181 \param stream the stream to load from 182 \return true on success, false on failure 183 */ 184 bool loadSaveGame(InputStream& stream); 185 186 /** 187 This method saves the current running game. 188 \param filename the name of the file to save to 189 \return true on success, false on failure 190 */ 191 bool saveGame(const std::string& filename); 192 193 /** 194 This method starts the game. Will return when the game is finished or aborted. 195 */ 196 void runMainLoop(); 197 quitGame()198 inline void quitGame() { bQuitGame = true;}; 199 200 /** 201 This method pauses the current game. 202 */ pauseGame()203 void pauseGame() { 204 if(gameType != GameType::CustomMultiplayer) { 205 bPause = true; 206 } 207 } 208 209 /** 210 This method resumes the current paused game. 211 */ 212 void resumeGame(); 213 214 /** 215 This method writes out an object to a stream. 216 \param stream the stream to write to 217 \param obj the object to be saved 218 */ 219 void saveObject(OutputStream& stream, ObjectBase* obj); 220 221 /** 222 This method loads an object from the stream. 223 \param stream the stream to read from 224 \param ObjectID the object id that this unit/structure should get 225 \return the read unit/structure 226 */ 227 ObjectBase* loadObject(InputStream& stream, Uint32 objectID); 228 getObjectManager()229 inline ObjectManager& getObjectManager() { return objectManager; }; getGameInterface()230 inline GameInterface& getGameInterface() { return *pInterface; }; 231 getGameInitSettings()232 const GameInitSettings& getGameInitSettings() const { return gameInitSettings; }; setNextGameInitSettings(const GameInitSettings & nextGameInitSettings)233 void setNextGameInitSettings(const GameInitSettings& nextGameInitSettings) { this->nextGameInitSettings = nextGameInitSettings; }; 234 235 /** 236 This method should be called if whatNext() returns GAME_NEXTMISSION or GAME_LOAD. You should 237 destroy this Game and create a new one. Call Game::initGame() with the GameInitClass 238 that was returned previously by getNextGameInitSettings(). 239 \return a GameInitSettings-Object that describes the next game. 240 */ 241 GameInitSettings getNextGameInitSettings(); 242 243 /** 244 This method should be called after startGame() has returned. whatNext() will tell the caller 245 what should be done after the current game has finished.<br> 246 Possible return values are:<br> 247 GAME_RETURN_TO_MENU - the game is finished and you should return to the main menu<br> 248 GAME_NEXTMISSION - the game is finished and you should load the next mission<br> 249 GAME_LOAD - from inside the game the user requests to load a savegame and you should do this now<br> 250 GAME_DEBRIEFING_WIN - show debriefing (player has won) and call whatNext() again afterwards<br> 251 GAME_DEBRIEFING_LOST - show debriefing (player has lost) and call whatNext() again afterwards<br> 252 <br> 253 \return one of GAME_RETURN_TO_MENU, GAME_NEXTMISSION, GAME_LOAD, GAME_DEBRIEFING_WIN, GAME_DEBRIEFING_LOST 254 */ 255 int whatNext(); 256 257 /** 258 This method is the callback method for the OPTIONS button at the top of the screen. 259 It pauses the game and loads the in game menu. 260 */ 261 void onOptions(); 262 263 /** 264 This method is the callback method for the MENTAT button at the top of the screen. 265 It pauses the game and loads the mentat help screen. 266 */ 267 void onMentat(); 268 269 /** 270 This method selects all units/structures in the list aList. 271 \param aList the list containing all the units/structures to be selected 272 */ 273 void selectAll(const std::set<Uint32>& aList); 274 275 /** 276 This method unselects all units/structures in the list aList. 277 \param aList the list containing all the units/structures to be unselected 278 */ 279 void unselectAll(const std::set<Uint32>& aList); 280 281 /** 282 Returns a list of all currently selected objects. 283 \return list of currently selected units/structures 284 */ getSelectedList()285 std::set<Uint32>& getSelectedList() { return selectedList; }; 286 287 /** 288 Marks that the selection changed (and must be retransmitted to other players in multiplayer games) 289 */ selectionChanged()290 inline void selectionChanged() { 291 bSelectionChanged = true; 292 if(pInterface) { 293 pInterface->updateObjectInterface(); 294 } 295 pLocalPlayer->onSelectionChanged(selectedList); 296 }; 297 298 299 void onReceiveSelectionList(const std::string& name, const std::set<Uint32>& newSelectionList, int groupListIndex); 300 301 /** 302 Returns a list of all currently by the other player selected objects (Only in multiplayer with multiple players per house). 303 \return list of currently selected units/structures by the other player 304 */ getSelectedByOtherPlayerList()305 std::set<Uint32>& getSelectedByOtherPlayerList() { return selectedByOtherPlayerList; }; 306 307 /** 308 Called when a peer disconnects the game. 309 */ 310 void onPeerDisconnected(const std::string& name, bool bHost, int cause); 311 312 /** 313 Adds a new message to the news ticker. 314 \param text the text to add 315 */ addToNewsTicker(const std::string & text)316 void addToNewsTicker(const std::string& text) { 317 if(pInterface != nullptr) { 318 pInterface->addToNewsTicker(text); 319 } 320 } 321 322 /** 323 Adds an urgent message to the news ticker. 324 \param text the text to add 325 */ addUrgentMessageToNewsTicker(const std::string & text)326 void addUrgentMessageToNewsTicker(const std::string& text) { 327 if(pInterface != nullptr) { 328 pInterface->addUrgentMessageToNewsTicker(text); 329 } 330 } 331 332 /** 333 This method returns wether the game is currently paused 334 \return true, if paused, false otherwise 335 */ isGamePaused()336 bool isGamePaused() const { return bPause; }; 337 338 /** 339 This method returns wether the game is finished 340 \return true, if paused, false otherwise 341 */ isGameFinished()342 bool isGameFinished() const { return finished; }; 343 344 /** 345 Are cheats enabled? 346 \return true = cheats enabled, false = cheats disabled 347 */ areCheatsEnabled()348 bool areCheatsEnabled() const { return bCheatsEnabled; }; 349 350 /** 351 Returns the name of the local player; this method should be used instead of using settings.general.playerName directly 352 \return the local player name 353 */ getLocalPlayerName()354 const std::string& getLocalPlayerName() const { return localPlayerName; } 355 356 /** 357 Register a new player in this game. 358 \param player the player to register 359 */ registerPlayer(Player * player)360 void registerPlayer(Player* player) { 361 playerName2Player.insert( std::make_pair(player->getPlayername(), player) ); 362 playerID2Player.insert( std::make_pair(player->getPlayerID(), player) ); 363 } 364 365 /** 366 Unregisters the specified player 367 \param player 368 */ unregisterPlayer(Player * player)369 void unregisterPlayer(Player* player) { 370 playerID2Player.erase(player->getPlayerID()); 371 372 for(auto iter = playerName2Player.begin(); iter != playerName2Player.end(); ++iter) { 373 if(iter->second == player) { 374 playerName2Player.erase(iter); 375 break; 376 } 377 } 378 } 379 380 /** 381 Returns the first player with the given name. 382 \param playername the name of the player 383 \return the player or nullptr if none was found 384 */ getPlayerByName(const std::string & playername)385 Player* getPlayerByName(const std::string& playername) const { 386 auto iter = playerName2Player.find(playername); 387 if(iter != playerName2Player.end()) { 388 return iter->second; 389 } else { 390 return nullptr; 391 } 392 } 393 394 /** 395 Returns the player with the given id. 396 \param playerID the name of the player 397 \return the player or nullptr if none was found 398 */ getPlayerByID(Uint8 playerID)399 Player* getPlayerByID(Uint8 playerID) const { 400 auto iter = playerID2Player.find(playerID); 401 if(iter != playerID2Player.end()) { 402 return iter->second; 403 } else { 404 return nullptr; 405 } 406 } 407 408 /** 409 This function is called when the user left clicks on the radar 410 \param worldPosition position in world coordinates 411 \param bRightMouseButton true = right mouse button, false = left mouse button 412 \param bDrag true = the mouse was moved while being pressed, e.g. dragging 413 \return true if dragging should start or continue 414 */ 415 bool onRadarClick(Coord worldPosition, bool bRightMouseButton, bool bDrag); 416 417 /** 418 Take a screenshot and save it with a unique name 419 */ 420 void takeScreenshot() const; 421 422 private: 423 424 /** 425 Checks whether the cursor is on the radar view 426 \param mouseX x-coordinate of cursor 427 \param mouseY y-coordinate of cursor 428 \return true if on radar view 429 */ 430 bool isOnRadarView(int mouseX, int mouseY); 431 432 /** 433 Handles the press of one key while chatting 434 \param key the key pressed 435 */ 436 void handleChatInput(SDL_KeyboardEvent& keyboardEvent); 437 438 /** 439 Handles the press of one key 440 \param key the key pressed 441 */ 442 void handleKeyInput(SDL_KeyboardEvent& keyboardEvent); 443 444 /** 445 Performs a building placement 446 \param xPos x-coordinate in map coordinates 447 \param yPos x-coordinate in map coordinates 448 \return true if placement was successful 449 */ 450 bool handlePlacementClick(int xPos, int yPos); 451 452 /** 453 Performs a attack click for the currently selected units/structures. 454 \param xPos x-coordinate in map coordinates 455 \param yPos x-coordinate in map coordinates 456 \return true if attack is possible 457 */ 458 bool handleSelectedObjectsAttackClick(int xPos, int yPos); 459 460 /** 461 Performs a move click for the currently selected units/structures. 462 \param xPos x-coordinate in map coordinates 463 \param yPos x-coordinate in map coordinates 464 \return true if move is possible 465 */ 466 bool handleSelectedObjectsMoveClick(int xPos, int yPos); 467 468 /** 469 Performs a capture click for the currently selected units/structures. 470 \param xPos x-coordinate in map coordinates 471 \param yPos x-coordinate in map coordinates 472 \return true if capture is possible 473 */ 474 bool handleSelectedObjectsCaptureClick(int xPos, int yPos); 475 476 477 /** 478 Performs a request carryall click for the currently selected units. 479 \param xPos x-coordinate in map coordinates 480 \param yPos x-coordinate in map coordinates 481 \return true if carryall drop is possible 482 */ 483 bool handleSelectedObjectsRequestCarryallDropClick(int xPos, int yPos); 484 485 486 /** 487 Performs an action click for the currently selected units/structures. 488 \param xPos x-coordinate in map coordinates 489 \param yPos x-coordinate in map coordinates 490 \return true if action click is possible 491 */ 492 bool handleSelectedObjectsActionClick(int xPos, int yPos); 493 494 495 /** 496 Selects the next structure of any of the types specified in itemIDs. If none of this type is currently selected the first one is selected. 497 \param itemIDs the ids of the structures to select 498 */ 499 void selectNextStructureOfType(const std::set<Uint32>& itemIDs); 500 501 /** 502 Returns the game speed of this game: The number of ms per game cycle. 503 For singleplayer games this is a global setting (but can be adjusted in the in-game settings menu). For multiplayer games the game speed 504 can be set by the person creating the game. 505 \return the current game speed 506 */ 507 int getGameSpeed() const; 508 509 public: 510 enum { 511 CursorMode_Normal, 512 CursorMode_Attack, 513 CursorMode_Move, 514 CursorMode_Capture, 515 CursorMode_CarryallDrop, 516 CursorMode_Placing 517 }; 518 519 int currentCursorMode = CursorMode_Normal; 520 521 GameType gameType = GameType::Campaign; 522 int techLevel = 0; 523 int winFlags = 0; 524 int loseFlags = 0; 525 526 Random randomGen; ///< This is the random number generator for this game 527 ObjectData objectData; ///< This contains all the unit/structure data 528 529 GameState gameState = GameState::Start; 530 531 private: 532 bool chatMode = false; ///< chat mode on? 533 std::string typingChatMessage; ///< currently typed chat message 534 535 bool scrollDownMode = false; ///< currently scrolling the map down? 536 bool scrollLeftMode = false; ///< currently scrolling the map left? 537 bool scrollRightMode = false; ///< currently scrolling the map right? 538 bool scrollUpMode = false; ///< currently scrolling the map up? 539 540 bool selectionMode = false; ///< currently selection multiple units with a selection rectangle? 541 SDL_Rect selectionRect = {0, 0, 0, 0}; ///< the drawn rectangle while selection multiple units 542 543 int whatNextParam = GAME_NOTHING; 544 545 Uint32 indicatorFrame = NONE_ID; 546 int indicatorTime = 5; 547 int indicatorTimer = 0; 548 Coord indicatorPosition = Coord::Invalid(); 549 550 float averageFrameTime = 31.25f; ///< The weighted average of the frame time of all previous frames (smoothed fps = 1000.0f/averageFrameTime) 551 552 Uint32 gameCycleCount = 0; 553 554 Uint32 skipToGameCycle = 0; ///< skip to this game cycle 555 556 bool takePeriodicalScreenshots = false; ///< take a screenshot every 10 seconds 557 558 SDL_Rect powerIndicatorPos = {14, 146, 4, 0}; ///< position of the power indicator in the right game bar 559 SDL_Rect spiceIndicatorPos = {20, 146, 4, 0}; ///< position of the spice indicator in the right game bar 560 SDL_Rect topBarPos = {0, 0, 0, 0}; ///< position of the top game bar 561 SDL_Rect sideBarPos = {0, 0, 0, 0}; ///< position of the right side bar 562 563 //////////////////// 564 565 GameInitSettings gameInitSettings; ///< the init settings this game was started with 566 GameInitSettings nextGameInitSettings; ///< the init settings the next game shall be started with (restarting the mission, loading a savegame) 567 GameInitSettings::HouseInfoList houseInfoListSetup; ///< this saves with which houses and players the game was actually set up. It is a copy of gameInitSettings::houseInfoList but without random houses 568 569 570 ObjectManager objectManager; ///< This manages all the object and maps object ids to the actual objects 571 572 CommandManager cmdManager; ///< This is the manager for all the game commands (e.g. moving a unit) 573 574 TriggerManager triggerManager; ///< This is the manager for all the triggers the scenario has (e.g. reinforcements) 575 576 bool bQuitGame = false; ///< Should the game be quited after this game tick 577 bool bPause = false; ///< Is the game currently halted 578 bool bMenu = false; ///< Is there currently a menu shown (options or mentat menu) 579 bool bReplay = false; ///< Is this game actually a replay 580 581 bool bShowFPS = false; ///< Show the FPS 582 583 bool bShowTime = false; ///< Show how long this game is running 584 585 bool bCheatsEnabled = false; ///< Cheat codes are enabled? 586 587 bool finished = false; ///< Is the game finished (won or lost) and we are just waiting for the end message to be shown 588 bool won = false; ///< If the game is finished, is it won or lost 589 Uint32 finishedLevelTime = 0; ///< The time in milliseconds when the level was finished (won or lost) 590 bool finishedLevel = false; ///< Set, when the game is really finished and the end message was shown 591 592 GameInterface* pInterface = nullptr; ///< This is the whole interface (top bar and side bar) 593 InGameMenu* pInGameMenu = nullptr; ///< This is the menu that is opened by the option button 594 MentatHelp* pInGameMentat = nullptr; ///< This is the mentat dialog opened by the mentat button 595 WaitingForOtherPlayers* pWaitingForOtherPlayers = nullptr; ///< This is the dialog that pops up when we are waiting for other players during network hangs 596 Uint32 startWaitingForOtherPlayersTime = 0; ///< The time in milliseconds when we started waiting for other players 597 598 bool bSelectionChanged = false; ///< Has the selected list changed (and must be retransmitted to other plays in multiplayer games) 599 std::set<Uint32> selectedList; ///< A set of all selected units/structures 600 std::set<Uint32> selectedByOtherPlayerList; ///< This is only used in multiplayer games where two players control one house 601 RobustList<Explosion*> explosionList; ///< A list containing all the explosions that must be drawn 602 603 std::vector<House*> house; ///< All the houses of this game, index by their houseID; has the size NUM_HOUSES; unused houses are nullptr 604 605 std::string localPlayerName; ///< the name of the local player 606 std::multimap<std::string, Player*> playerName2Player; ///< mapping player names to players (one entry per player) 607 std::map<Uint8, Player*> playerID2Player; ///< mapping player ids to players (one entry per player) 608 }; 609 610 #endif // GAME_H 611