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