1 /* This file is part of KsirK.
2    Copyright (C) 2004-2007 Gael de Chalendar <kleag@free.fr>
3 
4    KsirK is free software; you can redistribute it and/or
5    modify it under the terms of the GNU General Public
6    License as published by the Free Software Foundation, either version 2
7    of the License, or (at your option) any later version.
8 
9    This program 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 GNU
12    General Public License for more details.
13 
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software
16    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17    02110-1301, USA
18 */
19 
20 #ifndef KSIRK_GAMELOGIC_GAMEAUTOMATON_H
21 #define KSIRK_GAMELOGIC_GAMEAUTOMATON_H
22 
23 #include "eventslistproperty.h"
24 
25 #define USE_UNSTABLE_LIBKDEGAMESPRIVATE_API
26 #include <libkdegamesprivate/kgame/kgame.h>
27 #include <libkdegamesprivate/kgame/kplayer.h>
28 #include <libkdegamesprivate/kgame/kgameio.h>
29 #include <libkdegamesprivate/kgame/kgamemessage.h>
30 #include <libkdegamesprivate/kgame/kgameproperty.h>
31 #include <libkdegamesprivate/kgame/kmessageio.h>
32 #include <libkdegamesprivate/kgamesvgdocument.h>
33 
34 #include <QPointF>
35 #include <QString>
36 #include <QSvgRenderer>
37 #include <QMap>
38 #include <QTextStream>
39 
40 namespace Ksirk {
41 
42   class KGameWindow;
43 
44 namespace GameLogic {
45 
46 class Player;
47 class Country;
48 class Goal;
49 
50 /**
51   * All the messages that can be received.
52   */
53 enum KsirkMessagesIds {
54     CountryOwner = KGameMessage::IdUser+1, // 257
55     PlayerPutsArmy, // 258
56     StateChange, // 259
57     PlayerChange, // 260
58     RegisterCountry, // 261
59     PlayerAvailArmies, // 262
60     ResetPlayersDistributionData, // 263
61     ChangeItem, // 264
62     DisplayRecyclingButtons, // 265
63     ClearHighlighting, // 266
64     ActionRecycling, // 267
65     ClearGameActionsToolbar, // 268
66     DisplayDefenseButtons, // 269
67     ActionDefense, // 270
68     FirstCountry, // 271
69     SecondCountry, // 272
70     InitCombatMovement, // 273
71     AnimCombat, // 274
72  // 275
73     TerminateAttackSequence, // 276
74     DecrNbArmies, // 277
75     StartLocalCurrentAI, // 278
76     Invade, // 279
77     Retreat, // 280
78     NextPlayerNormal, // 281
79     NextPlayerRecycling, // 282
80     ShowArmiesToPlace, // 283
81     PlayerPutsInitialArmy, // 284
82     PlayerRemovesArmy, //285
83     VoteRecyclingFinished, // 286
84     CancelShiftSource, // 287
85     ChangePlayerNation, // 288
86     ChangePlayerName, // 289
87     StartGame, // 290
88     SetNation, // 291
89     SetBarFlagButton, // 292
90     FinishMoves, // 293
91     AnimExplosion, // 294
92     SetupOnePlayer, // 295
93     SetupWaitedPlayer, // 296
94     ValidateWaitedPlayerPassword, // 297
95     ValidPassword, // 298
96     InvalidPassword, // 299
97     SetupCountries, // 300
98     AddMsgIdPair, // 301
99     CheckGoal, // 302
100     SetGoalFor, // 303
101     GoalForIs, // 304
102     Winner, // 305
103     NbPlayers, // 306
104     FinalizePlayers, // 307
105     Acknowledge, // 308
106     DisplayGoals, // 309
107     DisplayFightResult, // 310
108     MoveSlide, // 311
109     InvasionFinished, // 312
110     AttackAuto, // 313
111     DisplayRecycleDetails, // 314
112     CurrentPlayerPlayed, // 315
113     NewGameSetupMsg, // 316
114     UnusedLastMessageId
115 };
116 
117 /** Messages formats:
118   *
119   * CountryOwner: country name (QString), owner (QString)
120   *
121   */
122 
123 
124 /**
125   * This is the central class of the game. As a KGame it handles game status,
126   * save/load, etc. In addition, it handles communication with other clients on
127   * the network.
128   *
129   * It is an automaton as its behavior depends on its state and on messages
130   * received from other parts of the game or from other clients on the network.
131   * It is also a singleton accessible from anywhere in the process.
132   * @author Gael de Chalendar
133   */
134 class GameAutomaton : public KGame
135 {
136 Q_OBJECT
137 
138 public:
139   /**
140     * This hackish member is here to allow AIs to run only when goals have been
141     * displayed. In fact, the game state should be set to KGame::Run at this
142     * moment but if it is done there, then the IO messages are not transmited. I
143     * don't understand why. Is it a KGame bug ?
144     * As it is a hugly hack, it is made huglier by making it public...
145     * @TODO Remove this hack
146     */
147   bool m_aicannotrunhack;
148 
149   /**
150     * The State enum enumerates all the possible states of the game. The
151     * behavior of various method will vary in function of it
152     */
153   enum GameState {
154     INIT,
155     INTERLUDE, // Waiting state after initial distribution of armies at game beginning
156     NEWARMIES,
157     WAIT, // Basic state waiting a player action
158     WAIT1,
159     WAIT_RECYCLING,
160     ATTACK,
161     ATTACK2,
162     INVADE,
163     SHIFT1,
164     SHIFT2,
165     FIGHT_BRING,
166     FIGHT_ANIMATE,
167     FIGHT_BRINGBACK,
168     WAITDEFENSE,
169     EXPLOSION_ANIMATE,
170     WAIT_PLAYERS,
171     GAME_OVER, // Game finished
172     INVALID,
173     STARTING_GAME // when displaying the new game ui
174   };
175 
176   enum NetworkGameType {
177     None,
178     Socket,
179     Jabber
180   };
181 
182   GameAutomaton();
183 
184   ~GameAutomaton() override;
185 
186   /** Creates the singleton member if necessary and associate it to the given
187     * KGameWindow */
188   void init(KGameWindow* gw);
189 
190   //@{
191   /** Accessors to the game state. */
192   GameState state() const;
193   void state(GameState state);
194   //@}
195 
196   /**
197     * Enques the given event the mouse being positioned at the given point
198     * @param event The event to register
199     * @param point The point where the event occurred
200     */
201   void gameEvent(const QString& event, const QPointF& point);
202 
203   /** returns the name of the current state */
204   QString stateName() const;
205 
206   /**
207     * Saves all the game parameters with a XML format
208     * @param xmlStream the stream on which to write the XML
209     */
210   void saveXml(QTextStream& xmlStream);
211 
212   /**
213     * Retrives the name of the current skin.
214     * @return The name of the current skin.
215     */
216   const QString& skin() const;
217 
218   /**
219     * Sets the new skin name.
220     * @param newSkin The name of the new skin.
221     */
222   void skin(const QString& newSkin);
223 
224   /**
225     * Reimplementation of a KGame virtual method. Not sure if it is really
226     * necessary...
227     *
228     * Chooses the next player to make a move by setting setTurn(true,true)
229     * in the current player object. If a last player is given then the new
230     * player will be chosen so that it is not the last player, i.e. the
231     * players a swapped. If no last player is given then the current player
232     * is reactiveted
233     * @param last - the last player who made a move
234     * @param unused
235     * @return the player whose turn it will be
236     */
237   KPlayer* nextPlayer(KPlayer *last,bool /*exclusive*/) override;
238 
239   /**
240     * Retrives the number of player playing from the network.
241     * @return the number of players playing from the network.
242     */
networkPlayersNumber()243   inline unsigned int networkPlayersNumber() {return m_networkPlayersNumber;}
setNetworkPlayersNumber(unsigned int nb)244   inline void setNetworkPlayersNumber(unsigned int nb) {m_networkPlayersNumber = nb;}
245 
246   /** Retrives the game window. This one still contains too much game code
247     * that shouldn't be in a GUI class. */
game()248   inline Ksirk::KGameWindow* game() {return m_game;}
game()249   inline const Ksirk::KGameWindow* game() const {return m_game;}
250 
251   /**
252     * Reimplementation of a KGame method. It creates players of different
253     * subclasses of KPlayer, depending on the rtti parameter.
254     * @param rtti The class of the created player will depend of this value:
255     * Player if 1; AIPlayer (AIColsonPlayer if 2).
256     * @param unused
257     * @param isvirtual Will create a local or a (distant) virtual player
258     * depending on this value.
259     */
260   KPlayer* createPlayer(int rtti, int /**io*/, bool isvirtual) override;
261 
262   /**
263    * @return A pointer to the given named player ; 0 if there is no such player
264    */
265   Player* playerNamed(const QString& playerName);
266 
267   //@{
268   /** Accessors to the current player */
269   Player* currentPlayer();
270   void currentPlayer(Player* player);
271   //@}
272 
273   //@{
274   /** Accessors to the information about the fact that the current player
275     * already played or not */
currentPlayerPlayed()276   inline bool currentPlayerPlayed() {return m_currentPlayerPlayed;}
currentPlayerPlayed(bool val)277   inline void currentPlayerPlayed(bool val) {m_currentPlayerPlayed = val;}
278   //@}
279 
280   //@{
281   /** Accessors to the saved player, this is the player that will first play
282     * after loading a saved game. */
savedPlayer(const QString & player)283   inline void savedPlayer(const QString& player) {m_savedPlayer = player;}
savedState(GameState state)284   inline void savedState(GameState state) {m_savedState = state;}
285   //@}
286 
287   //@{
288   /** Accessors to the map associating messages to their ids */
ids2msgs()289   inline QMap<quint32,QString>& ids2msgs() {return m_ids2msgs;}
msgs2ids()290   inline QMap<QString,quint32>& msgs2ids() {return m_msgs2ids;}
291   //@}
292 
293   //@{
294   /** Accessors to the messages and their ids */
295   quint32 idForMsg(const QString& msg);
296   QString& msgForId(quint32 id) ;
297   //@}
298 
299   //@{
300   /** Accessors to the goals known by this game. */
goals()301   inline const QList< Goal* >& goals() const {return m_goals;}
goals()302   inline QList< Goal* >& goals() {return m_goals;}
303   //@}
304 
305   /** If the game use goals, return true else (all players have to conquier the
306     * world) return false. */
useGoals()307   inline bool useGoals() {return m_useGoals;}
setUseGoals(bool value)308   inline void setUseGoals(bool value) {m_useGoals = value;}
309 
310   //@{
311   /** Accessors to the number of players of this game. */
nbPlayers()312   inline quint32 nbPlayers() const {return m_nbPlayers;}
nbPlayers(quint32 nb)313   inline void nbPlayers(quint32 nb) {m_nbPlayers = nb;}
314   //@}
315 
316   /**
317     * Ask the user how much players there will be in the game and what skin to
318     * use. Called during new game initialization.
319     * @param networkGame If the user choose to setup a network game, this
320     * parameter will be true after closing the dialog else it will be false.
321     * @param port If the user choose to setup a network game, this parameter
322     * will contain the port on which we will wait for connections.
323     * @param newPlayersNumber Will contain the number players of the new game.
324     */
325   bool setupPlayersNumberAndSkin(NetworkGameType netGameType);
326 
327     /**
328      * Create an IO device like Mouse or Keyboard for the given player
329      * and plug it into the player
330      * @param player - the player who should get the IO device
331      * @param io - the IO code for which a device needs to be created
332      */
333   void createIO(KPlayer *player,KGameIO::IOMode io);
334 
335   /** @return true if all players are played by computer ; false otherwise */
336   bool allComputerPlayers();
337 
338   /** @return true if all local players are played by computer ; false otherwise */
339   bool allLocalPlayersComputer();
340 
341   /**
342    * Gets a local player.
343    * @return Returns a local player... Any of them. Or 0 if there is no local
344    * player.
345    */
346   Player* getAnyLocalPlayer();
347 
348   //@{
349   /** Some accessors to data really necessary... */
nbArmiesIdsNamesCountriesMap()350   inline QMap< int, QString >& nbArmiesIdsNamesCountriesMap() {return m_nbArmiesIdsNamesCountriesMap;}
namesNbArmiesIdsCountriesMap()351   inline QMap< QString, int >& namesNbArmiesIdsCountriesMap() {return m_namesNbArmiesIdsCountriesMap;}
352 //   inline QMap< int, QString >& nbAddedArmiesIdsNamesCountriesMap() {return m_nbAddedArmiesIdsNamesCountriesMap;}
namesNbAddedArmiesIdsCountriesMap()353   inline QMap< QString, int >& namesNbAddedArmiesIdsCountriesMap() {return m_namesNbAddedArmiesIdsCountriesMap;}
354   //@}
355 
356   void movingFigthersArrived();
357   void movingArmiesArrived();
358   void movingArmyArrived(Country* country, unsigned int number);
359   void firingFinished();
360   void explosionFinished();
361 
362   void moveSlide();
363 
364   /**
365     * Change the automatic attack state.
366     * @param activated new state
367     */
368   void setAttackAuto(bool activated);
369 
370   /**
371     * Get the automatic attack state.
372     * @return state
373     */
isAttackAuto()374   inline bool isAttackAuto() {return m_attackAuto;}
375 
376   /**
377     * Change the automatic defense state.
378     * @param activated new state
379     */
380   void setDefenseAuto(bool activated);
381 
382   /**
383     * Get the automatic defense state.
384     * @return state
385     */
386   bool isDefenseAuto();
387 
388   bool finishSetupPlayersNumberAndSkin();
389 
port()390   inline int port() const {return m_port;}
391 
392   void askForJabberGames();
393 
394   bool startingGame() const;
395 
396   QSvgRenderer& rendererFor(const QString& skinName);
397   KGameSvgDocument& svgDomFor(const QString& skinName);
398 
networkGameType()399   inline NetworkGameType networkGameType() {return m_netGameType;}
400 
401   bool joinJabberGame(const QString& nick);
402 
403   void removeAllPlayers();
404   // Bug 308527.
405   void removeAllGoals();
406 
407   void newGameNext();
408 
409   bool connectToServ();
410 
411   void checkGoal(Player* player = 0);
412 
413 Q_SIGNALS:
414   void newJabberGame(const QString&, int, const QString&);
415 
416 public Q_SLOTS:
417   /** Reacts to the current state eventualy processing one queued event */
418   GameState run();
419 
420   /**
421     * This slot connects to a main signal of the KGame. It will be called
422     * whenever a KGame property changes its value. This slot can then
423     * used to build up the event distribution of your game, i.e. you react
424     * here to all events generated by the game (NewGame, ...)
425     * Which property is changed you best find out via the property id.
426     * For example: if (prop-id() == myvariable.id()) ...
427     *
428     * @param prop - the property
429     * @param game - the game object (unused)
430     */
431   void slotPropertyChanged(KGamePropertyBase *prop,KGame * game);
432 
433   /**
434     * This slot is called whenever a player joins the game.
435     * @param player The player that joined the game.
436     */
437   void slotPlayerJoinedGame(KPlayer* player);
438 
439   /**
440     * Called when data is received from the network.
441     * @param msgid Identifies the message.
442     * @param buffer Contains the data associated to this message.
443     * @param receiver Id of the client destination of this message.
444     * @param sender Id of the client sender of this message.
445     */
446   void slotNetworkData(int msgid, const QByteArray &buffer,
447           quint32 receiver, quint32 sender);
448 
449   /**
450     * Called when a network client connects to this game.
451     * @param clientid The id of the client connecting.
452     * @param unused
453     */
454   void slotClientJoinedGame(quint32 clientid, KGame* me);
455 
456   /**
457     * Called when the network connection to the server is broken.
458     */
459   void slotConnectionToServerBroken();
460 
461   /**
462     * Called when the network connection to a client is broken.
463     */
464   void slotConnectionToClientBroken(KMessageIO *);
465 
466   Country* getDefCountry();
467 
468 private Q_SLOTS:
469   void displayGoals();
470 
471 
472 protected:
473   friend class Ksirk::KGameWindow;
474 
475   /**
476     * Main method of the KGame which has to be overwritten in our
477     * class. It will receive all input a player makes, either via
478     * network, via mouse or even a computer player.
479     * @param msg - the datastream message containing the information
480     * @param player - the player who did the input
481     */
482   bool playerInput(QDataStream &msg,KPlayer *player) override;
483 
484 
485   /**
486     * Random distribution of countries between players at beginning of game.
487     * This is different than in the real board game where countries are chosen
488     * one by one by each player. This is in order to quick up game beginning.
489     */
490   void firstCountriesDistribution();
491 
492   void setGoalFor(Player* player);
493 
494 private:
GameAutomaton(const GameAutomaton &)495   GameAutomaton(const GameAutomaton& /*ga*/) : KGame() {};
496 
497   void countriesDistribution();
498 
499   void sendCountries();
500 
501   bool joinNetworkGame();
502 
503   void changePlayerName(Player* player);
504 
505   void changePlayerNation(Player* player);
506 
507   bool startGame();
508 
509   void finalizePlayers();
510 
511   void activateNeededAIPlayers();
512 
513   void resetPlayersDistributionData();
514 
515   void actionNextPlayer();
516 
517   GameState m_state;
518 //   KGameProperty< GameState > m_state;
519 //     int m_stateId;
520 
521   Ksirk::KGameWindow *m_game;
522 
523   EventsListProperty m_events;
524 
525   static const char* GameStateNames[] ;
526 
527   static const char* KsirkMessagesIdsNames[] ;
528 
529   KGamePropertyQString m_skin;
530 
531   unsigned int m_networkPlayersNumber;
532 
533   int m_skinId;
534 
535   /** @brief The name of the current player */
536   QString m_currentPlayer;
537 
538   /** @brief false until the current player has played something */
539 
540   bool m_currentPlayerPlayed;
541 //   int m_currentPlayerId;
542 
543   QMap< int, QString > m_nbArmiesIdsNamesCountriesMap;
544   QMap< QString, int > m_namesNbArmiesIdsCountriesMap;
545 //   QMap< int, QString > m_nbAddedArmiesIdsNamesCountriesMap;
546   QMap< QString, int > m_namesNbAddedArmiesIdsCountriesMap;
547 
548   quint32 m_choosedToRecycleNumber;
549 
550   QString m_savedPlayer;
551   GameState m_savedState;
552 
553   QMap<quint32,QString> m_ids2msgs;
554   QMap<QString,quint32> m_msgs2ids;
555 
556   QList< Goal* > m_goals;
557   bool m_useGoals;
558 
559   quint32 m_nbPlayers;
560 
561   QList<int> m_choosedToRecycle;
562 
563   // tell us if the automatic attack is enabled
564   bool m_attackAuto;
565 
566   // tell us if the automatic defense is enabled
567   struct AutoDefenseStruct
568   {
AutoDefenseStructAutoDefenseStruct569     AutoDefenseStruct() : value(false), firstCountry(0), secondCountry(0) {}
AutoDefenseStructAutoDefenseStruct570     AutoDefenseStruct(bool v) : value(v), firstCountry(0), secondCountry(0) {}
isDefenseAutoAutoDefenseStruct571     bool isDefenseAuto(Country* first, Country* second)
572     {
573       if (firstCountry!=first || secondCountry!=second)
574       {
575         firstCountry = 0;
576         secondCountry = 0;
577         value = false;
578       }
579       return value;
580     }
581     bool value;
582     Country* firstCountry;
583     Country* secondCountry;
584   };
585   AutoDefenseStruct m_defenseAuto;
586 
587   // Save Defense country
588   Country * defCountry;
589 
590   int m_port;
591 
592   bool m_startingGame;
593 
594   QMap<QString, QSvgRenderer*> m_renderers;
595   QMap<QString, KGameSvgDocument> m_svgDoms;
596 
597   NetworkGameType m_netGameType;
598 };
599 
600 QDataStream& operator>>(QDataStream& s, GameAutomaton::GameState& state);
601 
602 } // closing namespace GameLogic
603 } // closing namespace Ksirk
604 
605 #endif // KSIRK_GAMELOGIC_GAMEAUTOMATON_H
606