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