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:
@@ -24,4 +24,4 @@ public:
|
||||
static string Process(const string& s);
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -44,7 +44,6 @@ public:
|
||||
void setMenuObject(Targetable * object, bool must = false);
|
||||
void setCustomMenuObject(Targetable * object, bool must = false,vector<MTGAbility*>abilities = vector<MTGAbility*>());
|
||||
void ButtonPressed(int controllerid, int controlid);
|
||||
void doMultipleChoice(int choice = -1);
|
||||
void ButtonPressedOnMultipleChoice(int choice = -1);
|
||||
void doReactTo(int menuIndex);
|
||||
TargetChooser * getCurrentTargetChooser();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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];
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -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<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 * 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
|
||||
|
||||
@@ -28,7 +28,6 @@ private:
|
||||
Credits * credits;
|
||||
int mGamePhase;
|
||||
Player * mCurrentPlayer;
|
||||
vector<Player *> 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
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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&);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -97,7 +97,7 @@ int AIAction::clickMultiAct(vector<Targetable*>& 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<Targetable*>& 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())
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -124,4 +124,4 @@ string AutoLineMacro::Process(const string& s)
|
||||
result = gAutoLineMacros[i]->process(result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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<float>(options[Options::INTERRUPT_SECONDS].number * extraTime);
|
||||
timer = static_cast<float>(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)
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 << " " <<currentGamePhase;
|
||||
logAction(currentPlayer, stream.str());
|
||||
}
|
||||
|
||||
if(getCurrentTargetChooser() && getCurrentTargetChooser()->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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<DeckMetaData*> 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<DeckMetaData *> * 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<DeckMetaData *> * 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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<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)
|
||||
{
|
||||
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;
|
||||
|
||||
@@ -134,4 +134,4 @@ IconButton::~IconButton()
|
||||
ostream& IconButton::toString(ostream& out) const
|
||||
{
|
||||
return out << "IconButton ::: mHasFocus : " << mHasFocus;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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<string> displayText = split( mText, '\n');
|
||||
vector<string> 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<string> displayText = split( mText, '\n');
|
||||
vector<string> 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()
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user