File indexing completed on 2023-09-24 04:18:22

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