File indexing completed on 2024-04-21 04:04:07

0001 /* This file is part of KsirK.
0002    Copyright (C) 2004-2007 Gael de Chalendar <kleag@free.fr>
0003 
0004    KsirK is free software; you can redistribute it and/or
0005    modify it under the terms of the GNU General Public
0006    License as published by the Free Software Foundation, either version 2
0007    of the License, or (at your option) any later version.
0008 
0009    This program is distributed in the hope that it will be useful,
0010    but WITHOUT ANY WARRANTY; without even the implied warranty of
0011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0012    General Public License for more details.
0013 
0014    You should have received a copy of the GNU General Public License
0015    along with this program; if not, write to the Free Software
0016    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
0017    02110-1301, USA
0018 */
0019 
0020 #ifndef KSIRK_GAMELOGIC_GAMEAUTOMATON_H
0021 #define KSIRK_GAMELOGIC_GAMEAUTOMATON_H
0022 
0023 #include "eventslistproperty.h"
0024 
0025 #include "config-ksirk.h"
0026 
0027 #define USE_UNSTABLE_LIBKDEGAMESPRIVATE_API
0028 #include <libkdegamesprivate/kgame/kgame.h>
0029 #include <libkdegamesprivate/kgame/kplayer.h>
0030 #include <libkdegamesprivate/kgame/kgameio.h>
0031 #include <libkdegamesprivate/kgame/kgamemessage.h>
0032 #include <libkdegamesprivate/kgame/kgameproperty.h>
0033 #include <libkdegamesprivate/kgame/kmessageio.h>
0034 #include <libkdegamesprivate/kgamesvgdocument.h>
0035 
0036 #include <QPointF>
0037 #include <QString>
0038 #include <QSvgRenderer>
0039 #include <QMap>
0040 #include <QTextStream>
0041 
0042 namespace Ksirk {
0043   
0044   class KGameWindow;
0045   
0046 namespace GameLogic {
0047 
0048 class Player;
0049 class Country;
0050 class Goal;
0051 
0052 /**
0053   * All the messages that can be received.
0054   */
0055 enum KsirkMessagesIds {
0056     CountryOwner = KGameMessage::IdUser+1, // 257
0057     PlayerPutsArmy, // 258
0058     StateChange, // 259
0059     PlayerChange, // 260
0060     RegisterCountry, // 261
0061     PlayerAvailArmies, // 262
0062     ResetPlayersDistributionData, // 263
0063     ChangeItem, // 264
0064     DisplayRecyclingButtons, // 265
0065     ClearHighlighting, // 266
0066     ActionRecycling, // 267
0067     ClearGameActionsToolbar, // 268
0068     DisplayDefenseButtons, // 269
0069     ActionDefense, // 270
0070     FirstCountry, // 271
0071     SecondCountry, // 272
0072     InitCombatMovement, // 273
0073     AnimCombat, // 274
0074  // 275
0075     TerminateAttackSequence, // 276
0076     DecrNbArmies, // 277
0077     StartLocalCurrentAI, // 278
0078     Invade, // 279
0079     Retreat, // 280
0080     NextPlayerNormal, // 281
0081     NextPlayerRecycling, // 282
0082     ShowArmiesToPlace, // 283
0083     PlayerPutsInitialArmy, // 284
0084     PlayerRemovesArmy, //285
0085     VoteRecyclingFinished, // 286
0086     CancelShiftSource, // 287
0087     ChangePlayerNation, // 288
0088     ChangePlayerName, // 289
0089     StartGame, // 290
0090     SetNation, // 291
0091     SetBarFlagButton, // 292
0092     FinishMoves, // 293
0093     AnimExplosion, // 294
0094     SetupOnePlayer, // 295
0095     SetupWaitedPlayer, // 296
0096     ValidateWaitedPlayerPassword, // 297
0097     ValidPassword, // 298
0098     InvalidPassword, // 299
0099     SetupCountries, // 300
0100     AddMsgIdPair, // 301
0101     CheckGoal, // 302
0102     SetGoalFor, // 303
0103     GoalForIs, // 304
0104     Winner, // 305
0105     NbPlayers, // 306
0106     FinalizePlayers, // 307
0107     Acknowledge, // 308
0108     DisplayGoals, // 309
0109     DisplayFightResult, // 310
0110     MoveSlide, // 311
0111     InvasionFinished, // 312
0112     AttackAuto, // 313
0113     DisplayRecycleDetails, // 314
0114     CurrentPlayerPlayed, // 315
0115     NewGameSetupMsg, // 316
0116     UnusedLastMessageId
0117 };
0118 
0119 /** Messages formats:
0120   * 
0121   * CountryOwner: country name (QString), owner (QString) 
0122   * 
0123   */
0124 
0125 
0126 /**
0127   * This is the central class of the game. As a KGame it handles game status,
0128   * save/load, etc. In addition, it handles communication with other clients on
0129   * the network.
0130   * 
0131   * It is an automaton as its behavior depends on its state and on messages 
0132   * received from other parts of the game or from other clients on the network.
0133   * It is also a singleton accessible from anywhere in the process.
0134   * @author Gael de Chalendar
0135   */
0136 class GameAutomaton : public KGame
0137 {
0138 Q_OBJECT
0139     
0140     friend class GameSequence;
0141 
0142 public:
0143   /**
0144     * This hackish member is here to allow AIs to run only when goals have been
0145     * displayed. In fact, the game state should be set to KGame::Run at this
0146     * moment but if it is done there, then the IO messages are not transmited. I
0147     * don't understand why. Is it a KGame bug ?
0148     * As it is a hugly hack, it is made huglier by making it public...
0149     * @TODO Remove this hack
0150     */
0151   bool m_aicannotrunhack;
0152   
0153   /**
0154     * The State enum enumerates all the possible states of the game. The
0155     * behavior of various method will vary in function of it
0156     */
0157   enum GameState {
0158     INIT, 
0159     INTERLUDE, // Waiting state after initial distribution of armies at game beginning
0160     NEWARMIES, 
0161     WAIT, // Basic state waiting a player action
0162     WAIT1,
0163     WAIT_RECYCLING, 
0164     ATTACK,
0165     ATTACK2, 
0166     INVADE, 
0167     SHIFT1, 
0168     SHIFT2, 
0169     FIGHT_BRING,
0170     FIGHT_ANIMATE, 
0171     FIGHT_BRINGBACK, 
0172     WAITDEFENSE, 
0173     EXPLOSION_ANIMATE, 
0174     WAIT_PLAYERS, 
0175     GAME_OVER, // Game finished
0176     INVALID,
0177     STARTING_GAME // when displaying the new game ui
0178   };
0179 
0180   enum NetworkGameType {
0181     None,
0182     Socket,
0183 #if HAVE_JABBER_SUPPORT
0184     Jabber
0185 #endif
0186   };
0187   
0188   GameAutomaton();
0189   
0190   ~GameAutomaton() override;
0191   
0192   /** Creates the singleton member if necessary and associate it to the given
0193     * KGameWindow */
0194   void init(KGameWindow* gw);
0195 
0196   //@{
0197   /** Accessors to the game state. */
0198   GameState state() const;
0199   void state(GameState state);
0200   //@}
0201 
0202   /** 
0203     * Enques the given event the mouse being positioned at the given point
0204     * @param event The event to register
0205     * @param point The point where the event occurred
0206     */
0207   void gameEvent(const QString& event, const QPointF& point);
0208   
0209   /** returns the name of the current state */
0210   QString stateName() const;
0211     
0212   /**
0213     * Saves all the game parameters with a XML format
0214     * @param xmlStream the stream on which to write the XML
0215     */
0216   void saveXml(QTextStream& xmlStream);
0217 
0218   /** 
0219     * Retrives the name of the current skin.
0220     * @return The name of the current skin.
0221     */
0222   const QString& skin() const;
0223   
0224   /** 
0225     * Sets the new skin name.
0226     * @param newSkin The name of the new skin.
0227     */
0228   void skin(const QString& newSkin);
0229   
0230   /**
0231     * Reimplementation of a KGame virtual method. Not sure if it is really
0232     * necessary... 
0233     *
0234     * Chooses the next player to make a move by setting setTurn(true,true)
0235     * in the current player object. If a last player is given then the new
0236     * player will be chosen so that it is not the last player, i.e. the
0237     * players a swapped. If no last player is given then the current player
0238     * is reactiveted
0239     * @param last - the last player who made a move
0240     * @param unused
0241     * @return the player whose turn it will be
0242     */
0243   KPlayer* doNextPlayer(KPlayer *last,bool /*exclusive*/);
0244   
0245   /** 
0246     * Retrives the number of player playing from the network.
0247     * @return the number of players playing from the network.
0248     */
0249   inline unsigned int networkPlayersNumber() {return m_networkPlayersNumber;}
0250   inline void setNetworkPlayersNumber(unsigned int nb) {m_networkPlayersNumber = nb;}
0251   
0252   /** Retrives the game window. This one still contains too much game code 
0253     * that shouldn't be in a GUI class. */
0254   inline Ksirk::KGameWindow* game() {return m_game;}
0255   inline const Ksirk::KGameWindow* game() const {return m_game;}
0256   
0257   /**
0258     * Reimplementation of a KGame method. It creates players of different 
0259     * subclasses of KPlayer, depending on the rtti parameter.
0260     * @param rtti The class of the created player will depend of this value: 
0261     * Player if 1; AIPlayer (AIColsonPlayer if 2).
0262     * @param unused
0263     * @param isvirtual Will create a local or a (distant) virtual player 
0264     * depending on this value.
0265     */
0266   KPlayer* createPlayer(int rtti, int /**io*/, bool isvirtual) override;
0267   
0268   /**
0269    * @return A pointer to the given named player ; 0 if there is no such player
0270    */
0271   Player* playerNamed(const QString& playerName);
0272     
0273   //@{
0274   /** Accessors to the current player */
0275   Player* currentPlayer();
0276   void currentPlayer(Player* player);
0277   //@}
0278 
0279   //@{
0280   /** Accessors to the information about the fact that the current player 
0281     * already played or not */
0282   inline bool currentPlayerPlayed() {return m_currentPlayerPlayed;}
0283   inline void currentPlayerPlayed(bool val) {m_currentPlayerPlayed = val;}
0284   //@}
0285 
0286   //@{
0287   /** Accessors to the saved player, this is the player that will first play 
0288     * after loading a saved game. */
0289   inline void savedPlayer(const QString& player) {m_savedPlayer = player;}
0290   inline void savedState(GameState state) {m_savedState = state;}
0291   //@}
0292 
0293   //@{
0294   /** Accessors to the map associating messages to their ids */
0295   inline QMap<quint32,QString>& ids2msgs() {return m_ids2msgs;}
0296   inline QMap<QString,quint32>& msgs2ids() {return m_msgs2ids;}
0297   //@}
0298 
0299   //@{
0300   /** Accessors to the messages and their ids */
0301   quint32 idForMsg(const QString& msg);
0302   QString& msgForId(quint32 id) ;
0303   //@}
0304 
0305   //@{
0306   /** Accessors to the goals known by this game. */
0307   inline const QList< Goal* >& goals() const {return m_goals;}
0308   inline QList< Goal* >& goals() {return m_goals;}
0309   //@}
0310 
0311   /** If the game use goals, return true else (all players have to conquier the 
0312     * world) return false. */
0313   inline bool useGoals() {return m_useGoals;}
0314   inline void setUseGoals(bool value) {m_useGoals = value;}
0315   
0316   //@{
0317   /** Accessors to the number of players of this game. */
0318   inline quint32 nbPlayers() const {return m_nbPlayers;}
0319   inline void nbPlayers(quint32 nb) {m_nbPlayers = nb;}
0320   //@}
0321   
0322   /**
0323     * Ask the user how much players there will be in the game and what skin to 
0324     * use. Called during new game initialization.
0325     * @param networkGame If the user choose to setup a network game, this 
0326     * parameter will be true after closing the dialog else it will be false.
0327     * @param port If the user choose to setup a network game, this parameter 
0328     * will contain the port on which we will wait for connections.
0329     * @param newPlayersNumber Will contain the number players of the new game.
0330     */
0331   bool setupPlayersNumberAndSkin(NetworkGameType netGameType);
0332   
0333     /**
0334      * Create an IO device like Mouse or Keyboard for the given player
0335      * and plug it into the player
0336      * @param player - the player who should get the IO device
0337      * @param io - the IO code for which a device needs to be created
0338      */
0339   void createIO(KPlayer *player,KGameIO::IOMode io);
0340   
0341   /** @return true if all players are played by computer ; false otherwise */
0342   bool allComputerPlayers();
0343   
0344   /** @return true if all local players are played by computer ; false otherwise */
0345   bool allLocalPlayersComputer();
0346     
0347   /**
0348    * Gets a local player.
0349    * @return Returns a local player... Any of them. Or 0 if there is no local
0350    * player.
0351    */
0352   Player* getAnyLocalPlayer();
0353   
0354   //@{
0355   /** Some accessors to data really necessary... */
0356   inline QMap< int, QString >& nbArmiesIdsNamesCountriesMap() {return m_nbArmiesIdsNamesCountriesMap;}
0357   inline QMap< QString, int >& namesNbArmiesIdsCountriesMap() {return m_namesNbArmiesIdsCountriesMap;}
0358 //   inline QMap< int, QString >& nbAddedArmiesIdsNamesCountriesMap() {return m_nbAddedArmiesIdsNamesCountriesMap;}
0359   inline QMap< QString, int >& namesNbAddedArmiesIdsCountriesMap() {return m_namesNbAddedArmiesIdsCountriesMap;}
0360   //@}
0361 
0362   void movingFigthersArrived();
0363   void movingArmiesArrived();
0364   void movingArmyArrived(Country* country, unsigned int number);
0365   void firingFinished();
0366   void explosionFinished();
0367 
0368   void moveSlide();
0369 
0370   /**
0371     * Change the automatic attack state.
0372     * @param activated new state
0373     */
0374   void setAttackAuto(bool activated);
0375 
0376   /**
0377     * Get the automatic attack state.
0378     * @return state
0379     */
0380   inline bool isAttackAuto() {return m_attackAuto;}
0381 
0382   /**
0383     * Change the automatic defense state.
0384     * @param activated new state
0385     */
0386   void setDefenseAuto(bool activated);
0387 
0388   /**
0389     * Get the automatic defense state.
0390     * @return state
0391     */
0392   bool isDefenseAuto();
0393 
0394   bool finishSetupPlayersNumberAndSkin();
0395 
0396   inline int port() const {return m_port;}
0397 
0398 #if HAVE_JABBER_SUPPORT
0399   void askForJabberGames();
0400 #endif
0401 
0402   bool startingGame() const;
0403 
0404   QSvgRenderer& rendererFor(const QString& skinName);
0405   KGameSvgDocument& svgDomFor(const QString& skinName);
0406 
0407   inline NetworkGameType networkGameType() {return m_netGameType;}
0408 
0409 #if HAVE_JABBER_SUPPORT
0410   bool joinJabberGame(const QString& nick);
0411 #endif
0412 
0413   void removeAllPlayers();
0414   // Bug 308527.
0415   void removeAllGoals();
0416 
0417   void newGameNext();
0418   
0419   bool connectToServ();
0420 
0421   void checkGoal(Player* player = nullptr);
0422 
0423 #if HAVE_JABBER_SUPPORT
0424 Q_SIGNALS:
0425   void newJabberGame(const QString&, int, const QString&);
0426 #endif
0427 
0428 public Q_SLOTS:
0429   /** Reacts to the current state eventualy processing one queued event */
0430   GameState run();
0431   
0432   /**
0433     * This slot connects to a main signal of the KGame. It will be called
0434     * whenever a KGame property changes its value. This slot can then
0435     * used to build up the event distribution of your game, i.e. you react
0436     * here to all events generated by the game (NewGame, ...)
0437     * Which property is changed you best find out via the property id.
0438     * For example: if (prop-id() == myvariable.id()) ...
0439     *
0440     * @param prop - the property 
0441     * @param game - the game object (unused)
0442     */
0443   void slotPropertyChanged(KGamePropertyBase *prop,KGame * game);
0444   
0445   /**
0446     * This slot is called whenever a player joins the game.
0447     * @param player The player that joined the game.
0448     */
0449   void slotPlayerJoinedGame(KPlayer* player);
0450   
0451   /**
0452     * Called when data is received from the network.
0453     * @param msgid Identifies the message.
0454     * @param buffer Contains the data associated to this message.
0455     * @param receiver Id of the client destination of this message.
0456     * @param sender Id of the client sender of this message.
0457     */
0458   void slotNetworkData(int msgid, const QByteArray &buffer, 
0459           quint32 receiver, quint32 sender);
0460   
0461   /**
0462     * Called when a network client connects to this game.
0463     * @param clientid The id of the client connecting.
0464     * @param unused
0465     */
0466   void slotClientJoinedGame(quint32 clientid, KGame* me);
0467     
0468   /**
0469     * Called when the network connection to the server is broken.
0470     */
0471   void slotConnectionToServerBroken();
0472   
0473   /**
0474     * Called when the network connection to a client is broken.
0475     */
0476   void slotConnectionToClientBroken(KMessageIO *);
0477 
0478   Country* getDefCountry();
0479 
0480 private Q_SLOTS:
0481   void displayGoals();
0482   
0483   
0484 protected:
0485   friend class Ksirk::KGameWindow;
0486   
0487   /**
0488     * Main method of the KGame which has to be overwritten in our
0489     * class. It will receive all input a player makes, either via
0490     * network, via mouse or even a computer player.
0491     * @param msg - the datastream message containing the information
0492     * @param player - the player who did the input
0493     */
0494   bool playerInput(QDataStream &msg,KPlayer *player) override;
0495 
0496     
0497   /**
0498     * Random distribution of countries between players at beginning of game.
0499     * This is different than in the real board game where countries are chosen
0500     * one by one by each player. This is in order to quick up game beginning.
0501     */
0502   void firstCountriesDistribution();
0503   
0504   void setGoalFor(Player* player);
0505   
0506 private:
0507   GameAutomaton(const GameAutomaton& /*ga*/) : KGame() {};
0508 
0509   void countriesDistribution();
0510 
0511   void sendCountries();
0512   
0513   bool joinNetworkGame();
0514     
0515   void changePlayerName(Player* player);
0516   
0517   void changePlayerNation(Player* player);
0518   
0519   bool startGame();
0520 
0521   void finalizePlayers();
0522   
0523   void activateNeededAIPlayers();
0524 
0525   void resetPlayersDistributionData();
0526 
0527   void actionNextPlayer();
0528   
0529   GameState m_state;
0530 //   KGameProperty< GameState > m_state;
0531 //     int m_stateId;
0532   
0533   Ksirk::KGameWindow *m_game;
0534   
0535   EventsListProperty m_events;
0536   
0537   static const char* GameStateNames[] ;
0538   
0539   static const char* KsirkMessagesIdsNames[] ;
0540   
0541   KGamePropertyQString m_skin;
0542   
0543   unsigned int m_networkPlayersNumber;
0544   
0545   int m_skinId;
0546 
0547   /** @brief The name of the current player */
0548   QString m_currentPlayer;
0549 
0550   /** @brief false until the current player has played something */
0551 
0552   bool m_currentPlayerPlayed;
0553 //   int m_currentPlayerId;
0554   
0555   QMap< int, QString > m_nbArmiesIdsNamesCountriesMap;
0556   QMap< QString, int > m_namesNbArmiesIdsCountriesMap;
0557 //   QMap< int, QString > m_nbAddedArmiesIdsNamesCountriesMap;
0558   QMap< QString, int > m_namesNbAddedArmiesIdsCountriesMap;
0559 
0560   quint32 m_choosedToRecycleNumber;
0561   
0562   QString m_savedPlayer;
0563   GameState m_savedState;
0564   
0565   QMap<quint32,QString> m_ids2msgs;
0566   QMap<QString,quint32> m_msgs2ids;
0567   
0568   QList< Goal* > m_goals;
0569   bool m_useGoals;
0570   
0571   quint32 m_nbPlayers;
0572 
0573   QList<int> m_choosedToRecycle;
0574 
0575   // tell us if the automatic attack is enabled
0576   bool m_attackAuto;
0577 
0578   // tell us if the automatic defense is enabled
0579   struct AutoDefenseStruct
0580   {
0581     AutoDefenseStruct() : value(false), firstCountry(nullptr), secondCountry(nullptr) {}
0582     AutoDefenseStruct(bool v) : value(v), firstCountry(nullptr), secondCountry(nullptr) {}
0583     bool isDefenseAuto(Country* first, Country* second)
0584     {
0585       if (firstCountry!=first || secondCountry!=second)
0586       {
0587         firstCountry = nullptr;
0588         secondCountry = nullptr;
0589         value = false;
0590       }
0591       return value;
0592     }
0593     bool value;
0594     Country* firstCountry;
0595     Country* secondCountry;
0596   };
0597   AutoDefenseStruct m_defenseAuto;
0598 
0599   // Save Defense country
0600   Country * defCountry;
0601 
0602   int m_port;
0603   
0604   bool m_startingGame;
0605 
0606   QMap<QString, QSvgRenderer*> m_renderers;
0607   QMap<QString, KGameSvgDocument> m_svgDoms;
0608 
0609   NetworkGameType m_netGameType;
0610 };
0611 
0612 QDataStream& operator>>(QDataStream& s, GameAutomaton::GameState& state);
0613   
0614 } // closing namespace GameLogic
0615 } // closing namespace Ksirk
0616 
0617 #endif // KSIRK_GAMELOGIC_GAMEAUTOMATON_H