#include "PrecompiledHeader.h" #include "DeckMenu.h" #include "GameStateDuel.h" #include "utils.h" #include "AIPlayer.h" #include "AIMomirPlayer.h" #include "PlayerData.h" #include "DeckStats.h" #include "DeckManager.h" #include "DeckMetaData.h" #include "Credits.h" #include "Translate.h" #include "Rules.h" #include "ModRules.h" #include "GameApp.h" #include #ifdef TESTSUITE #include "TestSuiteAI.h" #endif #ifdef NETWORK_SUPPORT #include "NetworkPlayer.h" #endif #if defined (WIN32) || defined (LINUX) || defined(IOS) #include #endif enum ENUM_DUEL_STATE { DUEL_STATE_UNSET = 0, DUEL_STATE_START, DUEL_STATE_END, DUEL_STATE_CHOOSE_DECK1, DUEL_STATE_DECK1_DETAILED_INFO, DUEL_STATE_DECK2_DETAILED_INFO, DUEL_STATE_CHOOSE_DECK1_TO_2, DUEL_STATE_CHOOSE_DECK1_TO_PLAY, DUEL_STATE_CHOOSE_DECK2_TO_1, DUEL_STATE_CHOOSE_DECK2, DUEL_STATE_CHOOSE_DECK2_TO_2, // for tournament selection DUEL_STATE_CHOOSE_DECK2_TO_PLAY, DUEL_STATE_ERROR_NO_DECK, DUEL_STATE_CANCEL, DUEL_STATE_PLAY, DUEL_STATE_BACK_TO_MAIN_MENU, DUEL_STATE_MENU, DUEL_STATE_OPPONENT_WAIT, // used For Network only DUEL_STATE_PREPARE_CNOGMENU, DUEL_STATE_CHOOSE_NUMBER_OF_GAMES, DUEL_STATE_CNOGMENU_IS_CLOSING, DUEL_STATE_CANCEL_CNOGMENU, DUEL_STATE_CONTINUE_TOURNAMENT, DUEL_STATE_SHOW_SCORE, DUEL_STATE_MENU_TO_SCORE, DUEL_STATE_END_OF_GAME, DUEL_STATE_END_OF_MATCH, DUEL_STATE_END_OF_TOURNAMENT, DUEL_STATE_ERROR }; const char * stateStrings[] = { "unset", "start", "end", "choose_deck1", "deck1_detailed_info", "deck2_detailed_info", "choose_deck1_to_2", "choose_deck1_to_play","choose_deck2_to_1", "choose_deck2", "choose_deck2_to_2", "choose_deck2_to_play","error_no_deck", "cancel", "play", "back_to_main_menu", "menu", "oponent_wait","prepare_cnogmenu", "choose_number_games","cnogmenu_closes","cancel_cnogmenu","continue_tournament","show_score","menu_to_score","end_of_game","end_of_match","end_of_tournament", "error"}; enum ENUM_DUEL_MENUS { DUEL_MENU_GAME_MENU, DUEL_MENU_CHOOSE_DECK, DUEL_MENU_CHOOSE_OPPONENT, DUEL_MENU_DETAILED_DECK1_INFO, DUEL_MENU_CHOOSE_NUMBER_OF_GAMES, DUEL_MENU_DETAILED_DECK2_INFO }; enum ENUM_CNOGMENU_ITEMS { CNOGMENU_ITEM_SINGLE_GAME, CNOGMENU_ITEM_CONTINUE_TOURNAMENT, CNOGMENU_ITEM_BESTOF3, CNOGMENU_ITEM_BESTOF5, CNOGMENU_ITEM_BESTOF7, CNOGMENU_ITEM_BESTOF13, CNOGMENU_ITEM_DELTA2, CNOGMENU_ITEM_DELTA3, CNOGMENU_ITEM_CONSECUTIVE2, CNOGMENU_ITEM_CONSECUTIVE3, CNOGMENU_ITEM_3GAMES, CNOGMENU_ITEM_5GAMES, CNOGMENU_ITEM_10GAMES, CNOGMENU_ITEM_25GAMES, CNOGMENU_ITEM_50GAMES, CNOGMENU_ITEM_100GAMES, CNOGMENU_ITEM_BESTOF7PLAYOFF, CNOGMENU_ITEM_CANCEL }; enum ENUM_MATCHMODES { MATCHMODE_FIXED = 1, MATCHMODE_BESTOF = 2, MATCHMODE_DELTA = 3, MATCHMODE_CONSECUTIVE = 4 }; enum ENUM_TOURNAMENTMODES { TOURNAMENTMODES_ENDLESS = 1, TOURNAMENTMODES_GAUNTLET = 2, TOURNAMENTMODES_KO = 3, TOURNAMENTMODES_DOUBLEKO = 4, TOURNAMENTMODES_ROUNDROBIN = 5 }; //enum ENUM_GAMEMENU_ITEMS //{ // GAMEMENU_ITEM_CONTINUE, // GAMEMENU_ITEM_SPEED_STEPWISE, // GAMEMENU_ITEM_CONCEDE_GAME, // GAMEMENU_ITEM_CONCEDE_MATCH //}; enum ENUM_OPERATION_LEVELS { OPLEVEL_NEW = 1, OPLEVEL_NEXT_MATCH = 2, OPLEVEL_NEXT_GAME = 3, OPLEVEL_GAME_ACTIV = 4 }; int GameStateDuel::selectedPlayerDeckId = 0; int GameStateDuel::selectedAIDeckId = 0; static std::string kBgFile = ""; GameStateDuel::GameStateDuel(GameApp* parent) : GameState(parent, "duel") { cnogmenu = NULL; tournament = new Tournament(); premadeDeck = false; game = NULL; deckmenu = NULL; opponentMenu = NULL; menu = NULL; popupScreen = NULL; mGamePhase = DUEL_STATE_UNSET; taskList = NEW TaskList(); #ifdef TESTSUITE testSuite = NULL; #endif #ifdef AI_CHANGE_TESTING totalTestGames = 0; testPlayer2Victories = 0; totalAIDecks = 0; { int found = 1; while (found) { found = 0; char buffer[512]; sprintf(buffer, "ai/baka/deck%i.txt", totalAIDecks + 1); if (FileExists(buffer)) { found = 1; totalAIDecks++; } } } #endif credits = NULL; } GameStateDuel::~GameStateDuel() { End(); SAFE_DELETE(tournament); kBgFile = ""; //Reset the chosen backgorund. } void GameStateDuel::Start() { JRenderer * renderer = JRenderer::GetInstance(); renderer->EnableVSync(true); OpponentsDeckid = 0; bool createDeckMenu=true; // create only a deckmenu if not in tournament SAFE_DELETE(taskList); taskList = NEW TaskList(); #ifdef NETWORK_SUPPORT if(!mParent->mpNetwork) { #endif //NETWORK_SUPPORT game = NEW GameObserver(WResourceManager::Instance(), JGE::GetInstance()); #ifdef NETWORK_SUPPORT } else { game = NEW NetworkGameObserver(mParent->mpNetwork, WResourceManager::Instance(), JGE::GetInstance()); } #endif //NETWORK_SUPPORT #ifdef TESTSUITE SAFE_DELETE(testSuite); testSuite = NEW TestSuite("test/_tests.txt"); #endif setGamePhase(DUEL_STATE_CHOOSE_DECK1); credits = NEW Credits(); // match mode is available in classic and demo mode. // in both modes player 1 is from type PLAYER_TYPE_CPU if (mParent->players[1] == PLAYER_TYPE_CPU && (mParent->gameType == GAME_TYPE_COMMANDER || mParent->gameType == GAME_TYPE_CLASSIC || mParent->gameType == GAME_TYPE_DEMO)) { //initialize match // only reset "Played Games" and "Victories" info if we didn't come here from within a match tournament->Start(); if (tournament->getOpLevel()< OPLEVEL_NEXT_GAME) setGamePhase(DUEL_STATE_PREPARE_CNOGMENU); else { createDeckMenu=false; //there is a tournament running and we do not need a deckmenu SAFE_DELETE(deckmenu); } tournamentSelection=false; } menu = NULL; int decksneeded = 0; for (int i = 0; i < 2; i++) { if (createDeckMenu && mParent->players[i] == PLAYER_TYPE_HUMAN) { //DeckManager::EndInstance(); decksneeded = 1; deckmenu = NEW DeckMenu(DUEL_MENU_CHOOSE_DECK, this, Fonts::OPTION_FONT, "Choose a Deck", GameStateDuel::selectedPlayerDeckId, true, false); deckmenu->enableDisplayDetailsOverride(); DeckManager *deckManager = DeckManager::GetInstance(); vector playerDeckList = BuildDeckList(options.profileFile(), "", NULL, 0, mParent->gameType); int nbDecks = playerDeckList.size(); if (nbDecks) decksneeded = 0; if (nbDecks > 1) deckmenu->Add(MENUITEM_RANDOM_PLAYER, "Random", "Play with a random deck."); renderDeckMenu(deckmenu, playerDeckList); // save the changes to the player deck list maintained in DeckManager deckManager->updateMetaDataList(&playerDeckList, false); playerDeckList.clear(); break; } } if (deckmenu) { if (decksneeded) { if (gModRules.general.hasDeckEditor()) { //translate deck creating desc Translator * t = Translator::GetInstance(); string desc = _("Highly recommended to get the full Wagic experience!").c_str(); map::iterator it = t->deckValues.find(_("Create your Deck!").c_str()); if (it != t->deckValues.end()) desc = it->second; deckmenu->Add(MENUITEM_NEW_DECK, _("Create your Deck!").c_str(), desc); } premadeDeck = true; fillDeckMenu(deckmenu, _("player/premade").c_str(), "", NULL, 0, mParent->gameType); } else if (gModRules.general.hasDeckEditor()) { deckmenu->Add(MENUITEM_NEW_DECK, _("New Deck...").c_str(), _("Create a new deck to play with.").c_str()); } deckmenu->Add(MENUITEM_CANCEL, _("Main Menu").c_str(), _("Return to Main Menu").c_str()); } else if(createDeckMenu && (mParent->players[0] == PLAYER_TYPE_CPU && mParent->players[1] == PLAYER_TYPE_CPU)) { //DeckManager::EndInstance(); deckmenu = NEW DeckMenu(DUEL_MENU_CHOOSE_DECK, this, Fonts::OPTION_FONT, "Choose a Deck", GameStateDuel::selectedPlayerDeckId, true, true); int nmbDecks = options[Options::CHEATMODEAIDECK].number ? 1000 : options[Options::AIDECKS_UNLOCKED].number; if (nmbDecks > 1) { deckmenu->Add(MENUITEM_ENDLESSDEMO,"Endless demo",_("Random AI decks plays again each other.").c_str()); deckmenu->Add(MENUITEM_KO_TOURNAMENT,"KO Tournament",_("Starts a Knockout Tournament of all available AI-Decks.").c_str()); deckmenu->Add(MENUITEM_DOUBLEKO_TOURNAMENT,"Double KO Tournament",_("Starts a double Knockout Tournament of all available AI-Decks.").c_str()); deckmenu->Add(MENUITEM_GAUNTLET,"Gauntlet",_("Prove your mettle against each and every opponent, one at a time.").c_str()); deckmenu->Add(MENUITEM_RANDOM_PLAYER, "Random", _("Selects a random deck.").c_str()); } //deckmenu->enableDisplayDetailsOverride(); DeckManager *deckManager = DeckManager::GetInstance(); vector playerDeckList; playerDeckList = fillDeckMenu(deckmenu, "ai/baka", "ai_baka", NULL, nmbDecks, mParent->gameType); //printf("nmbDecks %i\n",playerDeckList.size()); //renderDeckMenu(deckmenu, playerDeckList); // save the changes to the player deck list maintained in DeckManager deckManager->updateMetaDataList(&playerDeckList, true); //save the real number of available decks tournament->setAvailableDecks(playerDeckList.size()); playerDeckList.clear(); deckmenu->Add(MENUITEM_CANCEL, _("Main Menu").c_str(), _("Return to Main Menu.").c_str()); } mEngine->ResetInput(); } void GameStateDuel::initRand(unsigned int seed) { if (!seed) seed = static_cast(time(0)); srand(seed); } #ifdef TESTSUITE void GameStateDuel::loadTestSuitePlayers() { if (!testSuite) return; initRand(testSuite->seed); SAFE_DELETE(game); game = new GameObserver(WResourceManager::Instance(), JGE::GetInstance()); testSuite->setObserver(game); for (int i = 0; i < 2; i++) { game->loadTestSuitePlayer(i, testSuite); } mParent->gameType = testSuite->getGameType(); game->startGame(mParent->gameType, mParent->rules); } #endif void GameStateDuel::End() { DebugTrace("Ending GameStateDuel"); #ifdef TRACK_OBJECT_USAGE ObjectAnalytics::DumpStatistics(); #endif JRenderer::GetInstance()->EnableVSync(false); SAFE_DELETE(game); premadeDeck = false; SAFE_DELETE(credits); SAFE_DELETE(menu); SAFE_DELETE(opponentMenu); SAFE_DELETE(deckmenu); SAFE_DELETE(popupScreen); SAFE_DELETE(taskList); //reset player for next match (only if actual match is finished) tournament->End(); #ifdef TESTSUITE SAFE_DELETE(testSuite); #endif MTGAbility::deletedpointers.clear(); // Clear the list of deallocated pointer. kBgFile = ""; //Reset the chosen backgorund. } //TODO Move This to utils or ResourceManager. Don't we have more generic functions that can do that? bool GameStateDuel::MusicExist(string FileName) { if (FileName.length() < 1) return false; // Fixed a problem when Music filename is empty. string musicFilename = WResourceManager::Instance()->musicFile(FileName); if (musicFilename.length() < 1) return false; return FileExists(musicFilename); } void GameStateDuel::ConstructOpponentMenu() { if (opponentMenu == NULL) { opponentMenu = NEW DeckMenu(DUEL_MENU_CHOOSE_OPPONENT, this, Fonts::OPTION_FONT, "Choose Opponent", GameStateDuel::selectedAIDeckId, true, true); int nbUnlockedDecks = options[Options::CHEATMODEAIDECK].number ? 1000 : options[Options::AIDECKS_UNLOCKED].number; if ((mParent->gameType == GAME_TYPE_COMMANDER || mParent->gameType == GAME_TYPE_CLASSIC || mParent->gameType == GAME_TYPE_DEMO) && mParent->players[1] == PLAYER_TYPE_CPU) { if (!tournamentSelection) { if (!tournament->isGauntlet()) { if (mParent->players[0] == PLAYER_TYPE_HUMAN){ opponentMenu->Add(MENUITEM_KO_TOURNAMENT,"KO Tournament",_("Starts a Knockout Tournament against selected AI-Decks! You have to win all matches. 4 Decks -> 2 Matches, 7 Decks -> 3 Matches, 16 Decks -> 4 Matches, 32 Decks -> 5 Matches, 64 Decks -> 6 Matches, 128 Decks -> 7 Matches, 256 Decks -> 8 Matches.").c_str()); opponentMenu->Add(MENUITEM_DOUBLEKO_TOURNAMENT,"Double KO",_("Starts a Double Knockout Tournament against selected AI-Decks!. You can loose once, but not more!. 4 Decks -> 3 Matches, 7 Decks -> 4 Matches, 16 Decks -> 5 Matches, 32 Decks -> 6 Matches, 64 Decks -> 7 Matches, 128 Decks -> 8 Matches, 256 Decks -> 9 Matches.").c_str()); } opponentMenu->Add(MENUITEM_RR_TOURNAMENT,"Round Robin Tournament",_("Starts an all vs all tournament!. Firstly, in a selection process participating AI-Decks can be chosen. The tournament state is saved after each game and can be continued!.").c_str()); } if (mParent->players[0] == PLAYER_TYPE_CPU) opponentMenu->Add(MENUITEM_GAUNTLET,"Gauntlet",_("Prove your mettle against each and every opponent, one at a time.").c_str()); opponentMenu->Add(MENUITEM_RANDOM_AI, "Random"); if (mParent->players[0] == PLAYER_TYPE_HUMAN) opponentMenu->Add(MENUITEM_RANDOM_AI_HARD, "Random (Not easy)",_("Selects a random AI deck with hard or normal difficulty.").c_str()); } else { opponentMenu->Add(MENUITEM_START_TOURNAMENT,"Begin Tournament",(std::string("Stop selection and start.")+tournament->exportTournamentDescription()).c_str()); if (tournament->getTournamentMode()==TOURNAMENTMODES_KO || tournament->getTournamentMode()==TOURNAMENTMODES_DOUBLEKO) { opponentMenu->Add(MENUITEM_FILL_NEXT_STAGE_HARD,"Fill stage (Not easy)",_("Fill next stage with random hard or normal opponents. 1 opponent -> 1 stage, 3 opponents -> 2 stages, 7 opponents -> 3 stages, 15 opponents -> 4 stages, 31 opponents -> 5 stages, 63 opponents -> 6 stages, 127 opponents -> 7 stages, 255 opponents -> 8 stages.").c_str()); opponentMenu->Add(MENUITEM_FILL_NEXT_STAGE,"Fill stage",_("Fill next stage with random opponents. 1 opponent -> 1 stage, 3 opponents -> 2 stages, 7 opponents -> 3 stages, 15 opponents -> 4 stages, 31 opponents -> 5 stages, 63 opponents -> 6 stages, 127 opponents -> 7 stages, 255 opponents -> 8 stages.").c_str()); } else { if (mParent->players[0] == PLAYER_TYPE_HUMAN) opponentMenu->Add(MENUITEM_RANDOM_AI_HARD, "Random (Not easy)",_("Selects a random AI deck with hard or normal difficulty.").c_str()); opponentMenu->Add(MENUITEM_RANDOM_AI, "Random"); } } } else if (mParent->gameType == GAME_TYPE_STONEHEWER && mParent->players[1] == PLAYER_TYPE_CPU){ opponentMenu->Add(MENUITEM_RANDOM_AI, "Random"); if (mParent->players[0] == PLAYER_TYPE_HUMAN) opponentMenu->Add(MENUITEM_RANDOM_AI_HARD, "Random (Not easy)",_("Selects a random AI deck with hard or normal difficulty.").c_str()); } if (options[Options::EVILTWIN_MODE_UNLOCKED].number && !tournamentSelection) opponentMenu->Add(MENUITEM_EVIL_TWIN, "Evil Twin", _("Can you defeat yourself?").c_str()); DeckManager * deckManager = DeckManager::GetInstance(); vector opponentDeckList; opponentDeckList = fillDeckMenu(opponentMenu, "ai/baka", "ai_baka", game->getPlayer(0), nbUnlockedDecks, mParent->gameType); deckManager->updateMetaDataList(&opponentDeckList, true); tournament->setAvailableDecks(opponentDeckList.size()); opponentMenu->Add(MENUITEM_CANCEL, "Cancel", _("Choose a different player deck").c_str()); opponentDeckList.clear(); } } void GameStateDuel::setGamePhase(int newGamePhase) { if (mGamePhase == newGamePhase) return; if (mGamePhase) JGE::GetInstance()->SendCommand("leaveduelphase:" + string(stateStrings[mGamePhase])); mGamePhase = newGamePhase; if (mGamePhase ) JGE::GetInstance()->SendCommand("enterduelphase:" + string(stateStrings[mGamePhase])); } #ifdef AI_CHANGE_TESTING boost::mutex GameStateDuel::mMutex; void GameStateDuel::ThreadProc(void* inParam) { GameStateDuel* instance = reinterpret_cast(inParam); float counter = 1.0f; while(instance->mGamePhase != DUEL_STATE_BACK_TO_MAIN_MENU) { GameObserver observer; int oldTurn = -1; int oldPhase = -1; int stagnationCounter = -1; observer.loadPlayer(0, PLAYER_TYPE_CPU_TEST); observer.loadPlayer(1, PLAYER_TYPE_CPU_TEST); observer.startGame(instance->mParent->gameType, instance->mParent->rules); while(!observer.didWin()) { if(observer.turn == oldTurn && observer.getCurrentGamePhase() == oldPhase) { stagnationCounter++; } else { stagnationCounter = 0; oldTurn = observer.turn; oldPhase = observer.getCurrentGamePhase(); } if(stagnationCounter >= 1000) { observer.dumpAssert(false); } observer.Update(counter++); } instance->handleResults(&observer); } } #endif //AI_CHANGE_TESTING void GameStateDuel::Update(float dt) { switch (mGamePhase) { case DUEL_STATE_ERROR_NO_DECK: if (JGE_BTN_OK == mEngine->ReadButton()) mParent->SetNextState(GAME_STATE_DECK_VIEWER); break; // The next state prepares the "Choose number of games" menu (PSY) case DUEL_STATE_PREPARE_CNOGMENU: SAFE_DELETE(cnogmenu); cnogmenu = NEW SimpleMenu(JGE::GetInstance(),WResourceManager::Instance(), DUEL_MENU_CHOOSE_NUMBER_OF_GAMES, this, Fonts::MENU_FONT,35,25,"How many games per match?"); cnogmenu->Add(CNOGMENU_ITEM_SINGLE_GAME,"Single Game",""); if (tournament->checkTournamentFile(mParent->players[0] == PLAYER_TYPE_CPU)) cnogmenu->Add(CNOGMENU_ITEM_CONTINUE_TOURNAMENT,"Continue Tournament",""); cnogmenu->Add(CNOGMENU_ITEM_BESTOF3,"Best of 3",""); cnogmenu->Add(CNOGMENU_ITEM_BESTOF5,"Best of 5",""); cnogmenu->Add(CNOGMENU_ITEM_BESTOF7,"Best of 7",""); cnogmenu->Add(CNOGMENU_ITEM_BESTOF13,"Best of 13",""); cnogmenu->Add(CNOGMENU_ITEM_DELTA2,"2 wins difference",""); cnogmenu->Add(CNOGMENU_ITEM_DELTA3,"3 wins difference",""); cnogmenu->Add(CNOGMENU_ITEM_CONSECUTIVE2,"2 in a row",""); cnogmenu->Add(CNOGMENU_ITEM_CONSECUTIVE3,"3 in a row",""); if (mParent->players[0] == PLAYER_TYPE_CPU && mParent->players[1] == PLAYER_TYPE_CPU) { //games with fixed game lenght are boring for human player cnogmenu->Add(CNOGMENU_ITEM_3GAMES,"3 Games",""); cnogmenu->Add(CNOGMENU_ITEM_5GAMES,"5 Games",""); cnogmenu->Add(CNOGMENU_ITEM_10GAMES,"10 Games",""); // i think nobody will play 25 games against the ai cnogmenu->Add(CNOGMENU_ITEM_25GAMES,"25 Games",""); // i think nobody will play 50 games against the ai cnogmenu->Add(CNOGMENU_ITEM_50GAMES,"50 Games",""); // i think nobody will play 100 games against the ai cnogmenu->Add(CNOGMENU_ITEM_100GAMES,"100 Games",""); cnogmenu->Add(CNOGMENU_ITEM_BESTOF7PLAYOFF,"Best of 7 Playoff",""); } cnogmenu->Add(CNOGMENU_ITEM_CANCEL,"Cancel",""); setGamePhase(DUEL_STATE_CHOOSE_NUMBER_OF_GAMES); break; /* The next state displays the "Choose number of games" menu and waits for input. (PSY) */ case DUEL_STATE_CHOOSE_NUMBER_OF_GAMES: cnogmenu->Update(dt); break; // The next state waits until cnogmenu is fully closed case DUEL_STATE_CNOGMENU_IS_CLOSING: if (cnogmenu->isClosed()) { // Is the closing animation finished? setGamePhase(DUEL_STATE_CHOOSE_DECK1); SAFE_DELETE(cnogmenu); } else cnogmenu->Update(dt); break; // The next state waits until cnogmenu is fully closed case DUEL_STATE_CONTINUE_TOURNAMENT: if (cnogmenu && cnogmenu->isClosed()) { // Is the closing animation finished? // contruct and close opponentmenu for loading decknames ConstructOpponentMenu(); opponentMenu->Close(); //setGamePhase(DUEL_STATE_PLAY); SAFE_DELETE(cnogmenu); } else if (opponentMenu && opponentMenu->isClosed()) { // Is the closing animation finished then we can start to play! setGamePhase(DUEL_STATE_PLAY); SAFE_DELETE(opponentMenu); } else if (cnogmenu) cnogmenu->Update(dt); else if (opponentMenu) opponentMenu->Update(dt); break; // The next state occurs when the player selected "Cancel" in the cnogmenu case DUEL_STATE_CANCEL_CNOGMENU: cnogmenu->Update(dt); if (cnogmenu->isClosed()) { // wait until menu has closed, then go back to main menu setGamePhase(DUEL_STATE_BACK_TO_MAIN_MENU); SAFE_DELETE(cnogmenu); } break; case DUEL_STATE_DECK1_DETAILED_INFO: case DUEL_STATE_DECK2_DETAILED_INFO: popupScreen->Update(dt); break; case DUEL_STATE_CHOOSE_DECK1: if (!mParent->rules->canChooseDeck()) { setGamePhase(DUEL_STATE_PLAY); } #ifdef TESTSUITE else if (mParent->players[1] == PLAYER_TYPE_TESTSUITE) { testSuite->setRules(mParent->rules); if (testSuite && testSuite->loadNext()) { loadTestSuitePlayers(); setGamePhase(DUEL_STATE_PLAY); testSuite->initGame(game); } else { if (!game) { setGamePhase(DUEL_STATE_ERROR); } else { setGamePhase(DUEL_STATE_END); } } } #endif else { if (mParent->players[0] == PLAYER_TYPE_HUMAN) { if (!popupScreen || popupScreen->isClosed()) deckmenu->Update(dt); } else { if (mParent->players[1] == PLAYER_TYPE_CPU && (mParent->gameType == GAME_TYPE_CLASSIC || mParent->gameType == GAME_TYPE_COMMANDER || mParent->gameType == GAME_TYPE_DEMO)) { if (deckmenu && (!popupScreen || popupScreen->isClosed())) deckmenu->Update(dt); } else { game->loadPlayer(0, mParent->players[0]); setGamePhase(DUEL_STATE_CHOOSE_DECK2); } } } break; case DUEL_STATE_CHOOSE_DECK1_TO_PLAY: if (deckmenu->isClosed()) { setGamePhase(DUEL_STATE_PLAY); SAFE_DELETE(deckmenu); } else deckmenu->Update(dt); break; case DUEL_STATE_CHOOSE_DECK1_TO_2: if (deckmenu->isClosed()) setGamePhase(DUEL_STATE_CHOOSE_DECK2); else deckmenu->Update(dt); break; case DUEL_STATE_CHOOSE_DECK2_TO_1: if (opponentMenu->isClosed()) { setGamePhase(DUEL_STATE_CHOOSE_DECK1); SAFE_DELETE(opponentMenu); } else opponentMenu->Update(dt); break; case DUEL_STATE_CHOOSE_DECK2_TO_2: if (opponentMenu->isClosed()) { setGamePhase(DUEL_STATE_CHOOSE_DECK2); SAFE_DELETE(opponentMenu); } else opponentMenu->Update(dt); break; case DUEL_STATE_CHOOSE_DECK2: if (mParent->players[1] == PLAYER_TYPE_HUMAN) deckmenu->Update(dt); else { if (mParent->players[0] == PLAYER_TYPE_HUMAN) { ConstructOpponentMenu(); opponentMenu->Update(dt); } else { if (mParent->players[1] == PLAYER_TYPE_CPU && (mParent->gameType == GAME_TYPE_CLASSIC || mParent->gameType == GAME_TYPE_COMMANDER || mParent->gameType == GAME_TYPE_DEMO)) { ConstructOpponentMenu(); opponentMenu->Update(dt); } else { game->loadPlayer(1, mParent->players[1]); setGamePhase(DUEL_STATE_PLAY); } } } break; case DUEL_STATE_CHOOSE_DECK2_TO_PLAY: if (mParent->players[1] == PLAYER_TYPE_HUMAN) { if (deckmenu && deckmenu->isClosed()) setGamePhase(DUEL_STATE_PLAY); else if(deckmenu) deckmenu->Update(dt); } else { if (opponentMenu && opponentMenu->isClosed()) { setGamePhase(DUEL_STATE_PLAY); SAFE_DELETE(opponentMenu); } else if(opponentMenu) opponentMenu->Update(dt); } break; // this called after each match and tournament case DUEL_STATE_SHOW_SCORE: if ((JGE_BTN_OK == mEngine->ReadButton()) || ( mParent->players[0] == PLAYER_TYPE_CPU && mParent->players[1] == PLAYER_TYPE_CPU && !(game && !game->didWin()) && !tournament->isMatchFinished())) { //check if Match and tournament is over if (game->didWin() && tournament->isMatchFinished() && !tournament->isNextDeckFound()) { tournament->setScoreDisplayed(true); tournament->setOpLevel(OPLEVEL_NEW); tournament->End(); //Display credits for human player if (mParent->players[0] == PLAYER_TYPE_HUMAN) { tournament->save(false); setGamePhase(DUEL_STATE_END); } else { setGamePhase(DUEL_STATE_END_OF_TOURNAMENT); } } else { // we have to play again if (game->didWin()) tournament->setScoreDisplayed(true); setGamePhase(DUEL_STATE_PLAY); } } break; // The next state occurs after the *match* has ended: case DUEL_STATE_END_OF_MATCH: break; // The next state occurs after the end of the last match of the tournament: case DUEL_STATE_END_OF_TOURNAMENT: if ( (JGE_BTN_OK == mEngine->ReadButton()) || (mParent->players[0] == PLAYER_TYPE_CPU && mParent->players[1] == PLAYER_TYPE_CPU) ) { setGamePhase(DUEL_STATE_BACK_TO_MAIN_MENU); } break; case DUEL_STATE_PLAY: if (!game->isStarted()) { game->startGame(mParent->gameType, mParent->rules); //start of in game music code musictrack = ""; //check opponent id and choose the music track based on it if (OpponentsDeckid) { char temp[4096]; sprintf(temp, "ai_baka_music%i.mp3", OpponentsDeckid); musictrack.assign(temp); } // Now it's possibile to randomly use up to 20 new sound tracks for duels (if random index is 20, it will be played the default "ai_baka_music.mp3" file). if (!MusicExist(musictrack)){ char temp[4096]; sprintf(temp, "Battlefield/TrackDuel%i.mp3", std::rand() % 21); musictrack.assign(temp); } // Try if there is a sound track for specific game type. if (!MusicExist(musictrack)){ if (mParent->gameType == GAME_TYPE_CLASSIC) musictrack = "ai_baka_music.mp3"; else if (mParent->gameType == GAME_TYPE_COMMANDER) musictrack = "ai_baka_music_commander.mp3"; else if (mParent->gameType == GAME_TYPE_MOMIR) musictrack = "ai_baka_music_momir.mp3"; else if (mParent->gameType == GAME_TYPE_RANDOM1 || mParent->gameType == GAME_TYPE_RANDOM2 || mParent->gameType == GAME_TYPE_RANDOM3 || mParent->gameType == GAME_TYPE_RANDOM5) musictrack = "ai_baka_music_random.mp3"; else if (mParent->gameType == GAME_TYPE_HORDE) musictrack = "ai_baka_music_horde.mp3"; else if (mParent->gameType == GAME_TYPE_SET_LIMITED) musictrack = "ai_baka_music_limited.mp3"; } if (!MusicExist(musictrack)) musictrack = "ai_baka_music.mp3"; #if defined (PSP) musictrack = "ai_baka_music.mp3"; #endif GameApp::playMusic(musictrack); // init Score table if ( (mParent->gameType == GAME_TYPE_COMMANDER || mParent->gameType == GAME_TYPE_CLASSIC || mParent->gameType == GAME_TYPE_DEMO) && mParent->players[1] == PLAYER_TYPE_CPU) { tournament->updateScoreTable(game->players[0], game->players[1], mParent->gameType); tournament->setScoreDisplayed(false); } } game->Update(dt); //run a "post update" init call in the rules. This is for things such as Manapool, which gets emptied in the update // That's mostly because of a legacy bug, where we use the update sequence for some things when we should use events (such as phase changes) mParent->rules->postUpdateInit(game); #ifdef NETWORK_SUPPORT if(mParent->mpNetwork) ((NetworkGameObserver*)game)->synchronize(); #endif if (game->didWin()) { //the following section will be called only in a classic or demo gamemode and if a tournament or match with more than one game is activ if ( (mParent->gameType == GAME_TYPE_COMMANDER || mParent->gameType == GAME_TYPE_CLASSIC || mParent->gameType == GAME_TYPE_DEMO) && mParent->players[1] == PLAYER_TYPE_CPU && (tournament->isTournament() || tournament->getGamesToPlay()>1 )) { setGamePhase(DUEL_STATE_SHOW_SCORE); /* Determine the winner of this game. This could be done more elegantly in credits.cpp (PSY) */ // (PSY!) check how the game handles draws, does it think it has a winner? if (!tournament->wasScoreDisplayed() || mParent->players[0]==PLAYER_TYPE_CPU) { tournament->gameFinished(game->didWin(game->players[0]),game->didWin(game->players[1])); tournament->updateScoreTable(game->players[0], game->players[1], mParent->gameType); if (tournament->isMatchFinished()) { // Hack for the competition: swap players back if swapped tournament->revertSwapPlayer(); //save match results in ai_test.csv only for ai vs ai games if (mParent->players[0]==PLAYER_TYPE_CPU) tournament->saveMatchResults(); if (tournament->isTournament()) { // We are in Tournament mode tournament->updateTournament(); // if first player is human then other results are random // It would be to boring for human player to watch all other ai decks to finish if (mParent->players[0]==PLAYER_TYPE_HUMAN) tournament->leaveOutAIvsAIMatches(); tournament->calculateRanking(); tournament->updateScoreforTournament(); if (tournament->isNextDeckFound()) // first player is either human or cpu mParent->players[0] = tournament->getDeckType(0); } } if (!tournament->isNextDeckFound() && tournament->isMatchFinished()) { //save tournament status tournament->save(mParent->players[0]==PLAYER_TYPE_CPU); if (mParent->players[0]==PLAYER_TYPE_HUMAN) { credits->computeTournament(game, mParent,tournament->isTournament(),!tournament->isTournament(),tournament->didHumanWin(),tournament->gamesWonbyHuman(),tournament->gamesPlayedbyHuman(),tournament->matchesWonbyHuman(),tournament->matchesPlayedbyHuman()); } } } if (tournament->wasScoreDisplayed() || mParent->players[0]==PLAYER_TYPE_CPU) { tournament->setScoreDisplayed(false); // load next deck if actual match is not finished or a next match is available if (tournament->isNextDeckFound() || !tournament->isMatchFinished()) { tournament->setOpLevel(OPLEVEL_NEXT_GAME); End(); Start(); tournament->setOpLevel(OPLEVEL_GAME_ACTIV); // Hack for the competition: swap players (human must be on deck[0]) tournament->swapPlayer(); for (int i = 0; i < NMB_PLAYERS; i++) { game->loadPlayer(i, tournament->getDeckType(i), tournament->getDeckNumber(i), premadeDeck); } //saves actual tournament state tournament->save(mParent->players[0]==PLAYER_TYPE_CPU); setAISpeed(); setGamePhase(DUEL_STATE_PLAY); } } } else { if (game->players[1]->playMode != Player::MODE_TEST_SUITE) credits->compute(game, mParent); setGamePhase(DUEL_STATE_END); } #ifdef TESTSUITE if (mParent->players[1] == PLAYER_TYPE_TESTSUITE) { if (testSuite->loadNext()) { loadTestSuitePlayers(); setGamePhase(DUEL_STATE_PLAY); testSuite->initGame(game); } else { setGamePhase(DUEL_STATE_END); } } else #endif #ifdef AI_CHANGE_TESTING { if (mParent->players[0] == PLAYER_TYPE_CPU_TEST && mParent->players[1] == PLAYER_TYPE_CPU_TEST) { handleResults(game); End(); Start(); if(mWorkerThread.empty()) { // "I don't like to wait" mode size_t thread_count = 1; startTime = JGEGetTime(); #ifdef QT_CONFIG thread_count = QThread::idealThreadCount(); #else thread_count = 4; #endif for(size_t i = 0; i < (thread_count); i++) mWorkerThread.push_back(boost::thread(ThreadProc, this)); } } } #endif if (mParent->players[0] == PLAYER_TYPE_CPU && mParent->players[1] == PLAYER_TYPE_CPU) { ///// Tournament Mod /////////// // End(); // Start(); ///// END Tournament Mod /////////// } // this is handled elsewhere. } if (mEngine->GetButtonClick(JGE_BTN_MENU)) { if (!menu) { menu = NEW SimpleMenu(JGE::GetInstance(), WResourceManager::Instance(), DUEL_MENU_GAME_MENU, this, Fonts::MENU_FONT, SCREEN_WIDTH / 2 - 100, 25); menu->Add(MENUITEM_CANCEL, "Cancel"); if(taskList->getState() != TaskList::TASKS_ACTIVE){ //almosthumane - mulligan if (((game->turn == 0 && game->getCurrentGamePhase() == MTG_PHASE_FIRSTMAIN) || (game->turn == 1 && game->getCurrentGamePhase() < MTG_PHASE_DRAW)) && game->currentPlayer->game->hand->nb_cards > 0 && game->currentPlayer->game->inPlay->nb_cards == 0 && game->currentPlayer->game->graveyard->nb_cards == 0 && game->currentPlayer->game->exile->nb_cards == 0 && game->currentlyActing() == (Player*)game->currentPlayer) //Now you can mulligan even if you didn't start as first. { menu->Add(MENUITEM_MULLIGAN, "Mulligan"); } //END almosthumane - mulligan if(game->getCurrentGamePhase() == MTG_PHASE_COMBATATTACKERS && game->currentlyActing() == (Player*)game->currentPlayer){ // During attack phase it shows a button to toggle all creatures to attack mode menu->Add(MENUITEM_TOGGLEATTACK_ALL_CREATURES, "Toggle Attack all Creatures"); } if(game->getCurrentTargetChooser() && game->getCurrentTargetChooser()->source->controller() == game->currentlyActing()){ if(game->getCurrentTargetChooser()->getNbTargets() < 1) menu->Add(MENUITEM_TOGGLE_SELECT_ALL, "Select all Targets"); else { menu->Add(MENUITEM_TOGGLE_SELECT_ALL, "Clear Selection"); menu->Add(MENUITEM_CONFIRM_SELECT_ALL, "Confirm Selection"); } } menu->Add(MENUITEM_MAIN_MENU, "Back to main menu"); #ifdef TESTSUITE menu->Add(MENUITEM_UNDO, "Undo"); menu->Add(MENUITEM_LOAD, "Load"); #endif if (mParent->players[1] == PLAYER_TYPE_CPU && (mParent->gameType == GAME_TYPE_COMMANDER || mParent->gameType == GAME_TYPE_CLASSIC || mParent->gameType == GAME_TYPE_DEMO)) { menu->Add(MENUITEM_SHOW_SCORE, "Show current score"); if (mParent->players[0] == PLAYER_TYPE_CPU) { if (tournament->getFastTimerMode()) menu->Add(MENUITEM_SPEED_NORMAL, "set Speed to NORMAL"); else menu->Add(MENUITEM_SPEED_FAST, "set Speed to FAST"); } } } } if(taskList->getState() != TaskList::TASKS_ACTIVE){ menu->Add(MENUITEM_TASKBOARD, "Open task board"); } else { menu->Add(MENUITEM_TASKBOARD, "Close task board"); } setGamePhase(DUEL_STATE_MENU); } break; #ifdef NETWORK_SUPPORT case DUEL_STATE_OPPONENT_WAIT: { if(game->players.size() > 1) { // Player loaded menu->Close(); SAFE_DELETE(menu); setGamePhase(DUEL_STATE_PLAY); } else if(menu == NULL) { menu = NEW SimpleMenu(JGE::GetInstance(), WResourceManager::Instance(), DUEL_STATE_OPPONENT_WAIT, this, Fonts::MENU_FONT, 150, 60); if (menu) { menu->Add(MENUITEM_MAIN_MENU, "Back to main menu"); } } else { menu->Update(dt); game->Update(dt); } } break; #endif //NETWORK_SUPPORT case DUEL_STATE_MENU: menu->Update(dt); break; case DUEL_STATE_MENU_TO_SCORE: menu->Update(dt); if (menu->isClosed()) { setGamePhase(DUEL_STATE_SHOW_SCORE); SAFE_DELETE(menu); } break; case DUEL_STATE_CANCEL: menu->Update(dt); if (menu->isClosed()) { setGamePhase(DUEL_STATE_PLAY); SAFE_DELETE(menu); } break; case DUEL_STATE_BACK_TO_MAIN_MENU: if (menu) { tournament->setOpLevel(OPLEVEL_NEW); tournament->End(); #ifdef AI_CHANGE_TESTING while(mWorkerThread.size()) { mWorkerThread.back().join(); mWorkerThread.pop_back(); } #endif //AI_CHANGE_TESTING menu->Update(dt); if (menu->isClosed()) { PlayerData * playerdata = NEW PlayerData(MTGCollection()); playerdata->taskList->passOneDay(); playerdata->taskList->save(); SAFE_DELETE(playerdata); SAFE_DELETE(menu); } } mParent->DoTransition(TRANSITION_FADE, GAME_STATE_MENU); break; default: if (JGE_BTN_OK == mEngine->ReadButton()) mParent->SetNextState(GAME_STATE_MENU); } if(taskList && taskList->getState() == TaskList::TASKS_IN) taskList->Update(dt); } void GameStateDuel::Render() { WFont * mFont = WResourceManager::Instance()->GetWFont(Fonts::MAIN_FONT); JRenderer * r = JRenderer::GetInstance(); r->ClearScreen(ARGB(0,0,0,0)); #if defined (PSP) JTexture * wpTex = WResourceManager::Instance()->RetrieveTexture("pspbgdeckeditor.jpg"); if (wpTex) { JQuadPtr wpQuad = WResourceManager::Instance()->RetrieveTempQuad("pspbgdeckeditor.jpg"); JRenderer::GetInstance()->RenderQuad(wpQuad.get(), 0, 0, 0, SCREEN_WIDTH_F / wpQuad->mWidth, SCREEN_HEIGHT_F / wpQuad->mHeight); } #else //Now it's possibile to randomly use up to 10 background images for deck selection (if random index is 0, it will be rendered the default "bgdeckeditor.jpg" image). JTexture * wpTex = NULL; if(kBgFile == ""){ char temp[4096]; sprintf(temp, "bgdeckeditor%i.jpg", std::rand() % 10); kBgFile.assign(temp); wpTex = WResourceManager::Instance()->RetrieveTexture(kBgFile); if (wpTex) { JQuadPtr wpQuad = WResourceManager::Instance()->RetrieveTempQuad(kBgFile); if (wpQuad.get()) JRenderer::GetInstance()->RenderQuad(wpQuad.get(), 0, 0, 0, SCREEN_WIDTH_F / wpQuad->mWidth, SCREEN_HEIGHT_F / wpQuad->mHeight); else { kBgFile = "bgdeckeditor.jpg"; //Fallback to default background image for deck selection. wpTex = NULL; } } else kBgFile = "bgdeckeditor.jpg"; //Fallback to default background image for deck selection. } if(!wpTex) wpTex = WResourceManager::Instance()->RetrieveTexture(kBgFile); if (wpTex) { JQuadPtr wpQuad = WResourceManager::Instance()->RetrieveTempQuad(kBgFile); JRenderer::GetInstance()->RenderQuad(wpQuad.get(), 0, 0, 0, SCREEN_WIDTH_F / wpQuad->mWidth, SCREEN_HEIGHT_F / wpQuad->mHeight); } #endif //render the game until someone did win the game (otherwise it crashes sometimes under linux) if (game && !game->didWin()) game->Render(); #ifdef AI_CHANGE_TESTING if (game && totalTestGames) { char buf[4096]; int currentTime = JGEGetTime(); if (totalTestGames < 2.5 * totalAIDecks) { mFont->SetColor(ARGB(255,255,255,0)); sprintf(buf, " Results are not significant, you should let at least %i more games run", (int)(totalAIDecks * 2.5) - totalTestGames); mFont->DrawString(buf,0,SCREEN_HEIGHT/2 - 20); } mFont->SetColor(ARGB(255,255,255,255)); float ratio = float(testPlayer2Victories) / float(totalTestGames); if (ratio < 0.48) mFont->SetColor(ARGB(255,255,0,0)); if (ratio > 0.52) mFont->SetColor(ARGB(255,0,255,0)); sprintf(buf, " Victories Player 2/total Games: %i/%i - Game Turn: %i", testPlayer2Victories, totalTestGames, /*(float)(1000*totalTestGames)/(currentTime - startTime)*/game->turn); mFont->DrawString(buf,0,SCREEN_HEIGHT/2); } #endif switch (mGamePhase) { case DUEL_STATE_START: break; case DUEL_STATE_SHOW_SCORE: { r->FillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, ARGB(200,0,0,0)); tournament->renderScoreTable(); break; } case DUEL_STATE_END_OF_GAME: break; case DUEL_STATE_END_OF_MATCH: break; case DUEL_STATE_END_OF_TOURNAMENT: break; case DUEL_STATE_END: { r->FillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, ARGB(200,0,0,0)); credits->Render(); #ifdef TESTSUITE if (mParent->players[1] == PLAYER_TYPE_TESTSUITE) { r->ClearScreen(ARGB(255,0,0,0)); char buf[4096]; mFont->SetColor(ARGB(255,255,255,255)); int elapsedTime = testSuite->getElapsedTime(); sprintf(buf, "Time to run the tests: %is", elapsedTime/1000); mFont->DrawString(buf,0,SCREEN_HEIGHT/2 - 20); int nbFailed = testSuite->nbFailed; int nbTests = testSuite->nbTests; if (!nbFailed) { sprintf(buf, "All %i tests successful!", nbTests); } else { sprintf(buf, "%i tests out of %i FAILED!", nbFailed, nbTests); } mFont->DrawString(buf,0,SCREEN_HEIGHT/2); nbFailed = testSuite->nbAIFailed; nbTests = testSuite->nbAITests; if (nbTests) { if (!nbFailed) { sprintf(buf, "AI Tests: All %i tests successful!", nbTests); } else { sprintf(buf, "AI Tests: %i tests out of %i FAILED!", nbFailed, nbTests); } mFont->DrawString(buf,0,SCREEN_HEIGHT/2+20); } } #endif break; } case DUEL_STATE_ERROR: { r->ClearScreen(ARGB(200,0,0,0)); mFont->DrawString(_("AN ERROR OCCURRED, CHECK FILE NAMES").c_str(), 0, SCREEN_HEIGHT / 2); break; } case DUEL_STATE_PREPARE_CNOGMENU: case DUEL_STATE_CHOOSE_NUMBER_OF_GAMES: case DUEL_STATE_CNOGMENU_IS_CLOSING: case DUEL_STATE_CANCEL_CNOGMENU: if (cnogmenu) cnogmenu->Render(); break; case DUEL_STATE_CHOOSE_DECK1: case DUEL_STATE_CHOOSE_DECK1_TO_2: case DUEL_STATE_CHOOSE_DECK1_TO_PLAY: case DUEL_STATE_CHOOSE_DECK2: case DUEL_STATE_CHOOSE_DECK2_TO_2: case DUEL_STATE_CHOOSE_DECK2_TO_PLAY: case DUEL_STATE_DECK1_DETAILED_INFO: case DUEL_STATE_DECK2_DETAILED_INFO: if (mParent->gameType != GAME_TYPE_CLASSIC #ifdef NETWORK_SUPPORT && mParent->gameType != GAME_TYPE_SLAVE #endif //NETWORK_SUPPORT && mParent->gameType != GAME_TYPE_STONEHEWER && mParent->gameType != GAME_TYPE_COMMANDER && mParent->gameType != GAME_TYPE_HERMIT) mFont->DrawString(_("LOADING DECKS").c_str(), 0, SCREEN_HEIGHT / 2); else { if (opponentMenu && !opponentMenu->isClosed()) { opponentMenu->Render(); // display the selected player deck name too string selectedPlayerDeckName = _("Player Deck: ").c_str() + game->players[0]->deckName; mFont->DrawString( selectedPlayerDeckName.c_str(), (SCREEN_WIDTH / 4) - (mFont->GetStringWidth(selectedPlayerDeckName.c_str())/2)-3, 32); } else if (deckmenu && !deckmenu->isClosed()) deckmenu->Render(); if (menu) menu->Render(); if (popupScreen && !popupScreen->isClosed()) popupScreen->Render(); } break; case DUEL_STATE_ERROR_NO_DECK: mFont->DrawString(_("NO DECK AVAILABLE,").c_str(), 0, SCREEN_HEIGHT / 2); mFont->DrawString(_("PRESS CIRCLE TO GO TO THE DECK EDITOR!").c_str(), 0, SCREEN_HEIGHT / 2 + 20); break; #ifdef NETWORK_SUPPORT case DUEL_STATE_OPPONENT_WAIT: if (menu) menu->Render(); break; #endif //NETWORK_SUPPORT case DUEL_STATE_MENU: case DUEL_STATE_CANCEL: case DUEL_STATE_MENU_TO_SCORE: case DUEL_STATE_BACK_TO_MAIN_MENU: if (game) { r->FillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, ARGB(100,0,0,0)); char buffer[4096]; sprintf(buffer, _("Turn:%i").c_str(), game->turn); mFont->SetColor(ARGB(255,255,255,255)); mFont->DrawString(buffer, SCREEN_WIDTH / 2, 0, JGETEXT_CENTER); } if (menu) { menu->Render(); // display the player deck names in their respective corners string playerDeckName = game->players[0]->deckName; float playerDeckNamePixelLength = mFont->GetStringWidth(playerDeckName.c_str()); mFont->DrawString( playerDeckName, SCREEN_WIDTH_F - playerDeckNamePixelLength, SCREEN_HEIGHT_F - 50); if(game->players.size()>1) { string opponentDeckName = game->players[1]->deckName; mFont->DrawString( opponentDeckName, 0, 50); } } } if(taskList && taskList->getState() == TaskList::TASKS_ACTIVE){ taskList->Render(); if(menu) menu->Render(); } } void GameStateDuel::ButtonPressed(int controllerId, int controlId) { int deckNumber = controlId; DeckManager * deckManager = DeckManager::GetInstance(); int aiDeckSize = deckManager->getAIDeckOrderList()->size(); switch (controllerId) { case DUEL_MENU_CHOOSE_NUMBER_OF_GAMES: // We're in the "Choose number of Games" menu { switch (controlId) { case CNOGMENU_ITEM_SINGLE_GAME: tournament->setMatchType(1,MATCHMODE_FIXED);break; case CNOGMENU_ITEM_CONTINUE_TOURNAMENT: if (cnogmenu) cnogmenu->Close(); if (!tournament->load(mParent->players[0] == PLAYER_TYPE_CPU,true)) { setGamePhase(DUEL_STATE_CANCEL_CNOGMENU); return; } tournament->calculateRanking(); tournament->updateScoreforTournament(); if (tournament->isNextDeckFound() || !tournament->isMatchFinished()) { tournament->setOpLevel(OPLEVEL_GAME_ACTIV); mParent->players[0] = tournament->getDeckType(0); mParent->players[1] = tournament->getDeckType(1); for (int i = 0; i < NMB_PLAYERS; i++) { game->loadPlayer(i, tournament->getDeckType(i),tournament->getDeckNumber(i) , premadeDeck); } setAISpeed(); setGamePhase(DUEL_STATE_CONTINUE_TOURNAMENT); return; } else { //end of match or end of tournament was already reached, the tournament cannot be continued setGamePhase(DUEL_STATE_CANCEL_CNOGMENU); return; } break; case CNOGMENU_ITEM_BESTOF3: tournament->setMatchType(3,MATCHMODE_BESTOF); break; case CNOGMENU_ITEM_BESTOF5: tournament->setMatchType(5,MATCHMODE_BESTOF); break; case CNOGMENU_ITEM_BESTOF7: tournament->setMatchType(7,MATCHMODE_BESTOF); break; case CNOGMENU_ITEM_BESTOF13: tournament->setMatchType(13,MATCHMODE_BESTOF); break; case CNOGMENU_ITEM_DELTA2: tournament->setMatchType(2,MATCHMODE_DELTA); break; case CNOGMENU_ITEM_DELTA3: tournament->setMatchType(3,MATCHMODE_DELTA); break; case CNOGMENU_ITEM_CONSECUTIVE2: tournament->setMatchType(2,MATCHMODE_CONSECUTIVE); break; case CNOGMENU_ITEM_CONSECUTIVE3: tournament->setMatchType(3,MATCHMODE_CONSECUTIVE); break; case CNOGMENU_ITEM_3GAMES: tournament->setMatchType(3,MATCHMODE_FIXED); break; case CNOGMENU_ITEM_5GAMES: tournament->setMatchType(5,MATCHMODE_FIXED); break; case CNOGMENU_ITEM_10GAMES: tournament->setMatchType(10,MATCHMODE_FIXED); break; case CNOGMENU_ITEM_25GAMES: tournament->setMatchType(25,MATCHMODE_FIXED); break; case CNOGMENU_ITEM_50GAMES: tournament->setMatchType(50,MATCHMODE_FIXED); break; case CNOGMENU_ITEM_100GAMES: tournament->setMatchType(100,MATCHMODE_FIXED); break; case CNOGMENU_ITEM_BESTOF7PLAYOFF: tournament->setMatchType(7,MATCHMODE_BESTOF,true); break; case CNOGMENU_ITEM_CANCEL: cnogmenu->Close(); setGamePhase(DUEL_STATE_CANCEL_CNOGMENU); return; } } cnogmenu->Close(); setGamePhase(DUEL_STATE_CNOGMENU_IS_CLOSING); break; case DUEL_MENU_DETAILED_DECK1_INFO: if ((popupScreen || deckmenu->showDetailsScreen())) { DeckMetaData* selectedDeck = deckmenu->getSelectedDeck(); if (!popupScreen->isClosed()) { popupScreen->Close(); setGamePhase(DUEL_STATE_CHOOSE_DECK1); SAFE_DELETE( popupScreen ); } else { popupScreen->Update(selectedDeck); popupScreen->Render(); } } break; case DUEL_MENU_DETAILED_DECK2_INFO: if ((popupScreen || opponentMenu->showDetailsScreen())) { DeckMetaData* selectedDeck = opponentMenu->getSelectedDeck(); if (!popupScreen->isClosed()) { popupScreen->Close(); setGamePhase(DUEL_STATE_CHOOSE_DECK2_TO_PLAY); SAFE_DELETE( popupScreen ); } else { popupScreen->Update(selectedDeck); popupScreen->Render(); } } break; case DUEL_MENU_CHOOSE_OPPONENT: switch (controlId) { case MENUITEM_RANDOM_AI: { int deck = tournament->getRandomDeck(false, mParent->gameType); if (deck>0) { game->loadPlayer(1, mParent->players[1], deck); tournament->addDeck(1,game->players.at(1)->deckId,mParent->players[1]); } } setAISpeed(); if (opponentMenu) opponentMenu->Close(); if (tournamentSelection) setGamePhase(DUEL_STATE_CHOOSE_DECK2_TO_2); else setGamePhase(DUEL_STATE_CHOOSE_DECK2_TO_PLAY); break; case MENUITEM_RANDOM_AI_HARD: { int deck = tournament->getRandomDeck(true, mParent->gameType); if (deck>0) { game->loadPlayer(1, mParent->players[1], deck, premadeDeck); tournament->addDeck(1,game->players.at(1)->deckId,mParent->players[1]); } } setAISpeed(); if (opponentMenu) opponentMenu->Close(); if (tournamentSelection) setGamePhase(DUEL_STATE_CHOOSE_DECK2_TO_2); else setGamePhase(DUEL_STATE_CHOOSE_DECK2_TO_PLAY); break; case MENUITEM_FILL_NEXT_STAGE: case MENUITEM_FILL_NEXT_STAGE_HARD: { int deck=0; do { deck = tournament->getRandomDeck(controlId==MENUITEM_FILL_NEXT_STAGE_HARD, mParent->gameType); if (deck>0) { game->loadPlayer(1, mParent->players[1], deck, premadeDeck); tournament->addDeck(1,game->players.at(1)->deckId,mParent->players[1]); } } while(tournament->remainingDecksToNextStage()>0 && deck>0); } setAISpeed(); if (opponentMenu) opponentMenu->Close(); if (tournamentSelection) setGamePhase(DUEL_STATE_CHOOSE_DECK2_TO_2); else setGamePhase(DUEL_STATE_CHOOSE_DECK2_TO_PLAY); break; default: // cancel option. return to player deck selection if (controlId == MENUITEM_CANCEL) { if (opponentMenu) opponentMenu->Close(); if (deckmenu) deckmenu->Close(); //reset tournament tournamentSelection=false; tournament->resetTournamentSelection(); setGamePhase(DUEL_STATE_CHOOSE_DECK2_TO_1); break; } else if (controlId == MENUITEM_MORE_INFO && opponentMenu->showDetailsScreen()) { DeckMetaData* selectedDeck = opponentMenu->getSelectedDeck(); if (!popupScreen) { popupScreen = NEW SimplePopup(DUEL_MENU_DETAILED_DECK2_INFO, this, Fonts::MAIN_FONT, "Detailed Information", selectedDeck, MTGCollection()); popupScreen->Render(); selectedAIDeckId = selectedDeck->getDeckId(); } else { popupScreen->Update(selectedDeck); } setGamePhase(DUEL_STATE_DECK2_DETAILED_INFO); break; } else if (controlId == MENUITEM_MORE_INFO && !opponentMenu->showDetailsScreen()) { // do nothing, ignore all key requests until popup is dismissed. break; } else if (controlId == MENUITEM_GAUNTLET) { tournament->enableTournamantMode(TOURNAMENTMODES_GAUNTLET,1); deckNumber = 1;// start Gauntlet with first deck } else if (controlId == MENUITEM_KO_TOURNAMENT) { tournamentSelection=true; tournament->enableTournamantMode(TOURNAMENTMODES_KO,1); if (opponentMenu) opponentMenu->Close(); setGamePhase(DUEL_STATE_CHOOSE_DECK2_TO_2); break; } else if (controlId == MENUITEM_DOUBLEKO_TOURNAMENT) { tournamentSelection=true; tournament->enableTournamantMode(TOURNAMENTMODES_DOUBLEKO,1); if (opponentMenu) opponentMenu->Close(); setGamePhase(DUEL_STATE_CHOOSE_DECK2_TO_2); break; } else if (controlId == MENUITEM_RR_TOURNAMENT) { tournamentSelection=true; tournament->enableTournamantMode(TOURNAMENTMODES_ROUNDROBIN); if (opponentMenu) opponentMenu->Close(); setGamePhase(DUEL_STATE_CHOOSE_DECK2_TO_2); break; } else if (controlId == MENUITEM_START_TOURNAMENT) { if (tournament->getNumberofTournamentDecks()>2) { tournamentSelection=false; tournament->initTournament(); game->loadPlayer(1, mParent->players[1], tournament->getDeckNumber(1), premadeDeck); setAISpeed(); if (opponentMenu) opponentMenu->Close(); setGamePhase(DUEL_STATE_CHOOSE_DECK2_TO_PLAY); } else { if (opponentMenu) opponentMenu->Close(); setGamePhase(DUEL_STATE_CHOOSE_DECK2_TO_2); } break; } else if (tournamentSelection) { deckNumber = deckManager->getAIDeckOrderList()->at(controlId - 1)->getDeckId(); OpponentsDeckid = deckNumber; tournament->addDeck(1,deckNumber,mParent->players[1]); if (opponentMenu) opponentMenu->Close(); setGamePhase(DUEL_STATE_CHOOSE_DECK2_TO_2); break; } else if (controlId != MENUITEM_EVIL_TWIN && aiDeckSize > 0) // evil twin deckNumber = deckManager->getAIDeckOrderList()->at(controlId - 1)->getDeckId(); game->loadPlayer(1, mParent->players[1], deckNumber, premadeDeck); tournament->addDeck(1,deckNumber,mParent->players[1]); setAISpeed(); OpponentsDeckid = deckNumber; if (opponentMenu) opponentMenu->Close(); setGamePhase(DUEL_STATE_CHOOSE_DECK2_TO_PLAY); break; } break; case DUEL_MENU_CHOOSE_DECK: if (controlId == MENUITEM_RANDOM_PLAYER) // Random Player Deck Selection { if (mParent->players[0] == PLAYER_TYPE_HUMAN) deckmenu->selectRandomDeck(false); else deckmenu->selectRandomDeck(true); tournament->addDeck(0,deckmenu->getSelectedDeckId(),mParent->players[0]); game->loadPlayer(0, mParent->players[0], deckmenu->getSelectedDeckId(), premadeDeck); if (deckmenu) deckmenu->Close(); ConstructOpponentMenu(); setGamePhase(DUEL_STATE_CHOOSE_DECK2_TO_PLAY); break; } else if (controlId == MENUITEM_MAIN_MENU || controlId == MENUITEM_CANCEL) // user clicked on "Cancel" { if (deckmenu) deckmenu->Close(); setGamePhase(DUEL_STATE_BACK_TO_MAIN_MENU); break; } else if (controlId == MENUITEM_MORE_INFO && deckmenu->showDetailsScreen()) { DeckMetaData* selectedDeck = deckmenu->getSelectedDeck(); if (!popupScreen) { popupScreen = NEW SimplePopup(DUEL_MENU_DETAILED_DECK1_INFO, this, Fonts::MAIN_FONT, "Detailed Information", selectedDeck, MTGCollection()); popupScreen->Render(); selectedPlayerDeckId = deckmenu->getSelectedDeckId(); } else { popupScreen->Update(selectedDeck); } setGamePhase(DUEL_STATE_DECK1_DETAILED_INFO); break; } else if (controlId == MENUITEM_MORE_INFO) { // do nothing break; } else if (controlId == MENUITEM_GAUNTLET) { tournament->enableTournamantMode(TOURNAMENTMODES_GAUNTLET,0); controlId = 1; } else if (controlId == MENUITEM_ENDLESSDEMO) { tournament->enableTournamantMode(TOURNAMENTMODES_ENDLESS); game->loadPlayer(0, mParent->players[0], tournament->getDeckNumber(0), premadeDeck); setAISpeed(); setGamePhase(DUEL_STATE_CHOOSE_DECK1_TO_PLAY); controlId = tournament->getDeckNumber(1); } else if (controlId == MENUITEM_KO_TOURNAMENT) { tournament->enableTournamantMode(TOURNAMENTMODES_KO); game->loadPlayer(0, mParent->players[0], tournament->getDeckNumber(0), premadeDeck); setAISpeed(); setGamePhase(DUEL_STATE_CHOOSE_DECK1_TO_PLAY); controlId = tournament->getDeckNumber(1); } else if (controlId == MENUITEM_DOUBLEKO_TOURNAMENT) { tournament->enableTournamantMode(TOURNAMENTMODES_DOUBLEKO); game->loadPlayer(0, mParent->players[0], tournament->getDeckNumber(0), premadeDeck); setAISpeed(); setGamePhase(DUEL_STATE_CHOOSE_DECK1_TO_PLAY); controlId = tournament->getDeckNumber(1); } if (controlId < 0) { mParent->SetNextState(GAME_STATE_DECK_VIEWER); return; } if (mGamePhase == DUEL_STATE_CHOOSE_DECK1) { if (mParent->players[0] == PLAYER_TYPE_HUMAN) { vector * playerDeck = deckManager->getPlayerDeckOrderList(); if (!premadeDeck && controlId > 0) deckNumber = playerDeck->at(controlId - 1)->getDeckId(); game->loadPlayer(0, mParent->players[0], deckNumber, premadeDeck); tournament->addDeck(0,deckNumber,mParent->players[0]); playerDeck = NULL; } else { //demo first player is CPU if (tournament->isGauntlet() || tournament->getTournamentMode() == TOURNAMENTMODES_KO || tournament->getTournamentMode() == TOURNAMENTMODES_DOUBLEKO) // start Gauntlet with first deck deckNumber = tournament->getDeckNumber(0); else { deckNumber = deckManager->getAIDeckOrderList()->at(controlId - 1)->getDeckId(); tournament->addDeck(0,deckNumber,mParent->players[0]); } game->loadPlayer(0, mParent->players[0], deckNumber, premadeDeck); } if (deckmenu) deckmenu->Close(); #ifdef NETWORK_SUPPORT if(mParent->mpNetwork) { // no need to choose an opponent deck in network mode setGamePhase(DUEL_STATE_OPPONENT_WAIT); } else #endif //NETWORK_SUPPORT { setGamePhase(DUEL_STATE_CHOOSE_DECK1_TO_2); } } else { game->loadPlayer(1, mParent->players[1], controlId, premadeDeck); if (deckmenu) deckmenu->Close(); if (!tournament->isEndlessDemo() && tournament->getTournamentMode()!=TOURNAMENTMODES_KO && tournament->getTournamentMode()!=TOURNAMENTMODES_DOUBLEKO) // no oppenent has to be selected for these modes setGamePhase(DUEL_STATE_CHOOSE_DECK2_TO_PLAY); } break; default: switch (controlId) { // case GAMEMENU_ITEM_CONCEDE_MATCH: // // This is a hack for 1-Player mode, it won't work in 2-player mode: // if (mParent->players[0] == PLAYER_TYPE_HUMAN) { // mVictories[0] = 0; // mVictories[1] = mNbGames; // mGamesPlayed = mNbGames; // } // // falling through // case GAMEMENU_ITEM_CONCEDE_GAME: // // This is a hack for 1-Player mode, it won't work in 2-player mode: // if (mParent->players[0] == PLAYER_TYPE_HUMAN) { // game->players[0]->life = -99; // } // // falling through // case GAMEMENU_ITEM_CONTINUE: // menu->Close(); // mGamePhase = DUEL_STATE_CONTINUE; // break; case MENUITEM_TASKBOARD: if(taskList->getState() != TaskList::TASKS_ACTIVE){ taskList->Start(); } else { taskList->End(); } menu->Close(); setGamePhase(DUEL_STATE_CANCEL); break; case MENUITEM_TOGGLEATTACK_ALL_CREATURES: for(unsigned int i = 0; i < game->players[0]->inPlay()->cards.size(); i++){ if(game->players[0]->inPlay()->cards[i]->canAttack()){ game->players[0]->inPlay()->cards[i]->toggleAttacker(); } } menu->Close(); setGamePhase(DUEL_STATE_CANCEL); break; case MENUITEM_TOGGLE_SELECT_ALL: if(game->getCurrentTargetChooser() && game->getCurrentTargetChooser()->getNbTargets() < 1){ for (int j = 0; j < 2; ++j){ if(game->getCurrentTargetChooser()->canTarget(game->players[j]) && game->getCurrentTargetChooser()->getNbTargets() < (unsigned int) game->getCurrentTargetChooser()->maxtargets) game->getCurrentTargetChooser()->addTarget(game->players[j]); MTGGameZone * zones[] = { game->players[j]->game->inPlay, game->players[j]->game->graveyard, game->players[j]->game->hand, game->players[j]->game->library, game->players[j]->game->exile, game->players[j]->game->stack, game->players[j]->game->commandzone, game->players[j]->game->sideboard, game->players[j]->game->reveal }; for (int k = 0; k < 9; k++){ for(unsigned int i = 0; i < zones[k]->cards.size(); i++){ if(game->getCurrentTargetChooser()->canTarget(zones[k]->cards[i]) && game->getCurrentTargetChooser()->getNbTargets() < (unsigned int) game->getCurrentTargetChooser()->maxtargets) game->getCurrentTargetChooser()->addTarget(zones[k]->cards[i]); } } } if(game->getCurrentTargetChooser()){ game->getCurrentTargetChooser()->done = false; game->getCurrentTargetChooser()->autoChoice = true; } } else if(game->getCurrentTargetChooser()){ game->getCurrentTargetChooser()->initTargets(); game->getCurrentTargetChooser()->done = false; game->getCurrentTargetChooser()->autoChoice = false; } menu->Close(); setGamePhase(DUEL_STATE_CANCEL); break; case MENUITEM_CONFIRM_SELECT_ALL: if(game->getCurrentTargetChooser()){ game->getCurrentTargetChooser()->done = true; game->getCurrentTargetChooser()->autoChoice = false; if(game->getCurrentTargetChooser()->source) game->cardClick(game->getCurrentTargetChooser()->source, game->getCurrentTargetChooser()->source); } menu->Close(); setGamePhase(DUEL_STATE_CANCEL); break; case MENUITEM_SPEED_FAST: tournament->setFastTimerMode(true); setAISpeed(); menu->Close(); setGamePhase(DUEL_STATE_CANCEL); break; case MENUITEM_SPEED_NORMAL: tournament->setFastTimerMode(false); setAISpeed(); menu->Close(); setGamePhase(DUEL_STATE_CANCEL); break; case MENUITEM_SHOW_SCORE: menu->Close(); //delete menu and display score setGamePhase(DUEL_STATE_MENU_TO_SCORE); break; case MENUITEM_MAIN_MENU: menu->Close(); setGamePhase(DUEL_STATE_BACK_TO_MAIN_MENU); break; case MENUITEM_CANCEL: menu->Close(); setGamePhase(DUEL_STATE_CANCEL); break; case MENUITEM_MULLIGAN: //almosthumane - mulligan game->Mulligan(); menu->Close(); setGamePhase(DUEL_STATE_CANCEL); break; case MENUITEM_UNDO: { game->undo(); menu->Close(); 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 } mEngine->ReleaseKey( JGE_BTN_MENU ); } } void GameStateDuel::OnScroll(int inXVelocity, int inYVelocity) { // ignore magnitude for now, since no action requires scrolling if (abs(inYVelocity) > 300) { /*bool flickUpwards = (inYVelocity < 0);*/ mEngine->HoldKey_NoRepeat(/*flickUpwards ? JGE_BTN_PREV : */JGE_BTN_SEC); //removing the activation of "left trigger" or "advance phase" because on high end tablets this gesture //is picked up by simply looking at the cards in your hand if the resolution of tablet exceed 1800 X ANY. } if (abs(inXVelocity) > 300) { bool flickLeft = (inYVelocity > 0); if(flickLeft && OptionClosedHand::INVISIBLE == options[Options::CLOSEDHAND].number) { JButton trigger = (options[Options::REVERSETRIGGERS].number ? JGE_BTN_PREV : JGE_BTN_NEXT); mEngine->HoldKey_NoRepeat(trigger); } else if(flickLeft && OptionClosedHand::VISIBLE == options[Options::CLOSEDHAND].number) { #if defined (ANDROID) //JButton trigger = (options[Options::REVERSETRIGGERS].number ? JGE_BTN_UP : JGE_BTN_DOWN); mEngine->HoldKey_NoRepeat(JGE_BTN_DOWN); #endif } } } void GameStateDuel::setAISpeed() { if(game) { for (unsigned int i = 0; i < game->players.size() - 1; i ++) { if (mParent->players[i] == PLAYER_TYPE_CPU) { if(dynamic_cast(game->players[i])) ((AIPlayer *)game->players[i])->setFastTimerMode(tournament->getFastTimerMode()); } } } } TDeck::TDeck(int deck,PlayerType deckType, int victories, int lastWin, int wonMatches, int playedMatches,int wonGames,int playedGames) :mDeckNumber(deck),mDeckType(deckType),mVictories(victories),mLastWin(lastWin),mWonMatches(wonMatches),mMatchesPlayed(playedMatches),mWonGames(wonGames),mGamesPlayed(playedGames) { mRanking=-1; mDifficulty=0; } TDeck::TDeck() { reset(); } void TDeck::reset() { mDeckNumber=0; mDeckType=PLAYER_TYPE_CPU; mVictories=0; mLastWin=0; mWonMatches=0; mGamesPlayed=0; mMatchesPlayed=0; mRanking=-1; mWonGames=0; mDifficulty=0; } TDeck::~TDeck() { } void TDeck::increaseDeckNumber() { mDeckNumber++; } std::string TDeck::getDeckName() { DeckManager * deckManager = DeckManager::GetInstance(); return deckManager->getDeckMetaDataById(getDeckNumber(), isAI())->getName(); } Tournament::Tournament() { for (int i = 0; i *deckList = deckManager->getAIDeckOrderList(); int deckNumber; unsigned int random=0; int k=0; bool isDouble=true; vector decks; for (unsigned int i=0;isize();i++){ if(type == GAME_TYPE_COMMANDER && deckList->at(i)->isCommanderDeck()){ if (noEasyDecks && (deckList->at(i)->getDifficulty()==HARD || deckList->at(i)->getDifficulty()==NORMAL)){ decks.push_back(i); } else { decks.push_back(i); } } else if(type != GAME_TYPE_COMMANDER){ if (noEasyDecks && (deckList->at(i)->getDifficulty()==HARD || deckList->at(i)->getDifficulty()==NORMAL)){ decks.push_back(i); } else { decks.push_back(i); } } } while(isDouble && decks.size()>0) { isDouble=false; k = rand() % (int)decks.size(); random = decks.at(k); deckNumber = deckList->at(random)->getDeckId(); if ( mTournamentMode==TOURNAMENTMODES_ROUNDROBIN || mTournamentMode==TOURNAMENTMODES_KO||mTournamentMode==TOURNAMENTMODES_DOUBLEKO) for (unsigned int i=0;i= mNbGames) endOfMatch = true; break; case MATCHMODE_BESTOF: if ((Deck[0].getVictories() > mNbGames/2 || Deck[1].getVictories() > mNbGames/2) && (!mCompetition || abs(Deck[0].getVictories() - Deck[1].getVictories()) >1)) endOfMatch = true; break; case MATCHMODE_DELTA: if ((Deck[0].getVictories() - Deck[1].getVictories() >= mNbGames) || (Deck[1].getVictories() - Deck[0].getVictories() >= mNbGames)) endOfMatch = true; break; case MATCHMODE_CONSECUTIVE: if (Deck[0].getLastWin() >= mNbGames || Deck[1].getLastWin() >= mNbGames) endOfMatch = true; break; default: endOfMatch = true; } return endOfMatch; } void Tournament::saveMatchResults() { std::ofstream file; if (JFileSystem::GetInstance()->openForWrite(file,AI_RESULTS_FILE,ios_base::app)) { time_t rawtime; struct tm * timeinfo; char timestamp [80]; time ( &rawtime ); timeinfo = localtime ( &rawtime ); strftime (timestamp,20,"%m/%d/%y, %H:%M:%S", timeinfo); int deck0 = 0; if (Deck[0].isAI()) deck0 = Deck[0].getDeckNumber(); else deck0 = -Deck[0].getDeckNumber(); int deck1 = 0; if (Deck[1].isAI()) deck1 = Deck[1].getDeckNumber(); else deck1 = -Deck[1].getDeckNumber(); int temp = 0; if (mCompetition) temp = 1; char buf[256]; sprintf(buf, "%s,% 6i,% 6i,% 5i,% 5i,% 5i,% 1i,% 5i,% 1i\n", timestamp, deck0, deck1, Deck[0].getVictories(), Deck[1].getVictories(), mGamesPlayed, mMatchMode, mNbGames, temp); file << buf; file.close(); } } void Tournament::resetTournamentSelection() { mTournamentMode=0; TournamentsDecks.clear(); TournamentsDecks.push_back(Deck[0]); TournamentsDecksID[0]=0; TournamentsDecksID[1]=1; } std::string Tournament::exportTournamentDescription() { std::string describtion; char buf[1024]; switch(mTournamentMode) { case TOURNAMENTMODES_KO: sprintf(buf, "knockout tournament!:\n"); describtion.append(buf); break; case TOURNAMENTMODES_DOUBLEKO: sprintf(buf, "double knockout tournament!:\n"); describtion.append(buf); break; case TOURNAMENTMODES_ROUNDROBIN: sprintf(buf, "round robin tournament!:\n"); describtion.append(buf); break; } sprintf(buf, "%i Decks selected:\n",(int)TournamentsDecks.size()-1); describtion.append(buf); for (unsigned int i=1;i0) { mTournamentMode=tournamentMode; // the first two decks are the first playing decks TournamentsDecksID[0]=0; TournamentsDecksID[1]=1; switch(mTournamentMode) { case TOURNAMENTMODES_ENDLESS: if (nmbDecks>1) { Deck[0].setDeckNumber((rand() % nmbDecks) + 1); Deck[1].setDeckNumber((rand() % nmbDecks) + 1); } else { Deck[0].setDeckNumber(1); Deck[1].setDeckNumber(1); } Deck[0].setDeckType(PLAYER_TYPE_CPU); Deck[1].setDeckType(PLAYER_TYPE_CPU); nextDeckFound = true; scoreMatchesPlayed=0; break; case TOURNAMENTMODES_GAUNTLET: Deck[player].setDeckNumber(1); Deck[player].setDeckType(PLAYER_TYPE_CPU); gauntletLastDeckNumber[player]=nmbDecks; break; case TOURNAMENTMODES_KO: TournamentsDecks.clear(); if (player>0) { TournamentsDecks.push_back(Deck[0]); } else { for (unsigned int i=0;i0) std::shuffle ( TournamentsDecks.begin()+1, TournamentsDecks.end(), g ); else std::shuffle ( TournamentsDecks.begin(), TournamentsDecks.end(), g ); Deck[0]=TournamentsDecks[0]; Deck[1]=TournamentsDecks[1]; } break; case TOURNAMENTMODES_DOUBLEKO: looserDecks=false; TournamentsDecks.clear(); if (player>0) { TournamentsDecks.push_back(Deck[0]); } else { //only AI-vs-AI for (unsigned int i=0;ireadIntoString(options.profileFile(PLAYER_TOURNAMENT), contents); else readTournament = JFileSystem::GetInstance()->readIntoString(AI_TOURNAMENT, contents); if (readTournament) { TournamentsDecks.clear(); std::stringstream stream(contents); std::string s; endOfMatch=false; nextDeckFound=false; TDeck newDeck; while (std::getline(stream, s)) { if (!s.size()) continue; if (s[s.size() - 1] == '\r') s.erase(s.size() - 1); //Handle DOS files if (s.size() && s[0] == '#') continue; size_t i = s.find_first_of("="); if (i == string::npos) continue; //printf("string %s\n",s.c_str()); string key = s.substr(0, i); string value = s.substr(i + 1); //printf("key %s, value %s\n",key.c_str(),value.c_str()); if (key.find("TournamentMode")!=string::npos) mTournamentMode=atoi(value.c_str()); if (key.find("endOfMatch")!=string::npos) endOfMatch=atoi(value.c_str())>0; if (key.find("nextDeckFound")!=string::npos) nextDeckFound=atoi(value.c_str())>0; if (loadComplete){ if (key.find("Competition")!=string::npos) mCompetition=atoi(value.c_str())>0; if (key.find("PlayerSwaped")!=string::npos) mPlayerSwaped=atoi(value.c_str())>0; if (key.find("NbGames")!=string::npos) mNbGames=atoi(value.c_str()); if (key.find("MatchMode")!=string::npos) mMatchMode=atoi(value.c_str()); if (key.find("GamesPlayed")!=string::npos) mGamesPlayed=atoi(value.c_str()); if (key.find("nmbDecks")!=string::npos) nmbDecks=atoi(value.c_str()); if (key.find("FastTimerMode")!=string::npos) mFastTimerMode=atoi(value.c_str())>0; if (key.find("looserDecks")!=string::npos) looserDecks=atoi(value.c_str())>0; if (s.find_first_of("[") != string::npos) { size_t p1 = s.find_first_of("["); key = s.substr(0, p1); string player = s.substr(p1 + 1,1); // printf("player %i\n",atoi(player.c_str())); if (key.find("PlayDeck")!=string::npos) { size_t t1 = value.find_first_of(","); Deck[atoi(player.c_str())].setDeckNumber(atoi(value.substr(0,t1).c_str())); size_t t2 = value.find(",",t1+1); Deck[atoi(player.c_str())].setDeckType((PlayerType)atoi(value.substr(t1+1,t2).c_str())); size_t t3 = value.find(",",t2+1); Deck[atoi(player.c_str())].setVictories(atoi(value.substr(t2+1,t3).c_str())); size_t t4 = value.find(",",t3+1); Deck[atoi(player.c_str())].setLastWin(atoi(value.substr(t3+1,t4).c_str())); size_t t5 = value.find(",",t4+1); gauntletLastDeckNumber[atoi(player.c_str())]=atoi(value.substr(t4+1,t5).c_str()); TournamentsDecksID[atoi(player.c_str())]=atoi(value.substr(t5+1).c_str()); } if (key.find("TDeck")!=string::npos) { newDeck.reset(); size_t t1 = value.find_first_of(","); newDeck.setDeckNumber(atoi(value.substr(0,t1).c_str())); size_t t2 = value.find(",",t1+1); newDeck.setDeckType((PlayerType)atoi(value.substr(t1+1,t2).c_str())); size_t t3 = value.find(",",t2+1); newDeck.setMatchesWon(atoi(value.substr(t2+1,t3).c_str())); size_t t4 = value.find(",",t3+1); newDeck.setMatchesPlayed(atoi(value.substr(t3+1,t4).c_str())); size_t t5 = value.find(",",t4+1); newDeck.setGamesWon(atoi(value.substr(t4+1,t5).c_str())); newDeck.setGamesPlayed(atoi(value.substr(t5+1).c_str())); addDeck(0,newDeck); } } } } // copy played games and matches back to Deck (only for tournaments) if (TournamentsDecks.size()>1) { if (TournamentsDecksID[0]openForWrite(Tfile,options.profileFile(PLAYER_TOURNAMENT),ios_base::out); else saveTournament = JFileSystem::GetInstance()->openForWrite(Tfile,AI_TOURNAMENT,ios_base::out); if (saveTournament) { char buf[256]; sprintf(buf, "TournamentMode=%i\n",mTournamentMode); Tfile << buf; sprintf(buf, "Competition=%i\n",mCompetition); Tfile << buf; sprintf(buf, "PlayerSwaped=%i\n",mPlayerSwaped); Tfile << buf; sprintf(buf, "NbGames=%i\n",mNbGames); Tfile << buf; sprintf(buf, "MatchMode=%i\n",mMatchMode); Tfile << buf; sprintf(buf, "GamesPlayed=%i\n",mGamesPlayed); Tfile << buf; sprintf(buf, "nmbDecks=%i\n",nmbDecks); Tfile << buf; sprintf(buf, "FastTimerMode=%i\n",mFastTimerMode); Tfile << buf; sprintf(buf, "endOfMatch=%i\n",endOfMatch); Tfile << buf; sprintf(buf, "nextDeckFound=%i\n",nextDeckFound); Tfile << buf; if (mTournamentMode==TOURNAMENTMODES_DOUBLEKO) { sprintf(buf, "looserDecks=%i\n",looserDecks); Tfile << buf; } sprintf(buf, "#PlayDeck[number]=decknumber,deckType,victories,lastWin,LastDeckNumber,TournamentsID\n"); Tfile << buf; for (int i = 0; i < NMB_PLAYERS; i++) { sprintf(buf, "PlayDeck[%i]=%i,%i,%i,%i,%i,%i\n",i,Deck[i].getDeckNumber(),Deck[i].getDeckType(),Deck[i].getVictories(),Deck[i].getLastWin(),gauntletLastDeckNumber[i],TournamentsDecksID[i]); Tfile << buf; } if (mTournamentMode>2) { sprintf(buf, "#TournamentDeck[number]=decknumber,deckType,matchWins,playedMatches,gameWins,playedGames\n"); Tfile << buf; for (unsigned int i = 0; i < TournamentsDecks.size(); i++) { sprintf(buf, "TDeck[%i]=%i,%i,%i,%i,%i,%i\n",i,TournamentsDecks.at(i).getDeckNumber(),TournamentsDecks.at(i).getDeckType(),TournamentsDecks.at(i).getMatchesWon(),TournamentsDecks.at(i).getMatchesPlayed(),TournamentsDecks.at(i).getGamesWon(),TournamentsDecks.at(i).getGamesPlayed()); Tfile << buf; } } Tfile.close(); } } void Tournament::swapPlayer() { if ((mCompetition && Deck[0].isAI()) || !Deck[1].isAI()) { TDeck tmpDeck; tmpDeck = Deck[0]; Deck[0] = Deck[1]; Deck[1] = tmpDeck; mPlayerSwaped = !mPlayerSwaped; } } void Tournament::revertSwapPlayer() { if (mPlayerSwaped) { TDeck tmpDeck; tmpDeck = Deck[0]; Deck[0] = Deck[1]; Deck[1] = tmpDeck; mPlayerSwaped = !mPlayerSwaped; } } void Tournament::updateScoreTable(Player * _p0, Player * _p1, int gt, bool gameEnd) { if (_p0) p0Quad = _p0->getIcon(); if (_p1) p1Quad = _p1->getIcon(); mgameType = gt; mVictories0=Deck[0].getVictories(); mVictories1=Deck[1].getVictories(); p0IsAI=Deck[0].isAI(); p1IsAI=Deck[1].isAI(); scoreFinal=isMatchFinished() || gameEnd; tournamentFinal=!isNextDeckFound() && isMatchFinished() && mTournamentMode>0; } void Tournament::updateScoreforTournament() { tournamentFinal=!isNextDeckFound() && isMatchFinished() && mTournamentMode>0; scoreMatchesPlayed++; switch(mTournamentMode) { case 0: //no tournament scoreMatchesPlayed=0; case TOURNAMENTMODES_GAUNTLET: if ((gauntletLastDeckNumber[0])*(gauntletLastDeckNumber[1])>0) scoreMatchesToPlay=(gauntletLastDeckNumber[0]*gauntletLastDeckNumber[1])-(Deck[0].getDeckNumber()-1)*gauntletLastDeckNumber[0]-Deck[1].getDeckNumber()-1; else if ((gauntletLastDeckNumber[0])>0) scoreMatchesToPlay=(gauntletLastDeckNumber[0])-Deck[0].getDeckNumber(); else scoreMatchesToPlay=(gauntletLastDeckNumber[1])-Deck[1].getDeckNumber(); break; case TOURNAMENTMODES_KO: scoreMatchesToPlay=TournamentsDecks.size()-1; break; case TOURNAMENTMODES_DOUBLEKO: scoreMatchesToPlay=(TournamentsDecks.size()); break; case TOURNAMENTMODES_ROUNDROBIN: //player 0 is always the player (RR is only available for human) scoreMatchesToPlay=(TournamentsDecks.size()-1)-TournamentsDecks.at(0).getMatchesPlayed(); break; } } void Tournament::renderScoreTable() { JRenderer * r = JRenderer::GetInstance(); WFont * f2 = WResourceManager::Instance()->GetWFont(Fonts::MENU_FONT); char buffer[256]; f2->SetColor(ARGB(255,255,255,255)); float y = 25; float x_score = 150; f2->SetScale(2); if (tournamentFinal && mTournamentMode>0) { f2->SetScale(1); switch(mTournamentMode) { case TOURNAMENTMODES_ENDLESS: break; case TOURNAMENTMODES_GAUNTLET: //f2->DrawString(_("Gauntletmode").c_str() ,380, y2); break; case TOURNAMENTMODES_KO: f2->DrawString(_("KO Tournament is over. Results:").c_str() ,80, y); f2->SetScale(1); break; case TOURNAMENTMODES_DOUBLEKO: f2->DrawString(_("Double KO Tournament is over. Results:").c_str() ,80, y); f2->SetScale(1); break; case TOURNAMENTMODES_ROUNDROBIN: f2->DrawString(_("Round robin Tournament is over. Results:").c_str() ,80, y); f2->SetScale(0.8f); break; } y+=30; f2->SetScale(0.8f); f2->DrawString(_("Deck").c_str() ,80, y); f2->DrawString(_("Matches").c_str() ,300, y); f2->DrawString(_("Games").c_str() ,400, y); y+=30; for (unsigned int i=0;i<10;i++ ) { if (sortedTournamentDecks[i].getDeckNumber()>0 && i<10) { if (sortedTournamentDecks[i].getDeckType()==PLAYER_TYPE_CPU) sprintf(buffer, _("%i.: %s").c_str(),sortedTournamentDecks[i].getRanking(), sortedTournamentDecks[i].getDeckName().c_str()); else sprintf(buffer, _("%i.: Player Deck: %s").c_str(),sortedTournamentDecks[i].getRanking(), sortedTournamentDecks[i].getDeckName().c_str()); f2->DrawString(buffer, 30, y); sprintf(buffer, _("%i/%i").c_str(), sortedTournamentDecks[i].getMatchesWon(), sortedTournamentDecks[i].getMatchesPlayed()); f2->DrawString(buffer, 300, y); sprintf(buffer, _("%i/%i").c_str(), sortedTournamentDecks[i].getGamesWon(), sortedTournamentDecks[i].getGamesPlayed()); f2->DrawString(buffer, 400, y); y+=20; } } } else { int gamesPlayed=0; if (scoreFinal) { f2->SetScale(1.5f); f2->DrawString(_("Final Score:").c_str() ,80, y); gamesPlayed=mVictories0+mVictories1; } else if (mCompetition) { f2->SetScale(1.5f); gamesPlayed=mVictories0+mVictories1+1; sprintf(buffer, _("Starting Game %i ...").c_str(), gamesPlayed); f2->DrawString(buffer, 80, y); } else { f2->SetScale(1.5f); gamesPlayed=mVictories0+mVictories1+1; f2->DrawString(_("Current Score:").c_str() ,80, y); } f2->SetScale(1); switch(mMatchMode) { case MATCHMODE_FIXED: sprintf(buffer, _("Game %i of %i games. ").c_str(),gamesPlayed,mNbGames); f2->DrawString(buffer ,30, 250); break; case MATCHMODE_BESTOF: //sprintf(buffer, _("Game %i, Best of %i mode, win at least %i games. ").c_str(),gamesPlayed,mNbGames,(int)ceil((double)mNbGames/2.)); sprintf(buffer, _("Game %i, Best of %i mode, win at least %i games. ").c_str(),gamesPlayed,mNbGames,(int)(((float)mNbGames/2.0f)+0.5f)); f2->DrawString(buffer ,30, 250); break; case MATCHMODE_DELTA: sprintf(buffer, _("Game %i, Win the match with %i wins difference. ").c_str(),gamesPlayed,mNbGames); f2->DrawString(buffer ,30, 250); break; case MATCHMODE_CONSECUTIVE: sprintf(buffer, _("Game %i, Win the match with %i wins in a row. ").c_str(), gamesPlayed,mNbGames); f2->DrawString(buffer ,30, 250); break; } f2->SetScale(0.8f); float y2=30; switch(mTournamentMode) { case TOURNAMENTMODES_ENDLESS: x_score=80; f2->DrawString(_("Endless demo mode").c_str() ,330, y2); sprintf(buffer, _("%i matches played.").c_str(),scoreMatchesPlayed-1); y2+=20; f2->DrawString(buffer ,330, y2); break; case TOURNAMENTMODES_GAUNTLET: x_score=80; //f2->DrawString(_("Gauntletmode").c_str() ,380, y2); f2->DrawString(_("Tournament:").c_str() ,330, y2); y2+=20; sprintf(buffer,_("Gauntlet (%i matches left)").c_str(),scoreMatchesToPlay); f2->DrawString(buffer ,330, y2); break; case TOURNAMENTMODES_KO: x_score=80; f2->DrawString(_("Tournament:").c_str() ,300, y2); y2+=20; sprintf(buffer,_("Knockout (%i decks left)").c_str(),scoreMatchesToPlay); f2->DrawString(buffer ,300, y2); y2+=20; f2->SetScale(0.7f); for (int i=0;i<8;i++) { if (sortedTournamentDecks[i].getDeckNumber()>0) { y2+=20; if (sortedTournamentDecks[i].getDeckType()==PLAYER_TYPE_HUMAN) sprintf(buffer, _("Player: %s (%i/%i)").c_str(), sortedTournamentDecks[i].getDeckName().c_str(),sortedTournamentDecks[i].getMatchesWon(),sortedTournamentDecks[i].getMatchesPlayed()); else sprintf(buffer, _("%s (%i/%i)").c_str(), sortedTournamentDecks[i].getDeckName().c_str(),sortedTournamentDecks[i].getMatchesWon(),sortedTournamentDecks[i].getMatchesPlayed()); f2->DrawString(buffer ,300, y2); } } break; case TOURNAMENTMODES_DOUBLEKO: x_score=80; f2->DrawString(_("Tournament:").c_str() ,300, y2); y2+=20; sprintf(buffer,_("Double Knockout (%i decks left):").c_str(),scoreMatchesToPlay); f2->DrawString(buffer ,300, y2); y2+=20; f2->SetScale(0.7f); for (int i=0;i<8;i++) { if (sortedTournamentDecks[i].getDeckNumber()>0) { y2+=20; if (sortedTournamentDecks[i].getDeckType()==PLAYER_TYPE_HUMAN) sprintf(buffer, _("Player: %s (%i/%i)").c_str(), sortedTournamentDecks[i].getDeckName().c_str(),sortedTournamentDecks[i].getMatchesWon(),sortedTournamentDecks[i].getMatchesPlayed()); else sprintf(buffer, _("%s (%i/%i)").c_str(), sortedTournamentDecks[i].getDeckName().c_str(),sortedTournamentDecks[i].getMatchesWon(),sortedTournamentDecks[i].getMatchesPlayed()); f2->DrawString(buffer ,300, y2); } } break; case TOURNAMENTMODES_ROUNDROBIN: // move results to the left x_score=80; f2->DrawString(_("Tournament:").c_str() ,300, y2); y2+=20; sprintf(buffer,_("Round robin (%i left)").c_str(),scoreMatchesToPlay); f2->DrawString(buffer ,300, y2); //displays the first 6 decks f2->SetScale(0.7f); for (int i=0;i<6;i++) { if (sortedTournamentDecks[i].getDeckNumber()>0) { y2+=20; if (sortedTournamentDecks[i].getDeckType()==PLAYER_TYPE_HUMAN) sprintf(buffer, _("%i. Player: %s (%i/%i)").c_str(), i+1,sortedTournamentDecks[i].getDeckName().c_str(),sortedTournamentDecks[i].getMatchesWon(),sortedTournamentDecks[i].getMatchesPlayed()); else //sprintf(buffer, _("%i. deck%i (%i/%i)").c_str(), i+1,sortedTournamentDecks[i].getDeckNumber()); sprintf(buffer, _("%i. %s (%i/%i)").c_str(), i+1,sortedTournamentDecks[i].getDeckName().c_str(),sortedTournamentDecks[i].getMatchesWon(),sortedTournamentDecks[i].getMatchesPlayed()); f2->DrawString(buffer ,300, y2); } } break; } y+=50; f2->SetScale(3); sprintf(buffer, _("%i").c_str(), mVictories1); f2->DrawString(buffer, x_score+80, y); y+=50; f2->DrawString(_("-").c_str() ,x_score+85, y); y+=50; sprintf(buffer, _("%i").c_str(), mVictories0); f2->DrawString(buffer, x_score+80, y); // For some reason, there's currently no player avatar prepared in-game: if (p1IsAI) { if (mgameType == GAME_TYPE_COMMANDER || mgameType == GAME_TYPE_CLASSIC || mgameType == GAME_TYPE_DEMO) r->RenderQuad(p1Quad.get(), x_score, 70, 0,1,1); } else { f2->SetScale(1); f2->DrawString(_("Player").c_str() ,x_score, 80); } if (p0IsAI) { if (mgameType == GAME_TYPE_COMMANDER || mgameType == GAME_TYPE_CLASSIC || mgameType == GAME_TYPE_DEMO) r->RenderQuad(p0Quad.get(), x_score+190, 215, 0,1,1); } else { f2->SetScale(1); f2->DrawString(_("Player").c_str() ,x_score+160, y+25); } f2->SetScale(1); } } void Tournament::initTournament() { scoreMatchesToPlay=0; scoreMatchesPlayed=0; if (mTournamentMode==TOURNAMENTMODES_KO || mTournamentMode==TOURNAMENTMODES_DOUBLEKO || mTournamentMode==TOURNAMENTMODES_ROUNDROBIN) { if (TournamentsDecksID[0]=0; i--) { if (nmbDecks>1) { Deck[i].increaseDeckNumber(); //second player must not be a human player if (i==1 && Deck[i].getDeckNumber() <= gauntletLastDeckNumber[i] && !Deck[i].isAI()) Deck[i].increaseDeckNumber(); if (Deck[i].getDeckNumber() > gauntletLastDeckNumber[i]) { Deck[i].setDeckNumber(1); } else { nextDeckFound = true; break; } } } Deck[0].deleteStats(); Deck[1].deleteStats(); } else if (mTournamentMode==TOURNAMENTMODES_KO) { assert(TournamentsDecksID[0]Deck[1].getVictories()) { TournamentsDecks[TournamentsDecksID[0]].winMatch(); TournamentsDecks[TournamentsDecksID[1]].looseMatch(); } else { TournamentsDecks[TournamentsDecksID[1]].winMatch(); TournamentsDecks[TournamentsDecksID[0]].looseMatch(); } //update played games and won games stats TournamentsDecks[TournamentsDecksID[1]].setGamesPlayed(Deck[1].getGamesPlayed()); TournamentsDecks[TournamentsDecksID[1]].setGamesWon(Deck[1].getGamesWon()); TournamentsDecks[TournamentsDecksID[0]].setGamesPlayed(Deck[0].getGamesPlayed()); TournamentsDecks[TournamentsDecksID[0]].setGamesWon(Deck[0].getGamesWon()); int n = TournamentsDecks.size(); int r = (int)ceil(log(double(n))/log(2.)); int Nbye=(int)pow(2.,double(r)) -n; //printf("n:%i r:%i nbye:%i\n",n,r,Nbye); if (TournamentsDecks.size()>0) { TournamentsDecksID[0]=TournamentsDecksID[0]+2; TournamentsDecksID[1]=TournamentsDecksID[1]+2; //is Deck available? if (TournamentsDecks.size()>2 && (TournamentsDecksID[1] >= TournamentsDecks.size()-Nbye || TournamentsDecksID[0] >= TournamentsDecks.size()-Nbye)) { // next Stage //remove looser Decks unsigned int k=0; while(k1) nextDeckFound = true; } else if (TournamentsDecks.size()==2) { TournamentsDecksID[0]=0; TournamentsDecksID[1]=1; // final match if both last decks win all matches until now. if (TournamentsDecks.at(0).getMatchesWon()==TournamentsDecks.at(0).getMatchesPlayed() && TournamentsDecks.at(1).getMatchesWon()==TournamentsDecks.at(1).getMatchesPlayed()) { nextDeckFound = true; } } else { nextDeckFound = true; } } if (nextDeckFound) { Deck[0]=TournamentsDecks.at(TournamentsDecksID[0]); Deck[1]=TournamentsDecks.at(TournamentsDecksID[1]); //printf("Deckfound %i vs %i (%i)\n",TournamentsDecksID[0],TournamentsDecksID[1],TournamentsDecks.size()); } } else if (mTournamentMode==TOURNAMENTMODES_DOUBLEKO) { assert(TournamentsDecksID[0]Deck[1].getVictories()) { TournamentsDecks[TournamentsDecksID[0]].winMatch(); TournamentsDecks[TournamentsDecksID[1]].looseMatch(); } else { TournamentsDecks[TournamentsDecksID[1]].winMatch(); TournamentsDecks[TournamentsDecksID[0]].looseMatch(); } //update played games and won games stats TournamentsDecks[TournamentsDecksID[1]].setGamesPlayed(Deck[1].getGamesPlayed()); TournamentsDecks[TournamentsDecksID[1]].setGamesWon(Deck[1].getGamesWon()); TournamentsDecks[TournamentsDecksID[0]].setGamesPlayed(Deck[0].getGamesPlayed()); TournamentsDecks[TournamentsDecksID[0]].setGamesWon(Deck[0].getGamesWon()); int n = TournamentsDecks.size(); int r = (int)ceil(log(double(n))/log(2.)); int Nbye=(int)pow(2.,double(r)) -n; if (TournamentsDecks.size()>0) { if (looserDecks) { // find next to teams who had loose one time wonMatches != playedMatches TournamentsDecksID[0]=TournamentsDecksID[1]+1; while ((TournamentsDecksID[0] < TournamentsDecks.size()) && TournamentsDecks[TournamentsDecksID[0]].getMatchesPlayed()!=(TournamentsDecks[TournamentsDecksID[0]].getMatchesWon()+1)) TournamentsDecksID[0]++; TournamentsDecksID[1]=TournamentsDecksID[0]+1; while ((TournamentsDecksID[1] < TournamentsDecks.size()) && TournamentsDecks[TournamentsDecksID[1]].getMatchesPlayed()!=(TournamentsDecks[TournamentsDecksID[1]].getMatchesWon()+1)) TournamentsDecksID[1]++; } else { // find next to teams who had never loose one time wonMatches == playedMatches TournamentsDecksID[0]=TournamentsDecksID[1]+1; while ((TournamentsDecksID[0] < TournamentsDecks.size()) && TournamentsDecks[TournamentsDecksID[0]].getMatchesPlayed()!=TournamentsDecks[TournamentsDecksID[0]].getMatchesWon()) TournamentsDecksID[0]++; TournamentsDecksID[1]=TournamentsDecksID[0]+1; while ((TournamentsDecksID[1] < TournamentsDecks.size()) && TournamentsDecks[TournamentsDecksID[1]].getMatchesPlayed()!=TournamentsDecks[TournamentsDecksID[1]].getMatchesWon()) TournamentsDecksID[1]++; //byes are only allowed in the first round for ( unsigned int i=0;i1) { Nbye=0; break; } if (TournamentsDecks.size()>2 && (TournamentsDecksID[1] >= TournamentsDecks.size()-Nbye || TournamentsDecksID[0] >= TournamentsDecks.size()-Nbye)) { looserDecks=true; TournamentsDecksID[0]=0; TournamentsDecksID[1]=1; while ((TournamentsDecksID[0] < TournamentsDecks.size()) && TournamentsDecks[TournamentsDecksID[0]].getMatchesPlayed()!=(TournamentsDecks[TournamentsDecksID[0]].getMatchesWon()+1)) TournamentsDecksID[0]++; TournamentsDecksID[1]=TournamentsDecksID[0]+1; while ((TournamentsDecksID[1] < TournamentsDecks.size()) && TournamentsDecks[TournamentsDecksID[1]].getMatchesPlayed()!=(TournamentsDecks[TournamentsDecksID[1]].getMatchesWon()+1)) TournamentsDecksID[1]++; } } //is Deck available? if (looserDecks && TournamentsDecks.size()>2 && (TournamentsDecksID[1] >= TournamentsDecks.size() || TournamentsDecksID[0] >= TournamentsDecks.size())) { printf("next stage %i,%i\n",TournamentsDecksID[0],TournamentsDecksID[1]); // next Stage //remove double looser Decks unsigned int k=0; while(k2) { //check if only one winner deck is available int winnerDecks=0; for (unsigned int i=0;i1) looserDecks=false; else looserDecks=true; if (!looserDecks) { // find next to teams who had never loose one time wonMatches == playedMatches while ((TournamentsDecksID[0] < TournamentsDecks.size()) && TournamentsDecks[TournamentsDecksID[0]].getMatchesPlayed()!=TournamentsDecks[TournamentsDecksID[0]].getMatchesWon()) TournamentsDecksID[0]++; TournamentsDecksID[1]=TournamentsDecksID[0]+1; while ((TournamentsDecksID[1] < TournamentsDecks.size()) && TournamentsDecks[TournamentsDecksID[1]].getMatchesPlayed()!=TournamentsDecks[TournamentsDecksID[1]].getMatchesWon()) TournamentsDecksID[1]++; } else { while ((TournamentsDecksID[0] < TournamentsDecks.size()) && TournamentsDecks[TournamentsDecksID[0]].getMatchesPlayed()!=TournamentsDecks[TournamentsDecksID[0]].getMatchesWon()+1) TournamentsDecksID[0]++; TournamentsDecksID[1]=TournamentsDecksID[0]+1; while ((TournamentsDecksID[1] < TournamentsDecks.size()) && TournamentsDecks[TournamentsDecksID[1]].getMatchesPlayed()!=TournamentsDecks[TournamentsDecksID[1]].getMatchesWon()+1) TournamentsDecksID[1]++; } } else looserDecks=true; //decks ok? if (TournamentsDecks.size()>1) nextDeckFound = true; } else if (TournamentsDecks.size()==2) { TournamentsDecksID[0]=0; TournamentsDecksID[1]=1; // final match if both last decks win all matches until now. if (!looserDecks) { nextDeckFound = true; looserDecks=true; } } else { nextDeckFound = true; } } if (nextDeckFound) { Deck[0]=TournamentsDecks.at(TournamentsDecksID[0]); Deck[1]=TournamentsDecks.at(TournamentsDecksID[1]); //printf("Deckfound %i vs %i (%i)\n",TournamentsDecksID[0],TournamentsDecksID[1],TournamentsDecks.size()); } } else if (mTournamentMode==TOURNAMENTMODES_ROUNDROBIN) { assert(TournamentsDecksID[0]Deck[1].getVictories()) { TournamentsDecks[TournamentsDecksID[0]].winMatch(); TournamentsDecks[TournamentsDecksID[1]].looseMatch(); } else if (Deck[1].getVictories()>Deck[0].getVictories()) { TournamentsDecks[TournamentsDecksID[1]].winMatch(); TournamentsDecks[TournamentsDecksID[0]].looseMatch(); } else { //draw TournamentsDecks[TournamentsDecksID[1]].drawMatch(); TournamentsDecks[TournamentsDecksID[0]].drawMatch(); } //update played games and won games stats TournamentsDecks[TournamentsDecksID[0]].setGamesPlayed(Deck[0].getGamesPlayed()); TournamentsDecks[TournamentsDecksID[0]].setGamesWon(Deck[0].getGamesWon()); TournamentsDecks[TournamentsDecksID[1]].setGamesPlayed(Deck[1].getGamesPlayed()); TournamentsDecks[TournamentsDecksID[1]].setGamesWon(Deck[1].getGamesWon()); if (TournamentsDecks.size()>0) { // decks are chosen in following way: 1-2,1-3,2-3,1-4,2-4,3-4, ... until 1-n,...,(n-1)-n TournamentsDecksID[0]++; //is Deck available? if (TournamentsDecksID[0] == TournamentsDecksID[1]) { TournamentsDecksID[0]=0; TournamentsDecksID[1]++; //decks ok? if (TournamentsDecksID[0] < TournamentsDecksID[1] && TournamentsDecksID[1] < TournamentsDecks.size()) nextDeckFound = true; } else { nextDeckFound = true; } } if (nextDeckFound) { Deck[0]=TournamentsDecks.at(TournamentsDecksID[0]); Deck[1]=TournamentsDecks.at(TournamentsDecksID[1]); //printf("Deckfound %i vs %i (%i)\n",TournamentsDecksID[0],TournamentsDecksID[1],TournamentsDecks.size()); } }//endif round robin else if (isEndlessDemo()) { Deck[0].deleteStats(); Deck[1].deleteStats(); if (nmbDecks>1) { Deck[0].setDeckNumber(rand() % nmbDecks + 1); Deck[1].setDeckNumber(rand() % nmbDecks + 1); } else { Deck[0].setDeckNumber(1); Deck[1].setDeckNumber(1); } nextDeckFound = true; } return nextDeckFound; } void Tournament::calculateRanking() { int rankingPos=1; unsigned int numberOfDecks=0; switch(mTournamentMode) { case 0://no tournament if (Deck[0].getVictories()>Deck[1].getVictories()) { Deck[0].setRanking(1); Deck[1].setRanking(2); } else { Deck[1].setRanking(1); Deck[0].setRanking(2); } break; case TOURNAMENTMODES_ROUNDROBIN: rankingPos=1; // starting from the maximal possible number of matchWins for (int maximalWin=TournamentsDecks.size();maximalWin>-1;maximalWin--) { // goes trough each deck and search for the deck which has matchwins equal to maximalwins for (unsigned int j=0;j8) numberOfDecks=8; for (unsigned int i=0;iTournamentsDecks[1].getMatchesWon()) { TournamentsDecks[0].setRanking(1); TournamentsDecks[1].setRanking(2); sortedTournamentDecks[0]=TDeck(TournamentsDecks.at(0)); sortedTournamentDecks[1]=TDeck(TournamentsDecks.at(1)); } else { TournamentsDecks[1].setRanking(1); TournamentsDecks[0].setRanking(2); sortedTournamentDecks[0]=TDeck(TournamentsDecks.at(1)); sortedTournamentDecks[1]=TDeck(TournamentsDecks.at(0)); } } else { numberOfDecks=TournamentsDecks.size(); if (numberOfDecks>8) numberOfDecks=8; for (unsigned int i=0;iDeck[1].getVictories(); else didWin=Deck[1].getVictories()>Deck[0].getVictories(); break; case TOURNAMENTMODES_KO: for (unsigned int player=0;player