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
+2 -2
View File
@@ -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())
+1 -4
View File
@@ -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);
+1 -1
View File
@@ -124,4 +124,4 @@ string AutoLineMacro::Process(const string& s)
result = gAutoLineMacros[i]->process(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)
{
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;
}
+9 -7
View File
@@ -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)
+3 -3
View File
@@ -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)
{
+2 -1
View File
@@ -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)
+1 -1
View File
@@ -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)
+1
View File
@@ -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);
+3 -3
View File
@@ -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;
+161 -30
View File
@@ -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();
}
}
+29 -90
View File
@@ -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
}
}
}
+28 -6
View File
@@ -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;
+1 -1
View File
@@ -134,4 +134,4 @@ IconButton::~IconButton()
ostream& IconButton::toString(ostream& out) const
{
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.find("#AUTO_DEFINE ") == 0)
{
AutoLineMacro::AddMacro(s.substr(13));
string toAdd = s.substr(13);
AutoLineMacro::AddMacro(toAdd);
continue;
}
-3
View File
@@ -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()
+1 -1
View File
@@ -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);
+4 -4
View File
@@ -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);
+11 -3
View File
@@ -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;
}
+3 -3
View File
@@ -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;
}
+34 -34
View File
@@ -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()
+5 -4
View File
@@ -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;
}