File indexing completed on 2024-12-08 03:47:31
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