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