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
This commit is contained in:
Xawotihs
2011-10-26 22:14:12 +00:00
parent 45f09972ad
commit c3dc51aed1
34 changed files with 410 additions and 297 deletions
+1 -1
View File
@@ -24,4 +24,4 @@ public:
static string Process(const string& s); static string Process(const string& s);
}; };
#endif #endif
-1
View File
@@ -44,7 +44,6 @@ public:
void setMenuObject(Targetable * object, bool must = false); void setMenuObject(Targetable * object, bool must = false);
void setCustomMenuObject(Targetable * object, bool must = false,vector<MTGAbility*>abilities = vector<MTGAbility*>()); void setCustomMenuObject(Targetable * object, bool must = false,vector<MTGAbility*>abilities = vector<MTGAbility*>());
void ButtonPressed(int controllerid, int controlid); void ButtonPressed(int controllerid, int controlid);
void doMultipleChoice(int choice = -1);
void ButtonPressedOnMultipleChoice(int choice = -1); void ButtonPressedOnMultipleChoice(int choice = -1);
void doReactTo(int menuIndex); void doReactTo(int menuIndex);
TargetChooser * getCurrentTargetChooser(); TargetChooser * getCurrentTargetChooser();
+2 -2
View File
@@ -207,7 +207,7 @@ public:
DONT_INTERRUPT_ALL = 2, DONT_INTERRUPT_ALL = 2,
}; };
Player * lastActionController; Player * lastActionController;
int setIsInterrupting(Player * player); int setIsInterrupting(Player * player, bool log = true);
int count( int type = 0 , int state = 0 , int display = -1); int count( int type = 0 , int state = 0 , int display = -1);
Interruptible * getActionElementFromCard(MTGCardInstance * card); Interruptible * getActionElementFromCard(MTGCardInstance * card);
Interruptible * getPrevious(Interruptible * next, int type = 0, int state = 0 , int display = -1); Interruptible * getPrevious(Interruptible * next, int type = 0, int state = 0 , int display = -1);
@@ -217,7 +217,7 @@ public:
void Fizzle(Interruptible * action); void Fizzle(Interruptible * action);
Interruptible * getAt(int id); Interruptible * getAt(int id);
void cancelInterruptOffer(int cancelMode = 1); void cancelInterruptOffer(int cancelMode = 1);
void endOfInterruption(); void endOfInterruption(bool log = true);
Interruptible * getLatest(int state); Interruptible * getLatest(int state);
Player * askIfWishesToInterrupt; Player * askIfWishesToInterrupt;
int garbageCollect(); int garbageCollect();
+4 -4
View File
@@ -1655,8 +1655,8 @@ public:
void Update(float dt) void Update(float dt)
{ {
if(!nonstatic) if(!nonstatic)
return; return;
((MTGCardInstance *) target)->power -= wppt->power.getValue(); ((MTGCardInstance *) target)->power -= wppt->power.getValue();
((MTGCardInstance *) target)->addToToughness(-wppt->toughness.getValue()); ((MTGCardInstance *) target)->addToToughness(-wppt->toughness.getValue());
if(PT.size()) if(PT.size())
@@ -1980,9 +1980,9 @@ public:
void Update(float dt) void Update(float dt)
{ {
ListMaintainerAbility::Update(dt); ListMaintainerAbility::Update(dt);
if(!ability->oneShot) if(!ability->oneShot) {
SorterFunction(); SorterFunction();
}
} }
void findMatchingAmount() void findMatchingAmount()
+3 -12
View File
@@ -24,19 +24,10 @@
#ifdef NETWORK_SUPPORT #ifdef NETWORK_SUPPORT
#include "JNetwork.h" #include "JNetwork.h"
#endif //NETWORK_SUPPORT #endif //NETWORK_SUPPORT
#include "GameObserver.h"
class Rules; 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 MTGAllCards;
class TransitionBase; class TransitionBase;
@@ -88,7 +79,7 @@ public:
static string currentMusicFile; static string currentMusicFile;
static void playMusic(string filename = "", bool loop = true); static void playMusic(string filename = "", bool loop = true);
static void stopMusic(); static void stopMusic();
static int players[2]; static PlayerType players[2];
}; };
+13 -3
View File
@@ -20,6 +20,7 @@ struct CardGui;
class Player; class Player;
class TargetChooser; class TargetChooser;
class Rules; class Rules;
class TestSuite;
using namespace std; using namespace std;
class GameObserver{ class GameObserver{
@@ -41,8 +42,9 @@ class GameObserver{
void logAction(const string& s); void logAction(const string& s);
bool processActions(bool undo); bool processActions(bool undo);
friend ostream& operator<<(ostream&, GameObserver&); friend ostream& operator<<(ostream&, GameObserver&);
bool load(const string& s, bool undo);
bool mLoading; bool mLoading;
void nextGamePhase();
void shuffleLibrary(Player* p);
public: public:
int currentPlayerId; int currentPlayerId;
@@ -74,11 +76,15 @@ class GameObserver{
const char * getCurrentGamePhaseName(); const char * getCurrentGamePhaseName();
const char * getNextGamePhaseName(); const char * getNextGamePhaseName();
void nextCombatStep(); void nextCombatStep();
void userRequestNextGamePhase(); void userRequestNextGamePhase(bool allowInterrupt = true, bool log = true);
void nextGamePhase();
void cleanupPhase(); void cleanupPhase();
void nextPlayer(); void nextPlayer();
void setPlayers(vector<Player *> _players); void setPlayers(vector<Player *> _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 * currentPlayer;
Player * currentActionPlayer; Player * currentActionPlayer;
Player * isInterrupting; Player * isInterrupting;
@@ -111,8 +117,12 @@ class GameObserver{
logAction(players[playerId], s); logAction(players[playerId], s);
}; };
void logAction(MTGCardInstance* card, MTGGameZone* zone, size_t index, int result); void logAction(MTGCardInstance* card, MTGGameZone* zone, size_t index, int result);
bool load(const string& s, bool undo = false);
bool undo(); bool undo();
bool isLoading(){ return mLoading; }; bool isLoading(){ return mLoading; };
void Mulligan(Player* player = NULL);
Player* getPlayer(size_t index) { return players[index];};
bool isStarted() { return (mLayers!=NULL);};
}; };
#endif #endif
+5 -4
View File
@@ -28,7 +28,6 @@ private:
Credits * credits; Credits * credits;
int mGamePhase; int mGamePhase;
Player * mCurrentPlayer; Player * mCurrentPlayer;
vector<Player *> mPlayers;
GameObserver * game; GameObserver * game;
DeckMenu * deckmenu; DeckMenu * deckmenu;
DeckMenu * opponentMenu; DeckMenu * opponentMenu;
@@ -42,7 +41,6 @@ private:
string musictrack; string musictrack;
bool MusicExist(string FileName); 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 ConstructOpponentMenu(); //loads the opponentMenu if it doesn't exist
void initScroller(); void initScroller();
void setGamePhase(int newGamePhase); void setGamePhase(int newGamePhase);
@@ -79,9 +77,12 @@ public:
MENUITEM_EVIL_TWIN = kEvilTwinMenuID, MENUITEM_EVIL_TWIN = kEvilTwinMenuID,
MENUITEM_MULLIGAN = -15, MENUITEM_MULLIGAN = -15,
MENUITEM_UNDO = -16, MENUITEM_UNDO = -16,
#ifdef TESTSUITE
MENUITEM_LOAD = -17,
#endif
#ifdef NETWORK_SUPPORT #ifdef NETWORK_SUPPORT
MENUITEM_REMOTE_CLIENT = -17, MENUITEM_REMOTE_CLIENT = -18,
MENUITEM_REMOTE_SERVER = -18, MENUITEM_REMOTE_SERVER = -19,
#endif #endif
MENUITEM_MORE_INFO = kInfoMenuID MENUITEM_MORE_INFO = kInfoMenuID
}; };
+1 -1
View File
@@ -293,7 +293,7 @@ public:
{ {
counters = 0; counters = 0;
} }
return MTGAbility::Update(dt); MTGAbility::Update(dt);
} }
virtual int reactToClick(MTGCardInstance * card); virtual int reactToClick(MTGCardInstance * card);
virtual int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL); virtual int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL);
+11
View File
@@ -24,6 +24,17 @@ typedef enum
#endif //NETWORK_SUPPORT #endif //NETWORK_SUPPORT
} GameType; } 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 class Constants
{ {
public: public:
+54 -54
View File
@@ -120,85 +120,85 @@ class MTGGameZone {
}; };
class MTGLibrary: public MTGGameZone { class MTGLibrary: public MTGGameZone {
public: public:
virtual ostream& toString(ostream&) const; virtual ostream& toString(ostream&) const;
const char * getName(){return "library";} const char * getName(){return "library";}
}; };
class MTGGraveyard: public MTGGameZone { class MTGGraveyard: public MTGGameZone {
public: public:
virtual ostream& toString(ostream&) const; virtual ostream& toString(ostream&) const;
const char * getName(){return "graveyard";} const char * getName(){return "graveyard";}
}; };
class MTGHand: public MTGGameZone { class MTGHand: public MTGGameZone {
public: public:
virtual ostream& toString(ostream&) const; virtual ostream& toString(ostream&) const;
const char * getName(){return "hand";} const char * getName(){return "hand";}
}; };
class MTGRemovedFromGame: public MTGGameZone { class MTGRemovedFromGame: public MTGGameZone {
public: public:
virtual ostream& toString(ostream&) const; virtual ostream& toString(ostream&) const;
const char * getName(){return "exile";} const char * getName(){return "exile";}
}; };
class MTGStack: public MTGGameZone { class MTGStack: public MTGGameZone {
public: public:
virtual ostream& toString(ostream&) const; virtual ostream& toString(ostream&) const;
const char * getName(){return "stack";} const char * getName(){return "stack";}
}; };
class MTGInPlay: public MTGGameZone { class MTGInPlay: public MTGGameZone {
public: public:
void untapAll(); void untapAll();
MTGCardInstance * getNextAttacker(MTGCardInstance * previous); MTGCardInstance * getNextAttacker(MTGCardInstance * previous);
virtual ostream& toString(ostream&) const; virtual ostream& toString(ostream&) const;
const char * getName(){return "battlefield";} const char * getName(){return "battlefield";}
}; };
class MTGPlayerCards { class MTGPlayerCards {
protected: protected:
void init(); void init();
public: public:
Player * owner; Player * owner;
PlayRestrictions * playRestrictions; PlayRestrictions * playRestrictions;
MTGLibrary * library; MTGLibrary * library;
MTGGraveyard * graveyard; MTGGraveyard * graveyard;
MTGHand * hand; MTGHand * hand;
MTGInPlay * inPlay; MTGInPlay * inPlay;
MTGInPlay * battlefield; //alias to inPlay MTGInPlay * battlefield; //alias to inPlay
MTGStack * stack; MTGStack * stack;
MTGRemovedFromGame * removedFromGame; MTGRemovedFromGame * removedFromGame;
MTGRemovedFromGame * exile; //alias to removedFromZone MTGRemovedFromGame * exile; //alias to removedFromZone
MTGGameZone * garbage; MTGGameZone * garbage;
MTGGameZone * temp; MTGGameZone * temp;
MTGPlayerCards(); MTGPlayerCards();
MTGPlayerCards(Player*, int * idList, int idListSize); MTGPlayerCards(Player*, int * idList, int idListSize);
MTGPlayerCards(MTGDeck * deck); MTGPlayerCards(MTGDeck * deck);
~MTGPlayerCards(); ~MTGPlayerCards();
void initGame(int shuffle = 1, int draw = 1); 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 OptimizedHand(Player * who,int amount = 7,int lands = 3,int creatures = 0,int othercards = 4);
void setOwner(Player * player); void setOwner(Player * player);
void discardRandom(MTGGameZone * from,MTGCardInstance * source); void discardRandom(MTGGameZone * from,MTGCardInstance * source);
void drawFromLibrary(); void drawFromLibrary();
void showHand(); void showHand();
void resetLibrary(); void resetLibrary();
void initDeck(MTGDeck * deck); void initDeck(MTGDeck * deck);
void beforeBeginPhase(); void beforeBeginPhase();
MTGCardInstance * putInGraveyard(MTGCardInstance * card); MTGCardInstance * putInGraveyard(MTGCardInstance * card);
MTGCardInstance * putInExile(MTGCardInstance * card); MTGCardInstance * putInExile(MTGCardInstance * card);
MTGCardInstance * putInLibrary(MTGCardInstance * card); MTGCardInstance * putInLibrary(MTGCardInstance * card);
MTGCardInstance * putInHand(MTGCardInstance * card); MTGCardInstance * putInHand(MTGCardInstance * card);
MTGCardInstance * putInZone(MTGCardInstance * card, MTGGameZone * from, MTGGameZone * to); MTGCardInstance * putInZone(MTGCardInstance * card, MTGGameZone * from, MTGGameZone * to);
int isInPlay(MTGCardInstance * card); int isInPlay(MTGCardInstance * card);
int isInGrave(MTGCardInstance * card); int isInGrave(MTGCardInstance * card);
int isInZone(MTGCardInstance * card,MTGGameZone * zone); int isInZone(MTGCardInstance * card,MTGGameZone * zone);
bool parseLine(const string& s); bool parseLine(const string& s);
}; };
ostream& operator<<(ostream&, const MTGGameZone&); ostream& operator<<(ostream&, const MTGGameZone&);
+7 -1
View File
@@ -101,8 +101,14 @@ public:
class HumanPlayer: public Player class HumanPlayer: public Player
{ {
protected:
bool premade;
public: 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 #endif
+1 -1
View File
@@ -66,7 +66,7 @@ unsigned long hash_djb2(const char *str);
void loadRandValues(string s); void loadRandValues(string s);
ostream& saveRandValues(ostream& out); ostream& saveRandValues(ostream& out);
int filesize(const char * filename); int filesize(const char * filename);
int WRand(); int WRand(bool log = false);
ptrdiff_t MRand (ptrdiff_t i); ptrdiff_t MRand (ptrdiff_t i);
#ifdef LINUX #ifdef LINUX
+2 -2
View File
@@ -97,7 +97,7 @@ int AIAction::clickMultiAct(vector<Targetable*>& actionTargets)
actionTargets.erase(actionTargets.begin() + f); 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. //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++) for(int k = 0;k < int(actionTargets.size());k++)
{ {
@@ -172,7 +172,7 @@ int AIPlayer::clickMultiTarget(TargetChooser * tc, vector<Targetable*>& potentia
potentialTargets.erase(potentialTargets.begin() + f); potentialTargets.erase(potentialTargets.begin() + f);
} }
} }
std::random_shuffle(potentialTargets.begin(), potentialTargets.end(), MRand); std::random_shuffle(potentialTargets.begin(), potentialTargets.end());
if(potentialTargets.size()) if(potentialTargets.size())
clickstream.push(NEW AIAction(this, NULL,tc->source,potentialTargets)); clickstream.push(NEW AIAction(this, NULL,tc->source,potentialTargets));
while(clickstream.size()) while(clickstream.size())
+1 -4
View File
@@ -1751,10 +1751,7 @@ int AIPlayerBaka::computeActions()
int doThis = selectMenuOption(); int doThis = selectMenuOption();
if(doThis >= 0) if(doThis >= 0)
{ {
if(object->abilitiesMenu->isMultipleChoice) observer->mLayers->actionLayer()->ButtonPressed(0, doThis);
observer->mLayers->actionLayer()->doMultipleChoice(doThis);
else
observer->mLayers->actionLayer()->doReactTo(doThis);
} }
else if(doThis < 0 || object->checkCantCancel()) else if(doThis < 0 || object->checkCantCancel())
observer->mLayers->actionLayer()->doReactTo(object->abilitiesMenu->mObjects.size()-1); observer->mLayers->actionLayer()->doReactTo(object->abilitiesMenu->mObjects.size()-1);
+1 -1
View File
@@ -124,4 +124,4 @@ string AutoLineMacro::Process(const string& s)
result = gAutoLineMacros[i]->process(result); result = gAutoLineMacros[i]->process(result);
} }
return result; return result;
} }
+6 -11
View File
@@ -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) void ActionLayer::ButtonPressed(int controllerid, int controlid)
{ {
stringstream stream;
stream << "choice " << controlid;
observer->logAction(observer->currentActionPlayer, stream.str());
if(this->abilitiesMenu && this->abilitiesMenu->isMultipleChoice) if(this->abilitiesMenu && this->abilitiesMenu->isMultipleChoice)
{ {
return ButtonPressedOnMultipleChoice(); return ButtonPressedOnMultipleChoice();
@@ -430,7 +425,7 @@ void ActionLayer::ButtonPressed(int controllerid, int controlid)
} }
else if (controlid == kCancelMenuID) else if (controlid == kCancelMenuID)
{ {
observer->mLayers->stackLayer()->endOfInterruption(); observer->mLayers->stackLayer()->endOfInterruption(false);
menuObject = 0; menuObject = 0;
} }
else else
@@ -464,7 +459,7 @@ void ActionLayer::ButtonPressedOnMultipleChoice(int choice)
} }
else if (currentMenuObject == kCancelMenuID) else if (currentMenuObject == kCancelMenuID)
{ {
observer->mLayers->stackLayer()->endOfInterruption(); observer->mLayers->stackLayer()->endOfInterruption(false);
} }
menuObject = 0; menuObject = 0;
} }
+9 -7
View File
@@ -34,7 +34,7 @@ NextGamePhase requested by user
*/ */
int NextGamePhase::resolve() int NextGamePhase::resolve()
{ {
observer->nextGamePhase(); observer->userRequestNextGamePhase(false, false);
return 1; return 1;
} }
@@ -568,7 +568,7 @@ int ActionStack::AddNextCombatStep()
return 1; return 1;
} }
int ActionStack::setIsInterrupting(Player * player) int ActionStack::setIsInterrupting(Player * player, bool log)
{ {
askIfWishesToInterrupt = NULL; askIfWishesToInterrupt = NULL;
@@ -589,7 +589,8 @@ int ActionStack::setIsInterrupting(Player * player)
int playerId = (player == observer->players[1]) ? 1 : 0; int playerId = (player == observer->players[1]) ? 1 : 0;
interruptDecision[playerId] = -1; interruptDecision[playerId] = -1;
observer->isInterrupting = player; observer->isInterrupting = player;
observer->logAction(player, "yes"); if(log)
observer->logAction(player, "yes");
return 1; return 1;
} }
@@ -826,7 +827,6 @@ int ActionStack::receiveEventPlus(WEvent * event)
void ActionStack::Update(float dt) void ActionStack::Update(float dt)
{ {
//This is a hack to avoid updating the stack while tuto messages are being shown //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 //Ideally, the tuto messages should be moved to a layer above this one
if (ATutorialMessage::Current) if (ATutorialMessage::Current)
@@ -845,6 +845,7 @@ void ActionStack::Update(float dt)
if (mode == ACTIONSTACK_STANDARD && tc && !checked) if (mode == ACTIONSTACK_STANDARD && tc && !checked)
{ {
checked = 1; checked = 1;
for (size_t i = 0; i < mObjects.size(); i++) for (size_t i = 0; i < mObjects.size(); i++)
{ {
Interruptible * current = (Interruptible *) mObjects[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. extraTime = 1;//we never want this int to be 0.
if (timer < 0) if (timer < 0)
timer = static_cast<float>(options[Options::INTERRUPT_SECONDS].number * extraTime); timer = static_cast<float>(options[Options::INTERRUPT_SECONDS].number * extraTime);
timer -= dt; timer -= dt;
if (timer < 0) if (timer < 0)
cancelInterruptOffer(); cancelInterruptOffer();
@@ -964,12 +965,13 @@ void ActionStack::cancelInterruptOffer(int cancelMode)
observer->logAction(playerId, "no"); observer->logAction(playerId, "no");
} }
void ActionStack::endOfInterruption() void ActionStack::endOfInterruption(bool log)
{ {
int playerId = (observer->isInterrupting == observer->players[1]) ? 1 : 0; int playerId = (observer->isInterrupting == observer->players[1]) ? 1 : 0;
interruptDecision[playerId] = 0; interruptDecision[playerId] = 0;
observer->isInterrupting = NULL; observer->isInterrupting = NULL;
observer->logAction(playerId, "endinterruption"); if(log)
observer->logAction(playerId, "endinterruption");
} }
bool ActionStack::CheckUserInput(JButton key) bool ActionStack::CheckUserInput(JButton key)
+3 -3
View File
@@ -2219,7 +2219,7 @@ void MayAbility::Update(float dt)
} }
game->mLayers->actionLayer()->setMenuObject(source, must); game->mLayers->actionLayer()->setMenuObject(source, must);
previousInterrupter = game->isInterrupting; 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; MTGGameZone * inplay = spell->source->owner->game->inPlay;
spell->source->target = NULL; 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) if(tc->canTarget(inplay->cards[i]) && spell->source->target == NULL)
{ {
@@ -3768,7 +3768,7 @@ void ABlink::resolveBlink()
MTGGameZone * inplay = spell->source->owner->game->inPlay; MTGGameZone * inplay = spell->source->owner->game->inPlay;
spell->source->target = NULL; 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) if(tc->canTarget(inplay->cards[i]) && spell->source->target == NULL)
{ {
+2 -1
View File
@@ -92,7 +92,8 @@ void CardDisplay::Update(float dt)
} }
} }
PlayGuiObjectController::Update(dt); PlayGuiObjectController::Update(dt);
if (update) init(zone); if (update)
init(zone);
} }
bool CardDisplay::CheckUserInput(JButton key) bool CardDisplay::CheckUserInput(JButton key)
+1 -1
View File
@@ -338,7 +338,7 @@ void DeckMenu::Update(float dt)
timeOpen += dt * 10; timeOpen += dt * 10;
} }
if (mScroller) if (mScroller)
mScroller->Update(dt); mScroller->Update(dt);
} }
void DeckMenu::Add(int id, const char * text, string desc, bool forceFocus, DeckMetaData * deckMetaData) void DeckMenu::Add(int id, const char * text, string desc, bool forceFocus, DeckMetaData * deckMetaData)
+1
View File
@@ -78,6 +78,7 @@ void DuelLayers::Update(float dt, Player * currentPlayer)
{ {
for (int i = 0; i < nbitems; ++i) for (int i = 0; i < nbitems; ++i)
objects[i]->Update(dt); objects[i]->Update(dt);
int isAI = currentPlayer->isAI(); int isAI = currentPlayer->isAI();
if (isAI && !currentPlayer->getObserver()->isLoading()) if (isAI && !currentPlayer->getObserver()->isLoading())
currentPlayer->Act(dt); currentPlayer->Act(dt);
+3 -3
View File
@@ -34,7 +34,7 @@
#define DEFAULT_DURATION .25 #define DEFAULT_DURATION .25
int GameApp::players[] = { 0, 0 }; PlayerType GameApp::players[] = { PLAYER_TYPE_CPU, PLAYER_TYPE_CPU };
bool GameApp::HasMusic = true; bool GameApp::HasMusic = true;
JMusic * GameApp::music = NULL; JMusic * GameApp::music = NULL;
string GameApp::currentMusicFile = ""; string GameApp::currentMusicFile = "";
@@ -69,8 +69,8 @@ GameApp::GameApp() :
mGameStates[i] = NULL; mGameStates[i] = NULL;
mShowDebugInfo = false; mShowDebugInfo = false;
players[0] = 0; players[0] = PLAYER_TYPE_CPU;
players[1] = 0; players[1] = PLAYER_TYPE_CPU;
gameType = GAME_TYPE_CLASSIC; gameType = GAME_TYPE_CLASSIC;
mCurrentState = NULL; mCurrentState = NULL;
+161 -30
View File
@@ -12,6 +12,9 @@
#include "GuiPhaseBar.h" #include "GuiPhaseBar.h"
#include "AIPlayerBaka.h" #include "AIPlayerBaka.h"
#include "MTGRules.h" #include "MTGRules.h"
#ifdef TESTSUITE
#include "TestSuiteAI.h"
#endif
void GameObserver::initialize() void GameObserver::initialize()
{ {
@@ -31,6 +34,7 @@ void GameObserver::initialize()
mRules = NULL; mRules = NULL;
connectRule = false; connectRule = false;
mLoading = false; mLoading = false;
mLayers = NULL;
} }
void GameObserver::cleanup() void GameObserver::cleanup()
@@ -59,11 +63,16 @@ void GameObserver::cleanup()
combatStep = BLOCKERS; combatStep = BLOCKERS;
connectRule = false; connectRule = false;
actionsList.clear(); actionsList.clear();
} }
GameObserver::~GameObserver() GameObserver::~GameObserver()
{ {
LOG("==Destroying GameObserver=="); LOG("==Destroying GameObserver==");
for (size_t i = 0; i < players.size(); ++i)
{
players[i]->End();
}
SAFE_DELETE(targetChooser); SAFE_DELETE(targetChooser);
SAFE_DELETE(mLayers); SAFE_DELETE(mLayers);
SAFE_DELETE(phaseRing); SAFE_DELETE(phaseRing);
@@ -243,17 +252,21 @@ void GameObserver::nextCombatStep()
} }
} }
void GameObserver::userRequestNextGamePhase() void GameObserver::userRequestNextGamePhase(bool allowInterrupt, bool log)
{ {
stringstream stream; if(log) {
stream << "next " << currentGamePhase; stringstream stream;
stream << "next " << allowInterrupt << " " <<currentGamePhase;
logAction(currentPlayer, stream.str());
}
if(getCurrentTargetChooser() && getCurrentTargetChooser()->maxtargets == 1000) if(getCurrentTargetChooser() && getCurrentTargetChooser()->maxtargets == 1000)
{ {
getCurrentTargetChooser()->done = true; getCurrentTargetChooser()->done = true;
if(getCurrentTargetChooser()->source) if(getCurrentTargetChooser()->source)
cardClick(getCurrentTargetChooser()->source); cardClick(getCurrentTargetChooser()->source);
} }
if (mLayers->stackLayer()->getNext(NULL, 0, NOT_RESOLVED)) if (allowInterrupt && mLayers->stackLayer()->getNext(NULL, 0, NOT_RESOLVED))
return; return;
if (getCurrentTargetChooser()) if (getCurrentTargetChooser())
return; return;
@@ -266,13 +279,13 @@ void GameObserver::userRequestNextGamePhase()
return; return;
Phase * cPhaseOld = phaseRing->getCurrentPhase(); 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_COMBATBLOCKERS && combatStep == TRIGGERS)
|| (cPhaseOld->id == Constants::MTG_PHASE_COMBATDAMAGE) || (cPhaseOld->id == Constants::MTG_PHASE_COMBATDAMAGE)
|| opponent()->isAI() || opponent()->isAI()
|| options[Options::optionInterrupt(currentGamePhase)].number || options[Options::optionInterrupt(currentGamePhase)].number
|| currentPlayer->offerInterruptOnPhase - 1 == currentGamePhase || currentPlayer->offerInterruptOnPhase - 1 == currentGamePhase
) ))
{ {
mLayers->stackLayer()->AddNextGamePhase(); mLayers->stackLayer()->AddNextGamePhase();
} }
@@ -280,11 +293,15 @@ void GameObserver::userRequestNextGamePhase()
{ {
nextGamePhase(); nextGamePhase();
} }
stream << " " << currentGamePhase ;
logAction(currentPlayer, stream.str());
} }
void GameObserver::shuffleLibrary(Player* p)
{
logAction(p, "shufflelib");
p->game->library->shuffle();
}
int GameObserver::forceShuffleLibraries() int GameObserver::forceShuffleLibraries()
{ {
int result = 0; int result = 0;
@@ -292,7 +309,7 @@ int GameObserver::forceShuffleLibraries()
{ {
if (players[i]->game->library->needShuffle) if (players[i]->game->library->needShuffle)
{ {
players[i]->game->library->shuffle(); shuffleLibrary(players[i]);
players[i]->game->library->needShuffle = false; players[i]->game->library->needShuffle = false;
++result; ++result;
} }
@@ -322,6 +339,8 @@ void GameObserver::startGame(GameType gtype, Rules * rules)
stringstream stream; stringstream stream;
stream << *this; stream << *this;
startupGameSerialized = stream.str(); startupGameSerialized = stream.str();
DebugTrace("startGame\n");
DebugTrace(startupGameSerialized);
if (rules) if (rules)
rules->initGame(this); rules->initGame(this);
@@ -407,6 +426,7 @@ bool GameObserver::removeObserver(ActionElement * observer)
void GameObserver::Update(float dt) void GameObserver::Update(float dt)
{ {
Player * player = currentPlayer; Player * player = currentPlayer;
if (Constants::MTG_PHASE_COMBATBLOCKERS == currentGamePhase && BLOCKERS == combatStep) if (Constants::MTG_PHASE_COMBATBLOCKERS == currentGamePhase && BLOCKERS == combatStep)
{ {
@@ -422,13 +442,15 @@ void GameObserver::Update(float dt)
currentActionPlayer = player; currentActionPlayer = player;
if (isInterrupting) if (isInterrupting)
player = isInterrupting; player = isInterrupting;
mLayers->Update(dt, player); if(mLayers)
while (mLayers->actionLayer()->stuffHappened)
{ {
mLayers->actionLayer()->Update(0); mLayers->Update(dt, player);
while (mLayers->actionLayer()->stuffHappened)
{
mLayers->actionLayer()->Update(0);
}
gameStateBasedEffects();
} }
gameStateBasedEffects();
oldGamePhase = currentGamePhase; oldGamePhase = currentGamePhase;
} }
@@ -703,7 +725,7 @@ void GameObserver::gameStateBasedEffects()
} }
//Auto skip Phases //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; : options[Options::ASPHASES].number;
int nrCreatures = currentPlayer->game->inPlay->countByType("Creature"); int nrCreatures = currentPlayer->game->inPlay->countByType("Creature");
@@ -843,8 +865,9 @@ void GameObserver::Affinity()
} }
void GameObserver::Render() void GameObserver::Render()
{ {
mLayers->Render(); if(mLayers)
if (targetChooser || mLayers->actionLayer()->isWaitingForAnswer()) mLayers->Render();
if (targetChooser || (mLayers && mLayers->actionLayer()->isWaitingForAnswer()))
JRenderer::GetInstance()->DrawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, ARGB(255,255,0,0)); JRenderer::GetInstance()->DrawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, ARGB(255,255,0,0));
if (mExtraPayment) if (mExtraPayment)
mExtraPayment->Render(); mExtraPayment->Render();
@@ -981,7 +1004,6 @@ int GameObserver::cardClick(MTGCardInstance * card, Targetable * object)
if (!card) { if (!card) {
clickedPlayer = ((Player *) object); clickedPlayer = ((Player *) object);
logAction(clickedPlayer);
} else { } else {
backup = card; backup = card;
zone = card->currentZone; zone = card->currentZone;
@@ -1135,9 +1157,12 @@ int GameObserver::untap(MTGCardInstance * card)
TargetChooser * GameObserver::getCurrentTargetChooser() TargetChooser * GameObserver::getCurrentTargetChooser()
{ {
TargetChooser * _tc = mLayers->actionLayer()->getCurrentTargetChooser(); if(mLayers)
if (_tc) {
return _tc; TargetChooser * _tc = mLayers->actionLayer()->getCurrentTargetChooser();
if (_tc)
return _tc;
}
return targetChooser; return targetChooser;
} }
@@ -1298,10 +1323,11 @@ bool GameObserver::load(const string& ss, bool undo)
int state = -1; int state = -1;
string s; string s;
stringstream stream(ss); stringstream stream(ss);
string deckFile = players[0]->deckFile; string deckFile = "";//players[0]->deckFile;
string deckFileSmall = players[0]->deckFileSmall; string deckFileSmall = "";//players[0]->deckFileSmall;
DebugTrace("Loading " + ss); DebugTrace("Loading " + ss);
loadRandValues("");
cleanup(); cleanup();
@@ -1374,9 +1400,16 @@ bool GameObserver::load(const string& ss, bool undo)
phaseRing = NEW PhaseRing(this); phaseRing = NEW PhaseRing(this);
startedAt = time(0); startedAt = time(0);
// take a snapshot before processing the actions
startupGameSerialized = "";
stringstream stream;
stream << *this;
startupGameSerialized = stream.str();
mRules->initGame(this); mRules->initGame(this);
phaseRing->goToPhase(0, currentPlayer, false); phaseRing->goToPhase(0, currentPlayer, false);
phaseRing->goToPhase(currentGamePhase, currentPlayer); phaseRing->goToPhase(currentGamePhase, currentPlayer);
processActions(undo); processActions(undo);
} }
else else
@@ -1393,6 +1426,7 @@ bool GameObserver::load(const string& ss, bool undo)
bool GameObserver::processActions(bool undo) bool GameObserver::processActions(bool undo)
{ {
bool result = false; bool result = false;
size_t cmdIndex = 0;
loadingList = actionsList; loadingList = actionsList;
actionsList.clear(); actionsList.clear();
@@ -1404,15 +1438,24 @@ bool GameObserver::processActions(bool undo)
if(undo && loadingList.size()) { if(undo && loadingList.size()) {
while(loadingList.back().find("p2") != string::npos) while(loadingList.back().find("p2") != string::npos)
loadingList.pop_back(); 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; string s = *loadingite;
Player* p = players[1]; Player* p = players[1];
if (s.find("p1") != string::npos) if (s.find("p1") != string::npos)
p = players[0]; p = players[0];
for (int i = 0; i<5; i++)
{
// let's fake an update
Update(counter);
counter += 1.000f;
}
MTGGameZone* zone = NULL; MTGGameZone* zone = NULL;
if(s.find(p->game->hand->getName()) != string::npos) if(s.find(p->game->hand->getName()) != string::npos)
zone = p->game->hand; zone = p->game->hand;
@@ -1439,19 +1482,31 @@ bool GameObserver::processActions(bool undo)
userRequestNextGamePhase(); userRequestNextGamePhase();
} else if (s.find("choice") != string::npos) { } else if (s.find("choice") != string::npos) {
int choice = atoi(s.substr(s.find("choice ") + 7).c_str()); 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") { } else if (s == "p1" || s == "p2") {
cardClick(NULL, p); 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 { } else {
assert(0); 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 // let's fake an update
Update(counter); Update(counter);
counter += 1.000f; counter += 1.000f;
} }
assert(actionsList.back() == *loadingite);
assert(nb == actionsList.size());
assert(cmdIndex == (actionsList.size()-1));
} }
mLoading = false; mLoading = false;
@@ -1485,8 +1540,7 @@ void GameObserver::logAction(const string& s)
if(mLoading) if(mLoading)
{ {
string toCheck = *loadingite; string toCheck = *loadingite;
if(toCheck != s) assert(toCheck == s);
assert(0);
} }
actionsList.push_back(s); actionsList.push_back(s);
}; };
@@ -1498,3 +1552,80 @@ bool GameObserver::undo()
DebugTrace(stream.str()); DebugTrace(stream.str());
return load(stream.str(), true); 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();
}
}
+29 -90
View File
@@ -67,7 +67,6 @@ int GameStateDuel::selectedAIDeckId = 0;
GameStateDuel::GameStateDuel(GameApp* parent) : GameStateDuel::GameStateDuel(GameApp* parent) :
GameState(parent, "duel") GameState(parent, "duel")
{ {
mPlayers.clear();
premadeDeck = false; premadeDeck = false;
game = NULL; game = NULL;
deckmenu = NULL; deckmenu = NULL;
@@ -120,6 +119,8 @@ void GameStateDuel::Start()
renderer->EnableVSync(true); renderer->EnableVSync(true);
OpponentsDeckid = 0; OpponentsDeckid = 0;
game = NEW GameObserver();
#ifdef TESTSUITE #ifdef TESTSUITE
SAFE_DELETE(testSuite); SAFE_DELETE(testSuite);
testSuite = NEW TestSuite("test/_tests.txt"); testSuite = NEW TestSuite("test/_tests.txt");
@@ -184,64 +185,6 @@ void GameStateDuel::Start()
} }
deckmenu->Add(MENUITEM_CANCEL, "Main Menu", "Return to Main Menu"); 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) void GameStateDuel::initRand(unsigned int seed)
@@ -258,12 +201,10 @@ void GameStateDuel::loadTestSuitePlayers()
initRand(testSuite->seed); initRand(testSuite->seed);
SAFE_DELETE(game); SAFE_DELETE(game);
game = new GameObserver(); game = new GameObserver();
mPlayers.clear();
for (int i = 0; i < 2; i++) 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; mParent->gameType = testSuite->gameType;
game->startGame(mParent->gameType, mParent->rules); game->startGame(mParent->gameType, mParent->rules);
@@ -279,22 +220,9 @@ void GameStateDuel::End()
#endif #endif
JRenderer::GetInstance()->EnableVSync(false); 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); SAFE_DELETE(game);
premadeDeck = false; premadeDeck = false;
if(mPlayers.size())
for (size_t i = 0; i < mPlayers.size(); i++)
{
mPlayers[i] = NULL;
}
mPlayers.clear();
SAFE_DELETE(credits); SAFE_DELETE(credits);
SAFE_DELETE(menu); SAFE_DELETE(menu);
@@ -325,7 +253,7 @@ void GameStateDuel::ConstructOpponentMenu()
DeckManager * deckManager = DeckManager::GetInstance(); DeckManager * deckManager = DeckManager::GetInstance();
vector<DeckMetaData*> opponentDeckList; vector<DeckMetaData*> opponentDeckList;
int nbUnlockedDecks = options[Options::CHEATMODEAIDECK].number ? 1000 : options[Options::AIDECKS_UNLOCKED].number; 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); deckManager->updateMetaDataList(&opponentDeckList, true);
opponentMenu->Add(MENUITEM_CANCEL, "Cancel", _("Choose a different player deck").c_str()); opponentMenu->Add(MENUITEM_CANCEL, "Cancel", _("Choose a different player deck").c_str());
opponentDeckList.clear(); opponentDeckList.clear();
@@ -393,7 +321,7 @@ void GameStateDuel::Update(float dt)
} }
else else
{ {
loadPlayer(0); game->loadPlayer(0, mParent->players[0]);
setGamePhase(DUEL_STATE_CHOOSE_DECK2); setGamePhase(DUEL_STATE_CHOOSE_DECK2);
} }
} }
@@ -416,7 +344,7 @@ void GameStateDuel::Update(float dt)
} }
else else
{ {
loadPlayer(1); game->loadPlayer(1, mParent->players[1]);
setGamePhase(DUEL_STATE_PLAY); setGamePhase(DUEL_STATE_PLAY);
} }
} }
@@ -439,9 +367,8 @@ void GameStateDuel::Update(float dt)
} }
break; break;
case DUEL_STATE_PLAY: case DUEL_STATE_PLAY:
if (!game) if (!game->isStarted())
{ {
game = new GameObserver(mPlayers);
game->startGame(mParent->gameType, mParent->rules); game->startGame(mParent->gameType, mParent->rules);
//start of in game music code //start of in game music code
@@ -523,6 +450,9 @@ void GameStateDuel::Update(float dt)
//END almosthumane - mulligan //END almosthumane - mulligan
menu->Add(MENUITEM_MAIN_MENU, "Back to main menu"); menu->Add(MENUITEM_MAIN_MENU, "Back to main menu");
menu->Add(MENUITEM_UNDO, "Undo"); menu->Add(MENUITEM_UNDO, "Undo");
#ifdef TESTSUITE
menu->Add(MENUITEM_LOAD, "Load");
#endif
menu->Add(MENUITEM_CANCEL, "Cancel"); menu->Add(MENUITEM_CANCEL, "Cancel");
} }
setGamePhase(DUEL_STATE_MENU); setGamePhase(DUEL_STATE_MENU);
@@ -763,7 +693,7 @@ void GameStateDuel::ButtonPressed(int controllerId, int controlId)
switch (controlId) switch (controlId)
{ {
case MENUITEM_RANDOM_AI: case MENUITEM_RANDOM_AI:
loadPlayer(1); game->loadPlayer(1, mParent->players[1]);
opponentMenu->Close(); opponentMenu->Close();
setGamePhase(DUEL_STATE_CHOOSE_DECK2_TO_PLAY); setGamePhase(DUEL_STATE_CHOOSE_DECK2_TO_PLAY);
break; break;
@@ -803,7 +733,7 @@ void GameStateDuel::ButtonPressed(int controllerId, int controlId)
} }
else if (controlId != MENUITEM_EVIL_TWIN && aiDeckSize > 0) // evil twin else if (controlId != MENUITEM_EVIL_TWIN && aiDeckSize > 0) // evil twin
deckNumber = deckManager->getAIDeckOrderList()->at(controlId - 1)->getDeckId(); deckNumber = deckManager->getAIDeckOrderList()->at(controlId - 1)->getDeckId();
loadPlayer(1, deckNumber, 1); game->loadPlayer(1, mParent->players[1], deckNumber, premadeDeck);
OpponentsDeckid = deckNumber; OpponentsDeckid = deckNumber;
opponentMenu->Close(); opponentMenu->Close();
setGamePhase(DUEL_STATE_CHOOSE_DECK2_TO_PLAY); setGamePhase(DUEL_STATE_CHOOSE_DECK2_TO_PLAY);
@@ -817,7 +747,7 @@ void GameStateDuel::ButtonPressed(int controllerId, int controlId)
{ {
vector<DeckMetaData *> * playerDeckList = deckManager->getPlayerDeckOrderList(); vector<DeckMetaData *> * playerDeckList = deckManager->getPlayerDeckOrderList();
deckNumber = playerDeckList->at(WRand() % (playerDeckList->size()))->getDeckId(); deckNumber = playerDeckList->at(WRand() % (playerDeckList->size()))->getDeckId();
loadPlayer(0, deckNumber); game->loadPlayer(0, mParent->players[0], deckNumber, premadeDeck);
deckmenu->Close(); deckmenu->Close();
setGamePhase(DUEL_STATE_CHOOSE_DECK2_TO_PLAY); setGamePhase(DUEL_STATE_CHOOSE_DECK2_TO_PLAY);
break; break;
@@ -860,11 +790,7 @@ void GameStateDuel::ButtonPressed(int controllerId, int controlId)
vector<DeckMetaData *> * playerDeck = deckManager->getPlayerDeckOrderList(); vector<DeckMetaData *> * playerDeck = deckManager->getPlayerDeckOrderList();
if (!premadeDeck && controlId > 0) if (!premadeDeck && controlId > 0)
deckNumber = playerDeck->at(controlId - 1)->getDeckId(); deckNumber = playerDeck->at(controlId - 1)->getDeckId();
loadPlayer(0, deckNumber, false game->loadPlayer(0, mParent->players[0], deckNumber, premadeDeck);
#ifdef NETWORK_SUPPORT
,(mParent->players[1] == PLAYER_TYPE_REMOTE)
#endif //NETWORK_SUPPORT
);
deckmenu->Close(); deckmenu->Close();
#ifdef NETWORK_SUPPORT #ifdef NETWORK_SUPPORT
if(mParent->players[1] == PLAYER_TYPE_REMOTE) if(mParent->players[1] == PLAYER_TYPE_REMOTE)
@@ -880,7 +806,7 @@ void GameStateDuel::ButtonPressed(int controllerId, int controlId)
} }
else else
{ {
loadPlayer(1, controlId); game->loadPlayer(1, mParent->players[1], controlId, premadeDeck);
deckmenu->Close(); deckmenu->Close();
setGamePhase(DUEL_STATE_CHOOSE_DECK2_TO_PLAY); setGamePhase(DUEL_STATE_CHOOSE_DECK2_TO_PLAY);
} }
@@ -901,7 +827,7 @@ void GameStateDuel::ButtonPressed(int controllerId, int controlId)
break; break;
case MENUITEM_MULLIGAN: case MENUITEM_MULLIGAN:
//almosthumane - mulligan //almosthumane - mulligan
game->currentPlayer->takeMulligan(); game->Mulligan();
menu->Close(); menu->Close();
setGamePhase(DUEL_STATE_CANCEL); setGamePhase(DUEL_STATE_CANCEL);
@@ -913,6 +839,19 @@ void GameStateDuel::ButtonPressed(int controllerId, int controlId)
setGamePhase(DUEL_STATE_CANCEL); setGamePhase(DUEL_STATE_CANCEL);
break; 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
} }
} }
} }
+28 -6
View File
@@ -16,6 +16,13 @@ const float kZoom_level1 = 1.4f;
const float kZoom_level2 = 2.2f; const float kZoom_level2 = 2.2f;
const float kZoom_level3 = 2.7f; const float kZoom_level3 = 2.7f;
struct True: public Exp
{
static inline bool test(DamagerDamaged* ref, DamagerDamaged* test)
{
return true;
}
};
struct Left: public Exp struct Left: public Exp
{ {
static inline bool test(DamagerDamaged* ref, DamagerDamaged* test) static inline bool test(DamagerDamaged* ref, DamagerDamaged* test)
@@ -107,7 +114,7 @@ void GuiCombat::validateDamage()
observer->nextCombatStep(); observer->nextCombatStep();
break; break;
case DAMAGE: case DAMAGE:
observer->nextGamePhase(); observer->userRequestNextGamePhase(false, false);
break; break;
default: default:
cout << "COMBAT : Cannot validate damage in this phase" << endl; cout << "COMBAT : Cannot validate damage in this phase" << endl;
@@ -168,11 +175,11 @@ bool GuiCombat::clickOK()
{ {
case BLOCKERS: case BLOCKERS:
case TRIGGERS: 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 return false; // that should not happen
case ORDER: case ORDER:
observer->nextGamePhase(); observer->userRequestNextGamePhase();
return true; return true;
case FIRST_STRIKE: case FIRST_STRIKE:
return false; return false;
@@ -192,6 +199,21 @@ bool GuiCombat::CheckUserInput(JButton key)
if (NONE == cursor_pos) if (NONE == cursor_pos)
return false; return false;
DamagerDamaged* oldActive = active; DamagerDamaged* oldActive = active;
/* This is untested
int x,y;
if(JGE::GetInstance()->GetLeftClickCoordinates(x, y))
{
DamagerDamaged* old = active;
active = closest<True> (activeAtk->blockers, NULL, static_cast<float> (x), static_cast<float> (y));
if (old != active)
{
if (old)
old->zoom = kZoom_none;
if (active)
active->zoom = kZoom_level1;
}
}
*/
switch (key) switch (key)
{ {
case JGE_BTN_OK: case JGE_BTN_OK:
@@ -608,7 +630,7 @@ int GuiCombat::receiveEventMinus(WEvent* e)
step = ORDER; step = ORDER;
} }
else else
observer->nextGamePhase(); observer->userRequestNextGamePhase(false, false);
return 1; return 1;
} }
case FIRST_STRIKE: case FIRST_STRIKE:
@@ -631,7 +653,7 @@ int GuiCombat::receiveEventMinus(WEvent* e)
if (!observer->currentPlayer->displayStack()) if (!observer->currentPlayer->displayStack())
{ {
((AIPlayer *) observer->currentPlayer)->affectCombatDamages(step); ((AIPlayer *) observer->currentPlayer)->affectCombatDamages(step);
observer->nextGamePhase(); observer->userRequestNextGamePhase(false, false);
return 1; return 1;
} }
for (inner_iterator attacker = attackers.begin(); attacker != attackers.end(); ++attacker) for (inner_iterator attacker = attackers.begin(); attacker != attackers.end(); ++attacker)
@@ -661,7 +683,7 @@ int GuiCombat::receiveEventMinus(WEvent* e)
case END_DAMAGE: case END_DAMAGE:
step = END_DAMAGE; step = END_DAMAGE;
if (0 == resolve()) if (0 == resolve())
observer->nextGamePhase(); observer->userRequestNextGamePhase(false, false);
return 1; return 1;
} }
return 0; return 0;
+1 -1
View File
@@ -134,4 +134,4 @@ IconButton::~IconButton()
ostream& IconButton::toString(ostream& out) const ostream& IconButton::toString(ostream& out) const
{ {
return out << "IconButton ::: mHasFocus : " << mHasFocus; return out << "IconButton ::: mHasFocus : " << mHasFocus;
} }
+2 -1
View File
@@ -344,7 +344,8 @@ int MTGAllCards::load(const char * config_file, const char * set_name, int autol
if (!s.size()) continue; if (!s.size()) continue;
if (s.find("#AUTO_DEFINE ") == 0) if (s.find("#AUTO_DEFINE ") == 0)
{ {
AutoLineMacro::AddMacro(s.substr(13)); string toAdd = s.substr(13);
AutoLineMacro::AddMacro(toAdd);
continue; continue;
} }
-3
View File
@@ -17,7 +17,6 @@ MTGGamePhase::MTGGamePhase(GameObserver* g, int id) :
void MTGGamePhase::Update(float dt) void MTGGamePhase::Update(float dt)
{ {
int newState = observer->getCurrentGamePhase(); int newState = observer->getCurrentGamePhase();
if (newState != currentState) if (newState != currentState)
{ {
@@ -34,9 +33,7 @@ void MTGGamePhase::Update(float dt)
{ {
activeState = INACTIVE; activeState = INACTIVE;
animation = 0; animation = 0;
} }
} }
bool MTGGamePhase::NextGamePhase() bool MTGGamePhase::NextGamePhase()
+1 -1
View File
@@ -390,7 +390,7 @@ void MTGPlayerCards::discardRandom(MTGGameZone * from, MTGCardInstance * source)
{ {
if (!from->nb_cards) if (!from->nb_cards)
return; return;
int r = WRand() % (from->nb_cards); int r = WRand(true) % (from->nb_cards);
WEvent * e = NEW WEventCardDiscard(from->cards[r]); WEvent * e = NEW WEventCardDiscard(from->cards[r]);
GameObserver * game = owner->getObserver(); GameObserver * game = owner->getObserver();
game->receiveEvent(e); game->receiveEvent(e);
+4 -4
View File
@@ -1517,7 +1517,7 @@ int MTGMomirRule::genRandomCreatureId(int convertedCost)
} }
if (!total_cards) if (!total_cards)
return 0; return 0;
int start = (WRand() % total_cards); int start = (WRand(true) % total_cards);
return pool[convertedCost][start]; return pool[convertedCost][start];
} }
@@ -1635,7 +1635,7 @@ int MTGStoneHewerRule::genRandomEquipId(int convertedCost)
if (convertedCost >= 20) if (convertedCost >= 20)
convertedCost = 19; convertedCost = 19;
int total_cards = 0; 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) while (!total_cards && i >= 0)
{ {
total_cards = pool[i].size(); total_cards = pool[i].size();
@@ -1644,7 +1644,7 @@ int MTGStoneHewerRule::genRandomEquipId(int convertedCost)
} }
if (!total_cards) if (!total_cards)
return 0; return 0;
int start = (WRand() % total_cards); int start = (WRand(true) % total_cards);
return pool[convertedCost][start]; return pool[convertedCost][start];
} }
@@ -1681,7 +1681,7 @@ int MTGHermitRule::receiveEvent(WEvent * event)
lands.push_back(temp); lands.push_back(temp);
} }
if(lands.size()) if(lands.size())
lcard = lands[WRand() % lands.size()]; lcard = lands[WRand(true) % lands.size()];
if(lcard) if(lcard)
{ {
MTGCardInstance * copy = game->currentPlayer->game->putInZone(lcard,game->currentPlayer->game->library, game->currentPlayer->game->temp); MTGCardInstance * copy = game->currentPlayer->game->putInZone(lcard,game->currentPlayer->game->library, game->currentPlayer->game->temp);
+11 -3
View File
@@ -110,12 +110,12 @@ JQuadPtr Player::getIcon()
Player * Player::opponent() 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]; return this == observer->players[0] ? observer->players[1] : observer->players[0];
} }
HumanPlayer::HumanPlayer(GameObserver *observer, string file, string fileSmall, MTGDeck * deck) : HumanPlayer::HumanPlayer(GameObserver *observer, string file, string fileSmall, bool premade, MTGDeck * deck) :
Player(observer, file, fileSmall, deck) Player(observer, file, fileSmall, deck), premade(premade)
{ {
mAvatarName = "avatar.jpg"; mAvatarName = "avatar.jpg";
playMode = MODE_HUMAN; playMode = MODE_HUMAN;
@@ -248,6 +248,11 @@ bool Player::parseLine(const string& s)
deckFile = s.substr(limiter + 1); deckFile = s.substr(limiter + 1);
return true; return true;
} }
else if (areaS.compare("deckfilesmall") == 0)
{
deckFileSmall = s.substr(limiter + 1);
return true;
}
else if (areaS.compare("offerinterruptonphase") == 0) else if (areaS.compare("offerinterruptonphase") == 0)
{ {
for (int i = 0; i < Constants::NB_MTG_PHASES; i++) 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; out << "offerinterruptonphase=" << Constants::MTGPhaseCodeNames[p.offerInterruptOnPhase] << endl;
if(p.deckFile != "") if(p.deckFile != "")
out << "deckfile=" << p.deckFile << endl; out << "deckfile=" << p.deckFile << endl;
if(p.deckFileSmall != "")
out << "deckfilesmall=" << p.deckFileSmall << endl;
if(p.game) if(p.game)
{ {
@@ -295,3 +302,4 @@ ostream& operator<<(ostream& out, const Player& p)
return out; return out;
} }
+3 -3
View File
@@ -254,8 +254,8 @@ Player * Rules::loadPlayerMomir(GameObserver* observer, int isAI)
Player * Rules::loadPlayerRandom(GameObserver* observer, int isAI, int mode) Player * Rules::loadPlayerRandom(GameObserver* observer, int isAI, int mode)
{ {
int color1 = 1 + WRand() % 5; int color1 = 1 + WRand(true) % 5;
int color2 = 1 + WRand() % 5; int color2 = 1 + WRand(true) % 5;
int color0 = Constants::MTG_COLOR_ARTIFACT; int color0 = Constants::MTG_COLOR_ARTIFACT;
if (mode == GAME_TYPE_RANDOM1) color2 = color1; if (mode == GAME_TYPE_RANDOM1) color2 = color1;
int colors[] = { color1, color2, color0 }; 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 (g->currentPlayer->playMode!= Player::MODE_TEST_SUITE && g->mRules->gamemode!= GAME_TYPE_STORY)
{ {
if(OptionWhosFirst::WHO_R == options[Options::FIRSTPLAYER].number) 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) if(OptionWhosFirst::WHO_O == options[Options::FIRSTPLAYER].number)
initState.player = 1; initState.player = 1;
} }
+34 -34
View File
@@ -46,22 +46,22 @@ void TextScroller::Update(float dt)
{ {
if (!strings.size()) return; if (!strings.size()) return;
start += mScrollSpeed * dt; start += mScrollSpeed * dt;
WFont * mFont = WResourceManager::Instance()->GetWFont(fontId); WFont * mFont = WResourceManager::Instance()->GetWFont(fontId);
if (start > mFont->GetStringWidth(mText.c_str())) if (start > mFont->GetStringWidth(mText.c_str()))
{ {
start = -mWidth; start = -mWidth;
if (mRandom) if (mRandom)
{ {
currentId = (rand() % strings.size()); currentId = (rand() % strings.size());
} }
else else
{ {
currentId++; currentId++;
if (currentId >= strings.size()) currentId = 0; if (currentId >= strings.size()) currentId = 0;
} }
mText = strings[currentId]; mText = strings[currentId];
} }
} }
void TextScroller::Render() void TextScroller::Render()
@@ -119,27 +119,27 @@ void VerticalTextScroller::Add( string text )
*/ */
void VerticalTextScroller::Update(float dt) 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 if ( mY <= mMarginY ) // top line has disappeared
{ {
timer = 0; timer = 0;
// now readjust mText // now readjust mText
size_t nbLines = 1; size_t nbLines = 1;
vector<string> displayText = split( mText, '\n'); vector<string> displayText = split( mText, '\n');
vector<string> newDisplayText; vector<string> newDisplayText;
for ( size_t i = nbLines; i < displayText.size(); ++i ) for ( size_t i = nbLines; i < displayText.size(); ++i )
newDisplayText.push_back( displayText[i] ); newDisplayText.push_back( displayText[i] );
for ( size_t i = 0; i < nbLines; ++i ) for ( size_t i = 0; i < nbLines; ++i )
newDisplayText.push_back( displayText[i] ); newDisplayText.push_back( displayText[i] );
mText = join( newDisplayText, "\n" ); mText = join( newDisplayText, "\n" );
mY = mOriginalY; mY = mOriginalY;
} }
++timer; ++timer;
mY -= currentYOffset; mY -= currentYOffset;
} }
void VerticalTextScroller::Render() void VerticalTextScroller::Render()
+5 -4
View File
@@ -68,13 +68,13 @@ void loadRandValues(string s)
ptrdiff_t MRand (ptrdiff_t i) ptrdiff_t MRand (ptrdiff_t i)
{ {
return WRand()%i; return WRand(true)%i;
} }
int WRand() int WRand(bool log)
{ {
int result; int result;
if (!loadedRandomValues.size()) if (!loadedRandomValues.size() || !log)
{ {
result = rand(); result = rand();
} }
@@ -83,7 +83,8 @@ int WRand()
result = loadedRandomValues.front(); result = loadedRandomValues.front();
loadedRandomValues.pop(); loadedRandomValues.pop();
} }
usedRandomValues.push(result); if(log)
usedRandomValues.push(result);
return result; return result;
} }