From c3dc51aed129c6652900fab5543f2790669428de Mon Sep 17 00:00:00 2001 From: Xawotihs Date: Wed, 26 Oct 2011 22:14:12 +0000 Subject: [PATCH] I just played 3 long games and I was able to undo two fully and got an assert on the third one after more than 1000 actions... so I commit what I have: - Modified undo to stop at "next phase" action - Added "muligan" and "force library shuffling" to the list of logged action - Fixed random logging - Fixed double logging of actions - Merged all the "next game" functions into a single one - Created a PlayerType type instead of using int - Moved the player loading code into the GameObserver and out of GameStateDuel to avoid having player references in both and simplify the initialization and termination. Tweeked a bit the humanplayer class to be able to do that. - Added a "load" menu available in testsuite mode, I use that to load problematique game. To use it, just copy-paste a game from the traces into Res/test/game/timetwister.txt. Game in traces starts by "rvalues:..." and ends by "[end]" - Added some untested and commented out code in GuiCombat to use the mouse/touch to setup the damage on the blockers - Broke the network game ... hoh well, I'll repair it when everything else works !! - various code cleanup and compilation fixes on Linux --- projects/mtg/include/AbilityParser.h | 2 +- projects/mtg/include/ActionLayer.h | 1 - projects/mtg/include/ActionStack.h | 4 +- projects/mtg/include/AllAbilities.h | 8 +- projects/mtg/include/GameApp.h | 15 +- projects/mtg/include/GameObserver.h | 16 ++- projects/mtg/include/GameStateDuel.h | 9 +- projects/mtg/include/MTGAbility.h | 2 +- projects/mtg/include/MTGDefinitions.h | 11 ++ projects/mtg/include/MTGGameZones.h | 108 +++++++-------- projects/mtg/include/Player.h | 8 +- projects/mtg/include/utils.h | 2 +- projects/mtg/src/AIPlayer.cpp | 4 +- projects/mtg/src/AIPlayerBaka.cpp | 5 +- projects/mtg/src/AbilityParser.cpp | 2 +- projects/mtg/src/ActionLayer.cpp | 17 +-- projects/mtg/src/ActionStack.cpp | 16 ++- projects/mtg/src/AllAbilities.cpp | 6 +- projects/mtg/src/CardDisplay.cpp | 3 +- projects/mtg/src/DeckMenu.cpp | 2 +- projects/mtg/src/DuelLayers.cpp | 1 + projects/mtg/src/GameApp.cpp | 6 +- projects/mtg/src/GameObserver.cpp | 191 ++++++++++++++++++++++---- projects/mtg/src/GameStateDuel.cpp | 119 ++++------------ projects/mtg/src/GuiCombat.cpp | 34 ++++- projects/mtg/src/IconButton.cpp | 2 +- projects/mtg/src/MTGDeck.cpp | 3 +- projects/mtg/src/MTGGamePhase.cpp | 3 - projects/mtg/src/MTGGameZones.cpp | 2 +- projects/mtg/src/MTGRules.cpp | 8 +- projects/mtg/src/Player.cpp | 14 +- projects/mtg/src/Rules.cpp | 6 +- projects/mtg/src/TextScroller.cpp | 68 ++++----- projects/mtg/src/utils.cpp | 9 +- 34 files changed, 410 insertions(+), 297 deletions(-) diff --git a/projects/mtg/include/AbilityParser.h b/projects/mtg/include/AbilityParser.h index c109b6e87..c6e4f3a2e 100644 --- a/projects/mtg/include/AbilityParser.h +++ b/projects/mtg/include/AbilityParser.h @@ -24,4 +24,4 @@ public: static string Process(const string& s); }; -#endif \ No newline at end of file +#endif diff --git a/projects/mtg/include/ActionLayer.h b/projects/mtg/include/ActionLayer.h index 911624a4e..c7056b603 100644 --- a/projects/mtg/include/ActionLayer.h +++ b/projects/mtg/include/ActionLayer.h @@ -44,7 +44,6 @@ public: void setMenuObject(Targetable * object, bool must = false); void setCustomMenuObject(Targetable * object, bool must = false,vectorabilities = vector()); void ButtonPressed(int controllerid, int controlid); - void doMultipleChoice(int choice = -1); void ButtonPressedOnMultipleChoice(int choice = -1); void doReactTo(int menuIndex); TargetChooser * getCurrentTargetChooser(); diff --git a/projects/mtg/include/ActionStack.h b/projects/mtg/include/ActionStack.h index 4c04a2207..a8c5f5917 100644 --- a/projects/mtg/include/ActionStack.h +++ b/projects/mtg/include/ActionStack.h @@ -207,7 +207,7 @@ public: DONT_INTERRUPT_ALL = 2, }; Player * lastActionController; - int setIsInterrupting(Player * player); + int setIsInterrupting(Player * player, bool log = true); int count( int type = 0 , int state = 0 , int display = -1); Interruptible * getActionElementFromCard(MTGCardInstance * card); Interruptible * getPrevious(Interruptible * next, int type = 0, int state = 0 , int display = -1); @@ -217,7 +217,7 @@ public: void Fizzle(Interruptible * action); Interruptible * getAt(int id); void cancelInterruptOffer(int cancelMode = 1); - void endOfInterruption(); + void endOfInterruption(bool log = true); Interruptible * getLatest(int state); Player * askIfWishesToInterrupt; int garbageCollect(); diff --git a/projects/mtg/include/AllAbilities.h b/projects/mtg/include/AllAbilities.h index 8dbbb28f7..38a166419 100644 --- a/projects/mtg/include/AllAbilities.h +++ b/projects/mtg/include/AllAbilities.h @@ -1655,8 +1655,8 @@ public: void Update(float dt) { - if(!nonstatic) - return; + if(!nonstatic) + return; ((MTGCardInstance *) target)->power -= wppt->power.getValue(); ((MTGCardInstance *) target)->addToToughness(-wppt->toughness.getValue()); if(PT.size()) @@ -1980,9 +1980,9 @@ public: void Update(float dt) { ListMaintainerAbility::Update(dt); - if(!ability->oneShot) + if(!ability->oneShot) { SorterFunction(); - + } } void findMatchingAmount() diff --git a/projects/mtg/include/GameApp.h b/projects/mtg/include/GameApp.h index a8159a94c..60a020410 100644 --- a/projects/mtg/include/GameApp.h +++ b/projects/mtg/include/GameApp.h @@ -24,19 +24,10 @@ #ifdef NETWORK_SUPPORT #include "JNetwork.h" #endif //NETWORK_SUPPORT - +#include "GameObserver.h" class Rules; -enum -{ - PLAYER_TYPE_CPU = 0, - PLAYER_TYPE_HUMAN = 1, - PLAYER_TYPE_TESTSUITE = 2, - PLAYER_TYPE_CPU_TEST = 3, -#ifdef NETWORK_SUPPORT - PLAYER_TYPE_REMOTE = 4 -#endif //NETWORK_SUPPORT -}; + class MTGAllCards; class TransitionBase; @@ -88,7 +79,7 @@ public: static string currentMusicFile; static void playMusic(string filename = "", bool loop = true); static void stopMusic(); - static int players[2]; + static PlayerType players[2]; }; diff --git a/projects/mtg/include/GameObserver.h b/projects/mtg/include/GameObserver.h index 1df7d7743..ed014a7e4 100644 --- a/projects/mtg/include/GameObserver.h +++ b/projects/mtg/include/GameObserver.h @@ -20,6 +20,7 @@ struct CardGui; class Player; class TargetChooser; class Rules; +class TestSuite; using namespace std; class GameObserver{ @@ -41,8 +42,9 @@ class GameObserver{ void logAction(const string& s); bool processActions(bool undo); friend ostream& operator<<(ostream&, GameObserver&); - bool load(const string& s, bool undo); bool mLoading; + void nextGamePhase(); + void shuffleLibrary(Player* p); public: int currentPlayerId; @@ -74,11 +76,15 @@ class GameObserver{ const char * getCurrentGamePhaseName(); const char * getNextGamePhaseName(); void nextCombatStep(); - void userRequestNextGamePhase(); - void nextGamePhase(); + void userRequestNextGamePhase(bool allowInterrupt = true, bool log = true); void cleanupPhase(); void nextPlayer(); void setPlayers(vector _players); + +#ifdef TESTSUITE + void loadTestSuitePlayer(int playerId, TestSuite* testSuite); +#endif //TESTSUITE + void loadPlayer(int playerId, PlayerType playerType = PLAYER_TYPE_HUMAN, int decknb=0, bool premadeDeck=false); Player * currentPlayer; Player * currentActionPlayer; Player * isInterrupting; @@ -111,8 +117,12 @@ class GameObserver{ logAction(players[playerId], s); }; void logAction(MTGCardInstance* card, MTGGameZone* zone, size_t index, int result); + bool load(const string& s, bool undo = false); bool undo(); bool isLoading(){ return mLoading; }; + void Mulligan(Player* player = NULL); + Player* getPlayer(size_t index) { return players[index];}; + bool isStarted() { return (mLayers!=NULL);}; }; #endif diff --git a/projects/mtg/include/GameStateDuel.h b/projects/mtg/include/GameStateDuel.h index 05d04dec8..32130f22f 100644 --- a/projects/mtg/include/GameStateDuel.h +++ b/projects/mtg/include/GameStateDuel.h @@ -28,7 +28,6 @@ private: Credits * credits; int mGamePhase; Player * mCurrentPlayer; - vector mPlayers; GameObserver * game; DeckMenu * deckmenu; DeckMenu * opponentMenu; @@ -42,7 +41,6 @@ private: string musictrack; bool MusicExist(string FileName); - void loadPlayer(int playerId, int decknb = 0, bool isAI = false, bool isNetwork = false); void ConstructOpponentMenu(); //loads the opponentMenu if it doesn't exist void initScroller(); void setGamePhase(int newGamePhase); @@ -79,9 +77,12 @@ public: MENUITEM_EVIL_TWIN = kEvilTwinMenuID, MENUITEM_MULLIGAN = -15, MENUITEM_UNDO = -16, +#ifdef TESTSUITE + MENUITEM_LOAD = -17, +#endif #ifdef NETWORK_SUPPORT - MENUITEM_REMOTE_CLIENT = -17, - MENUITEM_REMOTE_SERVER = -18, + MENUITEM_REMOTE_CLIENT = -18, + MENUITEM_REMOTE_SERVER = -19, #endif MENUITEM_MORE_INFO = kInfoMenuID }; diff --git a/projects/mtg/include/MTGAbility.h b/projects/mtg/include/MTGAbility.h index 4ff4f515a..b11624862 100644 --- a/projects/mtg/include/MTGAbility.h +++ b/projects/mtg/include/MTGAbility.h @@ -293,7 +293,7 @@ public: { counters = 0; } - return MTGAbility::Update(dt); + MTGAbility::Update(dt); } virtual int reactToClick(MTGCardInstance * card); virtual int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL); diff --git a/projects/mtg/include/MTGDefinitions.h b/projects/mtg/include/MTGDefinitions.h index 21bb97d6a..65fc886e7 100644 --- a/projects/mtg/include/MTGDefinitions.h +++ b/projects/mtg/include/MTGDefinitions.h @@ -24,6 +24,17 @@ typedef enum #endif //NETWORK_SUPPORT } GameType; +typedef enum +{ + PLAYER_TYPE_CPU = 0, + PLAYER_TYPE_HUMAN = 1, + PLAYER_TYPE_TESTSUITE = 2, + PLAYER_TYPE_CPU_TEST = 3, +#ifdef NETWORK_SUPPORT + PLAYER_TYPE_REMOTE = 4 +#endif //NETWORK_SUPPORT +} PlayerType; + class Constants { public: diff --git a/projects/mtg/include/MTGGameZones.h b/projects/mtg/include/MTGGameZones.h index ac03616a7..b95a43e5c 100644 --- a/projects/mtg/include/MTGGameZones.h +++ b/projects/mtg/include/MTGGameZones.h @@ -120,85 +120,85 @@ class MTGGameZone { }; class MTGLibrary: public MTGGameZone { - public: - virtual ostream& toString(ostream&) const; - const char * getName(){return "library";} +public: + virtual ostream& toString(ostream&) const; + const char * getName(){return "library";} }; class MTGGraveyard: public MTGGameZone { - public: - virtual ostream& toString(ostream&) const; - const char * getName(){return "graveyard";} +public: + virtual ostream& toString(ostream&) const; + const char * getName(){return "graveyard";} }; class MTGHand: public MTGGameZone { - public: - virtual ostream& toString(ostream&) const; - const char * getName(){return "hand";} +public: + virtual ostream& toString(ostream&) const; + const char * getName(){return "hand";} }; class MTGRemovedFromGame: public MTGGameZone { - public: - virtual ostream& toString(ostream&) const; - const char * getName(){return "exile";} +public: + virtual ostream& toString(ostream&) const; + const char * getName(){return "exile";} }; class MTGStack: public MTGGameZone { - public: - virtual ostream& toString(ostream&) const; - const char * getName(){return "stack";} +public: + virtual ostream& toString(ostream&) const; + const char * getName(){return "stack";} }; class MTGInPlay: public MTGGameZone { - public: - void untapAll(); - MTGCardInstance * getNextAttacker(MTGCardInstance * previous); - virtual ostream& toString(ostream&) const; - const char * getName(){return "battlefield";} +public: + void untapAll(); + MTGCardInstance * getNextAttacker(MTGCardInstance * previous); + virtual ostream& toString(ostream&) const; + const char * getName(){return "battlefield";} }; class MTGPlayerCards { - protected: - void init(); +protected: + void init(); public: Player * owner; PlayRestrictions * playRestrictions; - MTGLibrary * library; - MTGGraveyard * graveyard; - MTGHand * hand; - MTGInPlay * inPlay; - MTGInPlay * battlefield; //alias to inPlay + MTGLibrary * library; + MTGGraveyard * graveyard; + MTGHand * hand; + MTGInPlay * inPlay; + MTGInPlay * battlefield; //alias to inPlay - MTGStack * stack; - MTGRemovedFromGame * removedFromGame; - MTGRemovedFromGame * exile; //alias to removedFromZone - MTGGameZone * garbage; - MTGGameZone * temp; + MTGStack * stack; + MTGRemovedFromGame * removedFromGame; + MTGRemovedFromGame * exile; //alias to removedFromZone + MTGGameZone * garbage; + MTGGameZone * temp; - MTGPlayerCards(); - MTGPlayerCards(Player*, int * idList, int idListSize); - MTGPlayerCards(MTGDeck * deck); - ~MTGPlayerCards(); - void initGame(int shuffle = 1, int draw = 1); - void OptimizedHand(Player * who,int amount = 7,int lands = 3,int creatures = 0,int othercards = 4); - void setOwner(Player * player); - void discardRandom(MTGGameZone * from,MTGCardInstance * source); - void drawFromLibrary(); - void showHand(); - void resetLibrary(); - void initDeck(MTGDeck * deck); - void beforeBeginPhase(); - MTGCardInstance * putInGraveyard(MTGCardInstance * card); - MTGCardInstance * putInExile(MTGCardInstance * card); - MTGCardInstance * putInLibrary(MTGCardInstance * card); - MTGCardInstance * putInHand(MTGCardInstance * card); - MTGCardInstance * putInZone(MTGCardInstance * card, MTGGameZone * from, MTGGameZone * to); - int isInPlay(MTGCardInstance * card); - int isInGrave(MTGCardInstance * card); - int isInZone(MTGCardInstance * card,MTGGameZone * zone); - bool parseLine(const string& s); + MTGPlayerCards(); + MTGPlayerCards(Player*, int * idList, int idListSize); + MTGPlayerCards(MTGDeck * deck); + ~MTGPlayerCards(); + void initGame(int shuffle = 1, int draw = 1); + void OptimizedHand(Player * who,int amount = 7,int lands = 3,int creatures = 0,int othercards = 4); + void setOwner(Player * player); + void discardRandom(MTGGameZone * from,MTGCardInstance * source); + void drawFromLibrary(); + void showHand(); + void resetLibrary(); + void initDeck(MTGDeck * deck); + void beforeBeginPhase(); + MTGCardInstance * putInGraveyard(MTGCardInstance * card); + MTGCardInstance * putInExile(MTGCardInstance * card); + MTGCardInstance * putInLibrary(MTGCardInstance * card); + MTGCardInstance * putInHand(MTGCardInstance * card); + MTGCardInstance * putInZone(MTGCardInstance * card, MTGGameZone * from, MTGGameZone * to); + int isInPlay(MTGCardInstance * card); + int isInGrave(MTGCardInstance * card); + int isInZone(MTGCardInstance * card,MTGGameZone * zone); + bool parseLine(const string& s); }; ostream& operator<<(ostream&, const MTGGameZone&); diff --git a/projects/mtg/include/Player.h b/projects/mtg/include/Player.h index d63b02c4d..c5cb4bd42 100644 --- a/projects/mtg/include/Player.h +++ b/projects/mtg/include/Player.h @@ -101,8 +101,14 @@ public: class HumanPlayer: public Player { +protected: + bool premade; public: - HumanPlayer(GameObserver *observer, string deckFile, string deckFileSmall, MTGDeck * deck = NULL); + HumanPlayer(GameObserver *observer, string deckFile, string deckFileSmall, bool premade = false, MTGDeck * deck = NULL); + void End(){ + if(!premade && opponent()) + DeckStats::GetInstance()->saveStats(this, opponent(), observer); + }; }; #endif diff --git a/projects/mtg/include/utils.h b/projects/mtg/include/utils.h index 639a79362..f2ef9ba54 100644 --- a/projects/mtg/include/utils.h +++ b/projects/mtg/include/utils.h @@ -66,7 +66,7 @@ unsigned long hash_djb2(const char *str); void loadRandValues(string s); ostream& saveRandValues(ostream& out); int filesize(const char * filename); -int WRand(); +int WRand(bool log = false); ptrdiff_t MRand (ptrdiff_t i); #ifdef LINUX diff --git a/projects/mtg/src/AIPlayer.cpp b/projects/mtg/src/AIPlayer.cpp index b66478d7e..2f03053fa 100644 --- a/projects/mtg/src/AIPlayer.cpp +++ b/projects/mtg/src/AIPlayer.cpp @@ -97,7 +97,7 @@ int AIAction::clickMultiAct(vector& actionTargets) actionTargets.erase(actionTargets.begin() + f); } } - std::random_shuffle(actionTargets.begin(), actionTargets.end(), MRand); + std::random_shuffle(actionTargets.begin(), actionTargets.end()); //shuffle to make it less predictable, otherwise ai will always seem to target from right to left. making it very obvious. for(int k = 0;k < int(actionTargets.size());k++) { @@ -172,7 +172,7 @@ int AIPlayer::clickMultiTarget(TargetChooser * tc, vector& potentia potentialTargets.erase(potentialTargets.begin() + f); } } - std::random_shuffle(potentialTargets.begin(), potentialTargets.end(), MRand); + std::random_shuffle(potentialTargets.begin(), potentialTargets.end()); if(potentialTargets.size()) clickstream.push(NEW AIAction(this, NULL,tc->source,potentialTargets)); while(clickstream.size()) diff --git a/projects/mtg/src/AIPlayerBaka.cpp b/projects/mtg/src/AIPlayerBaka.cpp index c424aa6f9..e578e5482 100644 --- a/projects/mtg/src/AIPlayerBaka.cpp +++ b/projects/mtg/src/AIPlayerBaka.cpp @@ -1751,10 +1751,7 @@ int AIPlayerBaka::computeActions() int doThis = selectMenuOption(); if(doThis >= 0) { - if(object->abilitiesMenu->isMultipleChoice) - observer->mLayers->actionLayer()->doMultipleChoice(doThis); - else - observer->mLayers->actionLayer()->doReactTo(doThis); + observer->mLayers->actionLayer()->ButtonPressed(0, doThis); } else if(doThis < 0 || object->checkCantCancel()) observer->mLayers->actionLayer()->doReactTo(object->abilitiesMenu->mObjects.size()-1); diff --git a/projects/mtg/src/AbilityParser.cpp b/projects/mtg/src/AbilityParser.cpp index 0a84f561a..057b1fa4d 100644 --- a/projects/mtg/src/AbilityParser.cpp +++ b/projects/mtg/src/AbilityParser.cpp @@ -124,4 +124,4 @@ string AutoLineMacro::Process(const string& s) result = gAutoLineMacros[i]->process(result); } return result; -} \ No newline at end of file +} diff --git a/projects/mtg/src/ActionLayer.cpp b/projects/mtg/src/ActionLayer.cpp index 9ecfb682c..d778bfbc9 100644 --- a/projects/mtg/src/ActionLayer.cpp +++ b/projects/mtg/src/ActionLayer.cpp @@ -407,17 +407,12 @@ void ActionLayer::doReactTo(int menuIndex) } } -void ActionLayer::doMultipleChoice(int choice) -{ - if (menuObject) - { - DebugTrace("ActionLayer::doReactToChoice " << choice); - ButtonPressedOnMultipleChoice(choice); - } -} - void ActionLayer::ButtonPressed(int controllerid, int controlid) { + stringstream stream; + stream << "choice " << controlid; + observer->logAction(observer->currentActionPlayer, stream.str()); + if(this->abilitiesMenu && this->abilitiesMenu->isMultipleChoice) { return ButtonPressedOnMultipleChoice(); @@ -430,7 +425,7 @@ void ActionLayer::ButtonPressed(int controllerid, int controlid) } else if (controlid == kCancelMenuID) { - observer->mLayers->stackLayer()->endOfInterruption(); + observer->mLayers->stackLayer()->endOfInterruption(false); menuObject = 0; } else @@ -464,7 +459,7 @@ void ActionLayer::ButtonPressedOnMultipleChoice(int choice) } else if (currentMenuObject == kCancelMenuID) { - observer->mLayers->stackLayer()->endOfInterruption(); + observer->mLayers->stackLayer()->endOfInterruption(false); } menuObject = 0; } diff --git a/projects/mtg/src/ActionStack.cpp b/projects/mtg/src/ActionStack.cpp index c9fce6087..9e1995aac 100644 --- a/projects/mtg/src/ActionStack.cpp +++ b/projects/mtg/src/ActionStack.cpp @@ -34,7 +34,7 @@ NextGamePhase requested by user */ int NextGamePhase::resolve() { - observer->nextGamePhase(); + observer->userRequestNextGamePhase(false, false); return 1; } @@ -568,7 +568,7 @@ int ActionStack::AddNextCombatStep() return 1; } -int ActionStack::setIsInterrupting(Player * player) +int ActionStack::setIsInterrupting(Player * player, bool log) { askIfWishesToInterrupt = NULL; @@ -589,7 +589,8 @@ int ActionStack::setIsInterrupting(Player * player) int playerId = (player == observer->players[1]) ? 1 : 0; interruptDecision[playerId] = -1; observer->isInterrupting = player; - observer->logAction(player, "yes"); + if(log) + observer->logAction(player, "yes"); return 1; } @@ -826,7 +827,6 @@ int ActionStack::receiveEventPlus(WEvent * event) void ActionStack::Update(float dt) { - //This is a hack to avoid updating the stack while tuto messages are being shown //Ideally, the tuto messages should be moved to a layer above this one if (ATutorialMessage::Current) @@ -845,6 +845,7 @@ void ActionStack::Update(float dt) if (mode == ACTIONSTACK_STANDARD && tc && !checked) { checked = 1; + for (size_t i = 0; i < mObjects.size(); i++) { Interruptible * current = (Interruptible *) mObjects[i]; @@ -946,7 +947,7 @@ void ActionStack::Update(float dt) extraTime = 1;//we never want this int to be 0. if (timer < 0) - timer = static_cast(options[Options::INTERRUPT_SECONDS].number * extraTime); + timer = static_cast(options[Options::INTERRUPT_SECONDS].number * extraTime); timer -= dt; if (timer < 0) cancelInterruptOffer(); @@ -964,12 +965,13 @@ void ActionStack::cancelInterruptOffer(int cancelMode) observer->logAction(playerId, "no"); } -void ActionStack::endOfInterruption() +void ActionStack::endOfInterruption(bool log) { int playerId = (observer->isInterrupting == observer->players[1]) ? 1 : 0; interruptDecision[playerId] = 0; observer->isInterrupting = NULL; - observer->logAction(playerId, "endinterruption"); + if(log) + observer->logAction(playerId, "endinterruption"); } bool ActionStack::CheckUserInput(JButton key) diff --git a/projects/mtg/src/AllAbilities.cpp b/projects/mtg/src/AllAbilities.cpp index 8255994fb..b6fb91e20 100644 --- a/projects/mtg/src/AllAbilities.cpp +++ b/projects/mtg/src/AllAbilities.cpp @@ -2219,7 +2219,7 @@ void MayAbility::Update(float dt) } game->mLayers->actionLayer()->setMenuObject(source, must); previousInterrupter = game->isInterrupting; - game->mLayers->stackLayer()->setIsInterrupting(source->controller()); + game->mLayers->stackLayer()->setIsInterrupting(source->controller(), false); } } @@ -3669,7 +3669,7 @@ void ABlink::Update(float dt) MTGGameZone * inplay = spell->source->owner->game->inPlay; spell->source->target = NULL; - for(int i = WRand()%inplay->nb_cards;;i = WRand()%inplay->nb_cards) + for(int i = WRand(true)%inplay->nb_cards;;i = WRand(true)%inplay->nb_cards) { if(tc->canTarget(inplay->cards[i]) && spell->source->target == NULL) { @@ -3768,7 +3768,7 @@ void ABlink::resolveBlink() MTGGameZone * inplay = spell->source->owner->game->inPlay; spell->source->target = NULL; - for(int i = WRand()%inplay->nb_cards;;i = WRand()%inplay->nb_cards) + for(int i = WRand(true)%inplay->nb_cards;;i = WRand(true)%inplay->nb_cards) { if(tc->canTarget(inplay->cards[i]) && spell->source->target == NULL) { diff --git a/projects/mtg/src/CardDisplay.cpp b/projects/mtg/src/CardDisplay.cpp index 766befab3..4377961b7 100644 --- a/projects/mtg/src/CardDisplay.cpp +++ b/projects/mtg/src/CardDisplay.cpp @@ -92,7 +92,8 @@ void CardDisplay::Update(float dt) } } PlayGuiObjectController::Update(dt); - if (update) init(zone); + if (update) + init(zone); } bool CardDisplay::CheckUserInput(JButton key) diff --git a/projects/mtg/src/DeckMenu.cpp b/projects/mtg/src/DeckMenu.cpp index 9439046b1..181b0870c 100644 --- a/projects/mtg/src/DeckMenu.cpp +++ b/projects/mtg/src/DeckMenu.cpp @@ -338,7 +338,7 @@ void DeckMenu::Update(float dt) timeOpen += dt * 10; } if (mScroller) - mScroller->Update(dt); + mScroller->Update(dt); } void DeckMenu::Add(int id, const char * text, string desc, bool forceFocus, DeckMetaData * deckMetaData) diff --git a/projects/mtg/src/DuelLayers.cpp b/projects/mtg/src/DuelLayers.cpp index 9e55daef3..a37eafaa5 100644 --- a/projects/mtg/src/DuelLayers.cpp +++ b/projects/mtg/src/DuelLayers.cpp @@ -78,6 +78,7 @@ void DuelLayers::Update(float dt, Player * currentPlayer) { for (int i = 0; i < nbitems; ++i) objects[i]->Update(dt); + int isAI = currentPlayer->isAI(); if (isAI && !currentPlayer->getObserver()->isLoading()) currentPlayer->Act(dt); diff --git a/projects/mtg/src/GameApp.cpp b/projects/mtg/src/GameApp.cpp index 53ac8eb32..454803c77 100644 --- a/projects/mtg/src/GameApp.cpp +++ b/projects/mtg/src/GameApp.cpp @@ -34,7 +34,7 @@ #define DEFAULT_DURATION .25 -int GameApp::players[] = { 0, 0 }; +PlayerType GameApp::players[] = { PLAYER_TYPE_CPU, PLAYER_TYPE_CPU }; bool GameApp::HasMusic = true; JMusic * GameApp::music = NULL; string GameApp::currentMusicFile = ""; @@ -69,8 +69,8 @@ GameApp::GameApp() : mGameStates[i] = NULL; mShowDebugInfo = false; - players[0] = 0; - players[1] = 0; + players[0] = PLAYER_TYPE_CPU; + players[1] = PLAYER_TYPE_CPU; gameType = GAME_TYPE_CLASSIC; mCurrentState = NULL; diff --git a/projects/mtg/src/GameObserver.cpp b/projects/mtg/src/GameObserver.cpp index afd5be033..df620f4bb 100644 --- a/projects/mtg/src/GameObserver.cpp +++ b/projects/mtg/src/GameObserver.cpp @@ -12,6 +12,9 @@ #include "GuiPhaseBar.h" #include "AIPlayerBaka.h" #include "MTGRules.h" +#ifdef TESTSUITE +#include "TestSuiteAI.h" +#endif void GameObserver::initialize() { @@ -31,6 +34,7 @@ void GameObserver::initialize() mRules = NULL; connectRule = false; mLoading = false; + mLayers = NULL; } void GameObserver::cleanup() @@ -59,11 +63,16 @@ void GameObserver::cleanup() combatStep = BLOCKERS; connectRule = false; actionsList.clear(); + } GameObserver::~GameObserver() { LOG("==Destroying GameObserver=="); + for (size_t i = 0; i < players.size(); ++i) + { + players[i]->End(); + } SAFE_DELETE(targetChooser); SAFE_DELETE(mLayers); SAFE_DELETE(phaseRing); @@ -243,17 +252,21 @@ void GameObserver::nextCombatStep() } } -void GameObserver::userRequestNextGamePhase() +void GameObserver::userRequestNextGamePhase(bool allowInterrupt, bool log) { - stringstream stream; - stream << "next " << currentGamePhase; + if(log) { + stringstream stream; + stream << "next " << allowInterrupt << " " <maxtargets == 1000) { getCurrentTargetChooser()->done = true; if(getCurrentTargetChooser()->source) cardClick(getCurrentTargetChooser()->source); } - if (mLayers->stackLayer()->getNext(NULL, 0, NOT_RESOLVED)) + if (allowInterrupt && mLayers->stackLayer()->getNext(NULL, 0, NOT_RESOLVED)) return; if (getCurrentTargetChooser()) return; @@ -266,13 +279,13 @@ void GameObserver::userRequestNextGamePhase() return; Phase * cPhaseOld = phaseRing->getCurrentPhase(); - if ((cPhaseOld->id == Constants::MTG_PHASE_COMBATBLOCKERS && combatStep == ORDER) + if (allowInterrupt && ((cPhaseOld->id == Constants::MTG_PHASE_COMBATBLOCKERS && combatStep == ORDER) || (cPhaseOld->id == Constants::MTG_PHASE_COMBATBLOCKERS && combatStep == TRIGGERS) || (cPhaseOld->id == Constants::MTG_PHASE_COMBATDAMAGE) || opponent()->isAI() || options[Options::optionInterrupt(currentGamePhase)].number || currentPlayer->offerInterruptOnPhase - 1 == currentGamePhase - ) + )) { mLayers->stackLayer()->AddNextGamePhase(); } @@ -280,11 +293,15 @@ void GameObserver::userRequestNextGamePhase() { nextGamePhase(); } - - stream << " " << currentGamePhase ; - logAction(currentPlayer, stream.str()); } +void GameObserver::shuffleLibrary(Player* p) +{ + logAction(p, "shufflelib"); + p->game->library->shuffle(); +} + + int GameObserver::forceShuffleLibraries() { int result = 0; @@ -292,7 +309,7 @@ int GameObserver::forceShuffleLibraries() { if (players[i]->game->library->needShuffle) { - players[i]->game->library->shuffle(); + shuffleLibrary(players[i]); players[i]->game->library->needShuffle = false; ++result; } @@ -322,6 +339,8 @@ void GameObserver::startGame(GameType gtype, Rules * rules) stringstream stream; stream << *this; startupGameSerialized = stream.str(); + DebugTrace("startGame\n"); + DebugTrace(startupGameSerialized); if (rules) rules->initGame(this); @@ -407,6 +426,7 @@ bool GameObserver::removeObserver(ActionElement * observer) void GameObserver::Update(float dt) { + Player * player = currentPlayer; if (Constants::MTG_PHASE_COMBATBLOCKERS == currentGamePhase && BLOCKERS == combatStep) { @@ -422,13 +442,15 @@ void GameObserver::Update(float dt) currentActionPlayer = player; if (isInterrupting) player = isInterrupting; - mLayers->Update(dt, player); - while (mLayers->actionLayer()->stuffHappened) + if(mLayers) { - mLayers->actionLayer()->Update(0); + mLayers->Update(dt, player); + while (mLayers->actionLayer()->stuffHappened) + { + mLayers->actionLayer()->Update(0); + } + gameStateBasedEffects(); } - - gameStateBasedEffects(); oldGamePhase = currentGamePhase; } @@ -703,7 +725,7 @@ void GameObserver::gameStateBasedEffects() } //Auto skip Phases - int skipLevel = (currentPlayer->playMode == Player::MODE_TEST_SUITE) ? Constants::ASKIP_NONE + int skipLevel = (currentPlayer->playMode == Player::MODE_TEST_SUITE || mLoading) ? Constants::ASKIP_NONE : options[Options::ASPHASES].number; int nrCreatures = currentPlayer->game->inPlay->countByType("Creature"); @@ -843,8 +865,9 @@ void GameObserver::Affinity() } void GameObserver::Render() { - mLayers->Render(); - if (targetChooser || mLayers->actionLayer()->isWaitingForAnswer()) + if(mLayers) + mLayers->Render(); + if (targetChooser || (mLayers && mLayers->actionLayer()->isWaitingForAnswer())) JRenderer::GetInstance()->DrawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, ARGB(255,255,0,0)); if (mExtraPayment) mExtraPayment->Render(); @@ -981,7 +1004,6 @@ int GameObserver::cardClick(MTGCardInstance * card, Targetable * object) if (!card) { clickedPlayer = ((Player *) object); - logAction(clickedPlayer); } else { backup = card; zone = card->currentZone; @@ -1135,9 +1157,12 @@ int GameObserver::untap(MTGCardInstance * card) TargetChooser * GameObserver::getCurrentTargetChooser() { - TargetChooser * _tc = mLayers->actionLayer()->getCurrentTargetChooser(); - if (_tc) - return _tc; + if(mLayers) + { + TargetChooser * _tc = mLayers->actionLayer()->getCurrentTargetChooser(); + if (_tc) + return _tc; + } return targetChooser; } @@ -1298,10 +1323,11 @@ bool GameObserver::load(const string& ss, bool undo) int state = -1; string s; stringstream stream(ss); - string deckFile = players[0]->deckFile; - string deckFileSmall = players[0]->deckFileSmall; + string deckFile = "";//players[0]->deckFile; + string deckFileSmall = "";//players[0]->deckFileSmall; DebugTrace("Loading " + ss); + loadRandValues(""); cleanup(); @@ -1374,9 +1400,16 @@ bool GameObserver::load(const string& ss, bool undo) phaseRing = NEW PhaseRing(this); startedAt = time(0); + // take a snapshot before processing the actions + startupGameSerialized = ""; + stringstream stream; + stream << *this; + startupGameSerialized = stream.str(); + mRules->initGame(this); phaseRing->goToPhase(0, currentPlayer, false); phaseRing->goToPhase(currentGamePhase, currentPlayer); + processActions(undo); } else @@ -1393,6 +1426,7 @@ bool GameObserver::load(const string& ss, bool undo) bool GameObserver::processActions(bool undo) { bool result = false; + size_t cmdIndex = 0; loadingList = actionsList; actionsList.clear(); @@ -1404,15 +1438,24 @@ bool GameObserver::processActions(bool undo) if(undo && loadingList.size()) { while(loadingList.back().find("p2") != string::npos) loadingList.pop_back(); - loadingList.pop_back(); + // we do not undo "next phase" action to avoid abuse by users + if(loadingList.back().find("next") == string::npos) + loadingList.pop_back(); } - for(loadingite = loadingList.begin(); loadingite != loadingList.end(); loadingite++) + for(loadingite = loadingList.begin(); loadingite != loadingList.end(); loadingite++, cmdIndex++) { string s = *loadingite; Player* p = players[1]; if (s.find("p1") != string::npos) p = players[0]; + for (int i = 0; i<5; i++) + { + // let's fake an update + Update(counter); + counter += 1.000f; + } + MTGGameZone* zone = NULL; if(s.find(p->game->hand->getName()) != string::npos) zone = p->game->hand; @@ -1439,19 +1482,31 @@ bool GameObserver::processActions(bool undo) userRequestNextGamePhase(); } else if (s.find("choice") != string::npos) { int choice = atoi(s.substr(s.find("choice ") + 7).c_str()); - mLayers->actionLayer()->doReactTo(choice); + //menuSelect(choice); + mLayers->actionLayer()->ButtonPressed(0, choice); } else if (s == "p1" || s == "p2") { cardClick(NULL, p); + } else if(s.find("mulligan") != string::npos) { + Mulligan(p); + } else if(s.find("shufflelib") != string::npos) { + // This should probably be differently and be automatically part of the ability triggered + // that would allow the AI to use it as well. + shuffleLibrary(p); } else { assert(0); } - for (int i = 0; i<10; i++) + size_t nb = actionsList.size(); + + for (int i = 0; i<5; i++) { // let's fake an update Update(counter); counter += 1.000f; } + assert(actionsList.back() == *loadingite); + assert(nb == actionsList.size()); + assert(cmdIndex == (actionsList.size()-1)); } mLoading = false; @@ -1485,8 +1540,7 @@ void GameObserver::logAction(const string& s) if(mLoading) { string toCheck = *loadingite; - if(toCheck != s) - assert(0); + assert(toCheck == s); } actionsList.push_back(s); }; @@ -1498,3 +1552,80 @@ bool GameObserver::undo() DebugTrace(stream.str()); return load(stream.str(), true); } + +void GameObserver::Mulligan(Player* player) +{ + if(!player) player = currentPlayer; + logAction(player, "mulligan"); + player->takeMulligan(); +} + +#ifdef TESTSUITE +void GameObserver::loadTestSuitePlayer(int playerId, TestSuite* testSuite) +{ + players.push_back(new TestSuiteAI(this, testSuite, playerId)); +} +#endif //TESTSUITE + +void GameObserver::loadPlayer(int playerId, PlayerType playerType, int decknb, bool premadeDeck) +{ + if (decknb) + { + if (playerType == PLAYER_TYPE_HUMAN) + { //Human Player + if(playerId == 0) + { + char deckFile[255]; + if (premadeDeck) + sprintf(deckFile, "player/premade/deck%i.txt", decknb); + else + sprintf(deckFile, "%s/deck%i.txt", options.profileFile().c_str(), decknb); + char deckFileSmall[255]; + sprintf(deckFileSmall, "player_deck%i", decknb); + players.push_back(NEW HumanPlayer(this, deckFile, deckFileSmall)); +#ifdef NETWORK_SUPPORT + // FIXME, this is broken + if(isNetwork) + { + ProxyPlayer* mProxy; + mProxy = NEW ProxyPlayer(mPlayers[playerId], mParent->mpNetwork); + } + } + else + { //Remote player + mPlayers.push_back(NEW RemotePlayer(mParent->mpNetwork)); +#endif //NETWORK_SUPPORT + } + } + else + { //AI Player, chooses deck + AIPlayerFactory playerCreator; + Player * opponent = NULL; + if (playerId == 1) opponent = players[0]; + players.push_back(playerCreator.createAIPlayer(this, MTGCollection(), opponent, decknb)); + } + } + else + { + //Random deck + AIPlayerFactory playerCreator; + Player * opponent = NULL; + + // Reset the random logging. + loadRandValues(""); + + if (playerId == 1) opponent = players[0]; +#ifdef AI_CHANGE_TESTING + if (playerType == PLAYER_TYPE_CPU_TEST) + players.push_back(playerCreator.createAIPlayerTest(this, MTGCollection(), opponent, playerId == 0 ? "ai/bakaA/" : "ai/bakaB/")); + else +#endif + { + players.push_back(playerCreator.createAIPlayer(this, MTGCollection(), opponent)); + } + + if (playerType == PLAYER_TYPE_CPU_TEST) + ((AIPlayer *) players[playerId])->setFastTimerMode(); + } +} + diff --git a/projects/mtg/src/GameStateDuel.cpp b/projects/mtg/src/GameStateDuel.cpp index b493f3c7c..c093a61fd 100644 --- a/projects/mtg/src/GameStateDuel.cpp +++ b/projects/mtg/src/GameStateDuel.cpp @@ -67,7 +67,6 @@ int GameStateDuel::selectedAIDeckId = 0; GameStateDuel::GameStateDuel(GameApp* parent) : GameState(parent, "duel") { - mPlayers.clear(); premadeDeck = false; game = NULL; deckmenu = NULL; @@ -120,6 +119,8 @@ void GameStateDuel::Start() renderer->EnableVSync(true); OpponentsDeckid = 0; + game = NEW GameObserver(); + #ifdef TESTSUITE SAFE_DELETE(testSuite); testSuite = NEW TestSuite("test/_tests.txt"); @@ -184,64 +185,6 @@ void GameStateDuel::Start() } deckmenu->Add(MENUITEM_CANCEL, "Main Menu", "Return to Main Menu"); } - - mPlayers.clear(); -} - -void GameStateDuel::loadPlayer(int playerId, int decknb, bool isAI, bool isNetwork) -{ - if (decknb) - { - if (!isAI) - { //Human Player - if(playerId == 0) - { - char deckFile[255]; - if (premadeDeck) - sprintf(deckFile, "player/premade/deck%i.txt", decknb); - else - sprintf(deckFile, "%s/deck%i.txt", options.profileFile().c_str(), decknb); - char deckFileSmall[255]; - sprintf(deckFileSmall, "player_deck%i", decknb); - mPlayers.push_back(NEW HumanPlayer(game, deckFile, deckFileSmall)); -#ifdef NETWORK_SUPPORT - if(isNetwork) - { - ProxyPlayer* mProxy; - mProxy = NEW ProxyPlayer(mPlayers[playerId], mParent->mpNetwork); - } - } - else - { //Remote player - mPlayers.push_back(NEW RemotePlayer(mParent->mpNetwork)); -#endif //NETWORK_SUPPORT - } - } - else - { //AI Player, chooses deck - AIPlayerFactory playerCreator; - Player * opponent = NULL; - if (playerId == 1) opponent = mPlayers[0]; - mPlayers.push_back(playerCreator.createAIPlayer(game, MTGCollection(), opponent, decknb)); - } - } - else - { //Random deck - AIPlayerFactory playerCreator; - Player * opponent = NULL; - if (playerId == 1) opponent = mPlayers[0]; -#ifdef AI_CHANGE_TESTING - if (mParent->players[0] == PLAYER_TYPE_CPU_TEST) - mPlayers.push_back(playerCreator.createAIPlayerTest(game, MTGCollection(), opponent, playerId == 0 ? "ai/bakaA/" : "ai/bakaB/")); - else -#endif - { - mPlayers.push_back(playerCreator.createAIPlayer(game, MTGCollection(), opponent)); - } - - if (mParent->players[playerId] == PLAYER_TYPE_CPU_TEST) - ((AIPlayer *) mPlayers[playerId])->setFastTimerMode(); - } } void GameStateDuel::initRand(unsigned int seed) @@ -258,12 +201,10 @@ void GameStateDuel::loadTestSuitePlayers() initRand(testSuite->seed); SAFE_DELETE(game); game = new GameObserver(); - mPlayers.clear(); for (int i = 0; i < 2; i++) { - mPlayers.push_back(new TestSuiteAI(game, testSuite, i)); + game->loadTestSuitePlayer(i, testSuite); } - game->setPlayers(mPlayers); mParent->gameType = testSuite->gameType; game->startGame(mParent->gameType, mParent->rules); @@ -279,22 +220,9 @@ void GameStateDuel::End() #endif JRenderer::GetInstance()->EnableVSync(false); - if (!premadeDeck && mPlayers.size() > 1 && mPlayers[0] && mPlayers[1]) - { // save the stats for the game - mPlayers[0]->End(); - } - else if (mPlayers.size() && mPlayers.size() == 1 && mPlayers[0] ) - // clean up player object - SAFE_DELETE( mPlayers[0] ); SAFE_DELETE(game); premadeDeck = false; - if(mPlayers.size()) - for (size_t i = 0; i < mPlayers.size(); i++) - { - mPlayers[i] = NULL; - } - mPlayers.clear(); SAFE_DELETE(credits); SAFE_DELETE(menu); @@ -325,7 +253,7 @@ void GameStateDuel::ConstructOpponentMenu() DeckManager * deckManager = DeckManager::GetInstance(); vector opponentDeckList; int nbUnlockedDecks = options[Options::CHEATMODEAIDECK].number ? 1000 : options[Options::AIDECKS_UNLOCKED].number; - opponentDeckList = fillDeckMenu(opponentMenu, "ai/baka", "ai_baka", mPlayers[0], nbUnlockedDecks); + opponentDeckList = fillDeckMenu(opponentMenu, "ai/baka", "ai_baka", game->getPlayer(0), nbUnlockedDecks); deckManager->updateMetaDataList(&opponentDeckList, true); opponentMenu->Add(MENUITEM_CANCEL, "Cancel", _("Choose a different player deck").c_str()); opponentDeckList.clear(); @@ -393,7 +321,7 @@ void GameStateDuel::Update(float dt) } else { - loadPlayer(0); + game->loadPlayer(0, mParent->players[0]); setGamePhase(DUEL_STATE_CHOOSE_DECK2); } } @@ -416,7 +344,7 @@ void GameStateDuel::Update(float dt) } else { - loadPlayer(1); + game->loadPlayer(1, mParent->players[1]); setGamePhase(DUEL_STATE_PLAY); } } @@ -439,9 +367,8 @@ void GameStateDuel::Update(float dt) } break; case DUEL_STATE_PLAY: - if (!game) + if (!game->isStarted()) { - game = new GameObserver(mPlayers); game->startGame(mParent->gameType, mParent->rules); //start of in game music code @@ -523,6 +450,9 @@ void GameStateDuel::Update(float dt) //END almosthumane - mulligan menu->Add(MENUITEM_MAIN_MENU, "Back to main menu"); menu->Add(MENUITEM_UNDO, "Undo"); +#ifdef TESTSUITE + menu->Add(MENUITEM_LOAD, "Load"); +#endif menu->Add(MENUITEM_CANCEL, "Cancel"); } setGamePhase(DUEL_STATE_MENU); @@ -763,7 +693,7 @@ void GameStateDuel::ButtonPressed(int controllerId, int controlId) switch (controlId) { case MENUITEM_RANDOM_AI: - loadPlayer(1); + game->loadPlayer(1, mParent->players[1]); opponentMenu->Close(); setGamePhase(DUEL_STATE_CHOOSE_DECK2_TO_PLAY); break; @@ -803,7 +733,7 @@ void GameStateDuel::ButtonPressed(int controllerId, int controlId) } else if (controlId != MENUITEM_EVIL_TWIN && aiDeckSize > 0) // evil twin deckNumber = deckManager->getAIDeckOrderList()->at(controlId - 1)->getDeckId(); - loadPlayer(1, deckNumber, 1); + game->loadPlayer(1, mParent->players[1], deckNumber, premadeDeck); OpponentsDeckid = deckNumber; opponentMenu->Close(); setGamePhase(DUEL_STATE_CHOOSE_DECK2_TO_PLAY); @@ -817,7 +747,7 @@ void GameStateDuel::ButtonPressed(int controllerId, int controlId) { vector * playerDeckList = deckManager->getPlayerDeckOrderList(); deckNumber = playerDeckList->at(WRand() % (playerDeckList->size()))->getDeckId(); - loadPlayer(0, deckNumber); + game->loadPlayer(0, mParent->players[0], deckNumber, premadeDeck); deckmenu->Close(); setGamePhase(DUEL_STATE_CHOOSE_DECK2_TO_PLAY); break; @@ -860,11 +790,7 @@ void GameStateDuel::ButtonPressed(int controllerId, int controlId) vector * playerDeck = deckManager->getPlayerDeckOrderList(); if (!premadeDeck && controlId > 0) deckNumber = playerDeck->at(controlId - 1)->getDeckId(); - loadPlayer(0, deckNumber, false -#ifdef NETWORK_SUPPORT - ,(mParent->players[1] == PLAYER_TYPE_REMOTE) -#endif //NETWORK_SUPPORT - ); + game->loadPlayer(0, mParent->players[0], deckNumber, premadeDeck); deckmenu->Close(); #ifdef NETWORK_SUPPORT if(mParent->players[1] == PLAYER_TYPE_REMOTE) @@ -880,7 +806,7 @@ void GameStateDuel::ButtonPressed(int controllerId, int controlId) } else { - loadPlayer(1, controlId); + game->loadPlayer(1, mParent->players[1], controlId, premadeDeck); deckmenu->Close(); setGamePhase(DUEL_STATE_CHOOSE_DECK2_TO_PLAY); } @@ -901,7 +827,7 @@ void GameStateDuel::ButtonPressed(int controllerId, int controlId) break; case MENUITEM_MULLIGAN: //almosthumane - mulligan - game->currentPlayer->takeMulligan(); + game->Mulligan(); menu->Close(); setGamePhase(DUEL_STATE_CANCEL); @@ -913,6 +839,19 @@ void GameStateDuel::ButtonPressed(int controllerId, int controlId) setGamePhase(DUEL_STATE_CANCEL); break; } +#ifdef TESTSUITE + case MENUITEM_LOAD: + { + std::string theGame; + if (JFileSystem::GetInstance()->readIntoString("test/game/timetwister.txt", theGame)) + { + game->load(theGame); + } + menu->Close(); + setGamePhase(DUEL_STATE_CANCEL); + break; + } +#endif } } } diff --git a/projects/mtg/src/GuiCombat.cpp b/projects/mtg/src/GuiCombat.cpp index 2801443f3..8b0b17c5f 100644 --- a/projects/mtg/src/GuiCombat.cpp +++ b/projects/mtg/src/GuiCombat.cpp @@ -16,6 +16,13 @@ const float kZoom_level1 = 1.4f; const float kZoom_level2 = 2.2f; const float kZoom_level3 = 2.7f; +struct True: public Exp +{ + static inline bool test(DamagerDamaged* ref, DamagerDamaged* test) + { + return true; + } +}; struct Left: public Exp { static inline bool test(DamagerDamaged* ref, DamagerDamaged* test) @@ -107,7 +114,7 @@ void GuiCombat::validateDamage() observer->nextCombatStep(); break; case DAMAGE: - observer->nextGamePhase(); + observer->userRequestNextGamePhase(false, false); break; default: cout << "COMBAT : Cannot validate damage in this phase" << endl; @@ -168,11 +175,11 @@ bool GuiCombat::clickOK() { case BLOCKERS: case TRIGGERS: - assert(false);//this is an assert for "do i show the screen that lets you select multiple blocker damage assignment. + assert(false);//this is an assert for "do i show the screen that lets you select multiple blocker damage assignment. return false; // that should not happen case ORDER: - observer->nextGamePhase(); + observer->userRequestNextGamePhase(); return true; case FIRST_STRIKE: return false; @@ -192,6 +199,21 @@ bool GuiCombat::CheckUserInput(JButton key) if (NONE == cursor_pos) return false; DamagerDamaged* oldActive = active; +/* This is untested + int x,y; + if(JGE::GetInstance()->GetLeftClickCoordinates(x, y)) + { + DamagerDamaged* old = active; + active = closest (activeAtk->blockers, NULL, static_cast (x), static_cast (y)); + if (old != active) + { + if (old) + old->zoom = kZoom_none; + if (active) + active->zoom = kZoom_level1; + } + } +*/ switch (key) { case JGE_BTN_OK: @@ -608,7 +630,7 @@ int GuiCombat::receiveEventMinus(WEvent* e) step = ORDER; } else - observer->nextGamePhase(); + observer->userRequestNextGamePhase(false, false); return 1; } case FIRST_STRIKE: @@ -631,7 +653,7 @@ int GuiCombat::receiveEventMinus(WEvent* e) if (!observer->currentPlayer->displayStack()) { ((AIPlayer *) observer->currentPlayer)->affectCombatDamages(step); - observer->nextGamePhase(); + observer->userRequestNextGamePhase(false, false); return 1; } for (inner_iterator attacker = attackers.begin(); attacker != attackers.end(); ++attacker) @@ -661,7 +683,7 @@ int GuiCombat::receiveEventMinus(WEvent* e) case END_DAMAGE: step = END_DAMAGE; if (0 == resolve()) - observer->nextGamePhase(); + observer->userRequestNextGamePhase(false, false); return 1; } return 0; diff --git a/projects/mtg/src/IconButton.cpp b/projects/mtg/src/IconButton.cpp index 40de6cabb..944f1e148 100644 --- a/projects/mtg/src/IconButton.cpp +++ b/projects/mtg/src/IconButton.cpp @@ -134,4 +134,4 @@ IconButton::~IconButton() ostream& IconButton::toString(ostream& out) const { return out << "IconButton ::: mHasFocus : " << mHasFocus; -} \ No newline at end of file +} diff --git a/projects/mtg/src/MTGDeck.cpp b/projects/mtg/src/MTGDeck.cpp index 690591a19..6756f195d 100644 --- a/projects/mtg/src/MTGDeck.cpp +++ b/projects/mtg/src/MTGDeck.cpp @@ -344,7 +344,8 @@ int MTGAllCards::load(const char * config_file, const char * set_name, int autol if (!s.size()) continue; if (s.find("#AUTO_DEFINE ") == 0) { - AutoLineMacro::AddMacro(s.substr(13)); + string toAdd = s.substr(13); + AutoLineMacro::AddMacro(toAdd); continue; } diff --git a/projects/mtg/src/MTGGamePhase.cpp b/projects/mtg/src/MTGGamePhase.cpp index e5e86d352..950ca9a42 100644 --- a/projects/mtg/src/MTGGamePhase.cpp +++ b/projects/mtg/src/MTGGamePhase.cpp @@ -17,7 +17,6 @@ MTGGamePhase::MTGGamePhase(GameObserver* g, int id) : void MTGGamePhase::Update(float dt) { - int newState = observer->getCurrentGamePhase(); if (newState != currentState) { @@ -34,9 +33,7 @@ void MTGGamePhase::Update(float dt) { activeState = INACTIVE; animation = 0; - } - } bool MTGGamePhase::NextGamePhase() diff --git a/projects/mtg/src/MTGGameZones.cpp b/projects/mtg/src/MTGGameZones.cpp index a30f3e989..5da13d150 100644 --- a/projects/mtg/src/MTGGameZones.cpp +++ b/projects/mtg/src/MTGGameZones.cpp @@ -390,7 +390,7 @@ void MTGPlayerCards::discardRandom(MTGGameZone * from, MTGCardInstance * source) { if (!from->nb_cards) return; - int r = WRand() % (from->nb_cards); + int r = WRand(true) % (from->nb_cards); WEvent * e = NEW WEventCardDiscard(from->cards[r]); GameObserver * game = owner->getObserver(); game->receiveEvent(e); diff --git a/projects/mtg/src/MTGRules.cpp b/projects/mtg/src/MTGRules.cpp index 3cc55c12d..443a5fdb5 100644 --- a/projects/mtg/src/MTGRules.cpp +++ b/projects/mtg/src/MTGRules.cpp @@ -1517,7 +1517,7 @@ int MTGMomirRule::genRandomCreatureId(int convertedCost) } if (!total_cards) return 0; - int start = (WRand() % total_cards); + int start = (WRand(true) % total_cards); return pool[convertedCost][start]; } @@ -1635,7 +1635,7 @@ int MTGStoneHewerRule::genRandomEquipId(int convertedCost) if (convertedCost >= 20) convertedCost = 19; int total_cards = 0; - int i = (WRand() % int(convertedCost+1));//+1 becuase we want to generate a random "<=" the coverted. + int i = (WRand(true) % int(convertedCost+1));//+1 becuase we want to generate a random "<=" the coverted. while (!total_cards && i >= 0) { total_cards = pool[i].size(); @@ -1644,7 +1644,7 @@ int MTGStoneHewerRule::genRandomEquipId(int convertedCost) } if (!total_cards) return 0; - int start = (WRand() % total_cards); + int start = (WRand(true) % total_cards); return pool[convertedCost][start]; } @@ -1681,7 +1681,7 @@ int MTGHermitRule::receiveEvent(WEvent * event) lands.push_back(temp); } if(lands.size()) - lcard = lands[WRand() % lands.size()]; + lcard = lands[WRand(true) % lands.size()]; if(lcard) { MTGCardInstance * copy = game->currentPlayer->game->putInZone(lcard,game->currentPlayer->game->library, game->currentPlayer->game->temp); diff --git a/projects/mtg/src/Player.cpp b/projects/mtg/src/Player.cpp index 7f959d300..6e95885a3 100644 --- a/projects/mtg/src/Player.cpp +++ b/projects/mtg/src/Player.cpp @@ -110,12 +110,12 @@ JQuadPtr Player::getIcon() Player * Player::opponent() { - if (!observer) return NULL; + if (!observer || (observer->players.size() < 2 )) return NULL; return this == observer->players[0] ? observer->players[1] : observer->players[0]; } -HumanPlayer::HumanPlayer(GameObserver *observer, string file, string fileSmall, MTGDeck * deck) : - Player(observer, file, fileSmall, deck) +HumanPlayer::HumanPlayer(GameObserver *observer, string file, string fileSmall, bool premade, MTGDeck * deck) : + Player(observer, file, fileSmall, deck), premade(premade) { mAvatarName = "avatar.jpg"; playMode = MODE_HUMAN; @@ -248,6 +248,11 @@ bool Player::parseLine(const string& s) deckFile = s.substr(limiter + 1); return true; } + else if (areaS.compare("deckfilesmall") == 0) + { + deckFileSmall = s.substr(limiter + 1); + return true; + } else if (areaS.compare("offerinterruptonphase") == 0) { for (int i = 0; i < Constants::NB_MTG_PHASES; i++) @@ -287,6 +292,8 @@ ostream& operator<<(ostream& out, const Player& p) out << "offerinterruptonphase=" << Constants::MTGPhaseCodeNames[p.offerInterruptOnPhase] << endl; if(p.deckFile != "") out << "deckfile=" << p.deckFile << endl; + if(p.deckFileSmall != "") + out << "deckfilesmall=" << p.deckFileSmall << endl; if(p.game) { @@ -295,3 +302,4 @@ ostream& operator<<(ostream& out, const Player& p) return out; } + diff --git a/projects/mtg/src/Rules.cpp b/projects/mtg/src/Rules.cpp index 704f2ac09..29f8ab3ae 100644 --- a/projects/mtg/src/Rules.cpp +++ b/projects/mtg/src/Rules.cpp @@ -254,8 +254,8 @@ Player * Rules::loadPlayerMomir(GameObserver* observer, int isAI) Player * Rules::loadPlayerRandom(GameObserver* observer, int isAI, int mode) { - int color1 = 1 + WRand() % 5; - int color2 = 1 + WRand() % 5; + int color1 = 1 + WRand(true) % 5; + int color2 = 1 + WRand(true) % 5; int color0 = Constants::MTG_COLOR_ARTIFACT; if (mode == GAME_TYPE_RANDOM1) color2 = color1; int colors[] = { color1, color2, color0 }; @@ -367,7 +367,7 @@ void Rules::initGame(GameObserver *g) if (g->currentPlayer->playMode!= Player::MODE_TEST_SUITE && g->mRules->gamemode!= GAME_TYPE_STORY) { if(OptionWhosFirst::WHO_R == options[Options::FIRSTPLAYER].number) - initState.player = WRand() % 2; + initState.player = WRand(true) % 2; if(OptionWhosFirst::WHO_O == options[Options::FIRSTPLAYER].number) initState.player = 1; } diff --git a/projects/mtg/src/TextScroller.cpp b/projects/mtg/src/TextScroller.cpp index 305ce547b..17a984b27 100644 --- a/projects/mtg/src/TextScroller.cpp +++ b/projects/mtg/src/TextScroller.cpp @@ -46,22 +46,22 @@ void TextScroller::Update(float dt) { if (!strings.size()) return; - start += mScrollSpeed * dt; - WFont * mFont = WResourceManager::Instance()->GetWFont(fontId); - if (start > mFont->GetStringWidth(mText.c_str())) - { - start = -mWidth; - if (mRandom) - { - currentId = (rand() % strings.size()); - } - else - { - currentId++; - if (currentId >= strings.size()) currentId = 0; - } - mText = strings[currentId]; - } + start += mScrollSpeed * dt; + WFont * mFont = WResourceManager::Instance()->GetWFont(fontId); + if (start > mFont->GetStringWidth(mText.c_str())) + { + start = -mWidth; + if (mRandom) + { + currentId = (rand() % strings.size()); + } + else + { + currentId++; + if (currentId >= strings.size()) currentId = 0; + } + mText = strings[currentId]; + } } void TextScroller::Render() @@ -119,27 +119,27 @@ void VerticalTextScroller::Add( string text ) */ void VerticalTextScroller::Update(float dt) { - if (!strings.size()) return; + if (!strings.size()) return; - float currentYOffset = mScrollSpeed * dt; + float currentYOffset = mScrollSpeed * dt; - if ( mY <= mMarginY ) // top line has disappeared - { - timer = 0; - // now readjust mText - size_t nbLines = 1; - vector displayText = split( mText, '\n'); - vector newDisplayText; - for ( size_t i = nbLines; i < displayText.size(); ++i ) - newDisplayText.push_back( displayText[i] ); - for ( size_t i = 0; i < nbLines; ++i ) - newDisplayText.push_back( displayText[i] ); + if ( mY <= mMarginY ) // top line has disappeared + { + timer = 0; + // now readjust mText + size_t nbLines = 1; + vector displayText = split( mText, '\n'); + vector newDisplayText; + for ( size_t i = nbLines; i < displayText.size(); ++i ) + newDisplayText.push_back( displayText[i] ); + for ( size_t i = 0; i < nbLines; ++i ) + newDisplayText.push_back( displayText[i] ); - mText = join( newDisplayText, "\n" ); - mY = mOriginalY; - } - ++timer; - mY -= currentYOffset; + mText = join( newDisplayText, "\n" ); + mY = mOriginalY; + } + ++timer; + mY -= currentYOffset; } void VerticalTextScroller::Render() diff --git a/projects/mtg/src/utils.cpp b/projects/mtg/src/utils.cpp index 98094b64c..e6ac648e2 100644 --- a/projects/mtg/src/utils.cpp +++ b/projects/mtg/src/utils.cpp @@ -68,13 +68,13 @@ void loadRandValues(string s) ptrdiff_t MRand (ptrdiff_t i) { - return WRand()%i; + return WRand(true)%i; } -int WRand() +int WRand(bool log) { int result; - if (!loadedRandomValues.size()) + if (!loadedRandomValues.size() || !log) { result = rand(); } @@ -83,7 +83,8 @@ int WRand() result = loadedRandomValues.front(); loadedRandomValues.pop(); } - usedRandomValues.push(result); + if(log) + usedRandomValues.push(result); return result; }