Files
wagic/projects/mtg/src/GameStateDuel.cpp
wrenczes d5f3e4cfea Enabled precompiled headers for the build. This cuts the win compile time in debug by at least half on my laptop; on the psp compile, it shaves it down by ~ 45 seconds. I only did a cursory inspection of what to add to PrecompiledHeader.h, there's probably more that we can throw in there for more incremental speed improvements.
Also fixed the project includes so that we don't need to always use the indirect include path, ie:
#include "../include/foo.h" -> #include "foo.h"

I'm don't know much about make files - if I busted the linux build, mea culpa, but I think we're okay on that front too.  For future reference, here's the most straightforward link on the topic of adding pch support to make files:

http://www.mercs-eng.com/~hulud/index.php?2008/06/13/6-writing-a-good-makefile-for-a-c-project
2010-10-24 05:55:24 +00:00

613 lines
18 KiB
C++

#include "PrecompiledHeader.h"
#include "GameStateDuel.h"
#include "GameOptions.h"
#include "utils.h"
#include "AIPlayer.h"
#include "AIMomirPlayer.h"
#include "PlayerData.h"
#include "DeckStats.h"
#include "DeckManager.h"
#include "DeckMetaData.h"
#include "MTGRules.h"
#include "Credits.h"
#include "Translate.h"
#include "Rules.h"
#ifdef TESTSUITE
#include "TestSuiteAI.h"
#endif
#if defined (WIN32) || defined (LINUX)
#include <time.h>
#endif
enum ENUM_DUEL_STATE
{
DUEL_STATE_START,
DUEL_STATE_END,
DUEL_STATE_CHOOSE_DECK1,
DUEL_STATE_CHOOSE_DECK1_TO_2,
DUEL_STATE_CHOOSE_DECK2,
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_ERROR
};
enum ENUM_DUEL_MENUS
{
DUEL_MENU_GAME_MENU,
DUEL_MENU_CHOOSE_DECK,
DUEL_MENU_CHOOSE_OPPONENT
};
GameStateDuel::GameStateDuel(GameApp* parent): GameState(parent) {
for (int i = 0; i<2; i ++){
deck[i]=NULL;
mPlayers[i]=NULL;
}
premadeDeck = false;
game = NULL;
deckmenu = NULL;
opponentMenu = NULL;
menu = NULL;
#ifdef TESTSUITE
testSuite = NULL;
#endif
credits = NULL;
rules = NULL;
}
GameStateDuel::~GameStateDuel() {
End();
}
void GameStateDuel::Start()
{
JRenderer * renderer = JRenderer::GetInstance();
renderer->EnableVSync(true);
OpponentsDeckid=0;
#ifdef TESTSUITE
SAFE_DELETE(testSuite);
testSuite = NEW TestSuite(RESPATH"/test/_tests.txt",mParent->collection);
#endif
mGamePhase = DUEL_STATE_CHOOSE_DECK1;
credits = NEW Credits();
menu = NULL;
int decksneeded = 0;
for (int i = 0; i<2; i ++){
if (mParent->players[i] == PLAYER_TYPE_HUMAN){
decksneeded = 1;
deckmenu = NEW SimpleMenu(DUEL_MENU_CHOOSE_DECK, this, Fonts::MENU_FONT, 35, 25, "Choose a Deck");
DeckManager *deckManager = DeckManager::GetInstance();
vector<DeckMetaData *> playerDeckList = getValidDeckMetaData( options.profileFile() );
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){
//translate deck creating desc
Translator * t = Translator::GetInstance();
map<string,string>::iterator it = t->deckValues.find("Create your Deck!");
if (it != t->deckValues.end())
deckmenu->Add( MENUITEM_NEW_DECK, "Create your Deck!", it->second);
else
deckmenu->Add( MENUITEM_NEW_DECK, "Create your Deck!", "Highly recommended to get\nthe full Wagic experience!");
premadeDeck = true;
fillDeckMenu(deckmenu,RESPATH"/player/premade");
}
deckmenu->Add( MENUITEM_NEW_DECK, "New Deck...");
deckmenu->Add( MENUITEM_MAIN_MENU, "Main Menu", _("Return to Main Menu").c_str());
}
for (int i = 0; i < 2; ++i){
mPlayers[i] = NULL;
}
}
void GameStateDuel::loadPlayer(int playerId, int decknb, int isAI){
if (decknb) {
if (!isAI) { //Human Player
char deckFile[255];
if(premadeDeck)
sprintf(deckFile, RESPATH"/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);
MTGDeck * tempDeck = NEW MTGDeck(deckFile, mParent->collection);
mPlayers[playerId] = NEW HumanPlayer(tempDeck, deckFile, deckFileSmall);
deck[playerId] = mPlayers[playerId]->game;
delete tempDeck;
}
else { //AI Player, chooses deck
AIPlayerFactory playerCreator;
Player * opponent = NULL;
if (playerId == 1) opponent = mPlayers[0];
mPlayers[playerId] = playerCreator.createAIPlayer(mParent->collection,opponent,decknb);
deck[playerId] = mPlayers[playerId]->game;
}
}
else { //Random AI deck
AIPlayerFactory playerCreator;
Player * opponent = NULL;
if (playerId == 1) opponent = mPlayers[0];
mPlayers[playerId] = playerCreator.createAIPlayer(mParent->collection,opponent);
deck[playerId] = mPlayers[playerId]->game;
}
}
void GameStateDuel::initRand(unsigned int seed){
if (!seed) seed = time(0);
srand(seed);
}
#ifdef TESTSUITE
void GameStateDuel::loadTestSuitePlayers(){
if (!testSuite) return;
initRand(testSuite->seed);
SAFE_DELETE(game);
for (int i = 0; i < 2; i++){
mPlayers[i] = NEW TestSuiteAI(testSuite, i);
deck[i] = mPlayers[i]->game;
}
mParent->gameType = testSuite->gameType;
GameObserver::Init(mPlayers, 2);
game = GameObserver::GetInstance();
game->startGame(rules);
if (mParent->gameType == GAME_TYPE_MOMIR){
game->addObserver(NEW MTGMomirRule(-1, mParent->collection));
}
}
#endif
void GameStateDuel::End()
{
DebugTrace("Ending GameStateDuel");
SAFE_DELETE(deckmenu);
JRenderer::GetInstance()->EnableVSync(false);
if (mPlayers[0] && mPlayers[1]) mPlayers[0]->End();
GameObserver::EndInstance();
DeckManager::EndInstance();
game = NULL;
premadeDeck = false;
for (int i = 0; i < 2; i++){
mPlayers[i] = NULL;
deck[i] = NULL;
}
SAFE_DELETE(credits);
SAFE_DELETE(rules);
SAFE_DELETE(menu);
SAFE_DELETE(opponentMenu);
#ifdef TESTSUITE
SAFE_DELETE(testSuite);
#endif
}
//TODO Move This to utils or ResourceManager. Don't we have more generic functions that can do that?
bool GameStateDuel::MusicExist(string FileName){
string filepath = RESPATH;
filepath = filepath + "/" + resources.musicFile(FileName);
std::ifstream file(filepath.c_str());
if (file) {
file.close();
return true;
}
else
return false;
}
void GameStateDuel::ensureOpponentMenu(){
if (!opponentMenu){
opponentMenu = NEW SimpleMenu(DUEL_MENU_CHOOSE_OPPONENT, this, Fonts::MENU_FONT, 35, 25, "Choose Opponent");
opponentMenu->Add( MENUITEM_RANDOM_AI, "Random");
if (options[Options::EVILTWIN_MODE_UNLOCKED].number)
opponentMenu->Add( MENUITEM_EVIL_TWIN, "Evil Twin", _("Can you play against yourself?").c_str());
DeckManager * deckManager = DeckManager::GetInstance();
vector<DeckMetaData* > opponentDeckList = fillDeckMenu( opponentMenu, RESPATH"/ai/baka", "ai_baka", mPlayers[0]);
deckManager->updateMetaDataList(&opponentDeckList, true);
opponentMenu->Add( MENUITEM_CANCEL, "Cancel", _("Choose a different player deck").c_str());
opponentDeckList.clear();
}
}
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;
case DUEL_STATE_CHOOSE_DECK1:
if (mParent->gameType == GAME_TYPE_MOMIR){
rules = NEW Rules("momir.txt");
mGamePhase = DUEL_STATE_PLAY;
} else if (mParent->gameType == GAME_TYPE_RANDOM1){
rules = NEW Rules ("random1.txt");
mGamePhase = DUEL_STATE_PLAY;
}else if (mParent->gameType == GAME_TYPE_RANDOM2) {
rules = NEW Rules ("random2.txt");
mGamePhase = DUEL_STATE_PLAY;
}
#ifdef TESTSUITE
else if (mParent->players[1] == PLAYER_TYPE_TESTSUITE){
if (testSuite && testSuite->loadNext()){
rules = NEW Rules("testsuite.txt");
loadTestSuitePlayers();
mGamePhase = DUEL_STATE_PLAY;
testSuite->pregameTests();
testSuite->initGame();
}else{
if (!game){
mGamePhase = DUEL_STATE_ERROR;
}else{
mGamePhase = DUEL_STATE_END;
}
}
}
#endif
else{
if (!rules) rules = NEW Rules("mtg.txt");
if (mParent->players[0] == PLAYER_TYPE_HUMAN)
deckmenu->Update(dt);
else{
loadPlayer(0);
mGamePhase = DUEL_STATE_CHOOSE_DECK2;
}
}
break;
case DUEL_STATE_CHOOSE_DECK1_TO_2:
if (deckmenu->closed) mGamePhase = DUEL_STATE_CHOOSE_DECK2;
else deckmenu->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){
ensureOpponentMenu();
opponentMenu->Update(dt);
}else{
loadPlayer(1);
mGamePhase = DUEL_STATE_PLAY;
}
}
break;
case DUEL_STATE_CHOOSE_DECK2_TO_PLAY:
if (mParent->players[1] == PLAYER_TYPE_HUMAN){
if (deckmenu->closed) mGamePhase = DUEL_STATE_PLAY;
else deckmenu->Update(dt);
}
else{
ensureOpponentMenu();
if (opponentMenu->closed) mGamePhase = DUEL_STATE_PLAY;
else opponentMenu->Update(dt);
}
break;
case DUEL_STATE_PLAY:
if (!game){
GameObserver::Init(mPlayers, 2);
game = GameObserver::GetInstance();
game->startGame(rules);
if (mParent->gameType == GAME_TYPE_MOMIR){
game->addObserver(NEW MTGMomirRule(-1, mParent->collection));
}
//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);
}
else if(mParent->gameType == GAME_TYPE_CLASSIC)
musictrack = "ai_baka_music.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)
musictrack = "ai_baka_music_random.mp3";
if(!MusicExist(musictrack))
musictrack = "ai_baka_music.mp3";
GameApp::playMusic(musictrack);
}
game->Update(dt);
if (game->gameOver){
if (game->players[1]->playMode != Player::MODE_TEST_SUITE)
credits->compute(game->players[0],game->players[1], mParent);
mGamePhase = DUEL_STATE_END;
#ifdef TESTSUITE
if (mParent->players[1] == PLAYER_TYPE_TESTSUITE){
if (testSuite->loadNext()){
loadTestSuitePlayers();
mGamePhase = DUEL_STATE_PLAY;
testSuite->initGame();
}
else
mGamePhase = DUEL_STATE_END;
}
else
#endif
if (mParent->players[0] == PLAYER_TYPE_CPU && mParent->players[1] == PLAYER_TYPE_CPU){
End();
Start();
}
}
if (mEngine->GetButtonClick(JGE_BTN_MENU)) {
if (!menu) {
menu = NEW SimpleMenu(DUEL_MENU_GAME_MENU, this, Fonts::MENU_FONT, SCREEN_WIDTH/2-100, 25, game->players[1]->deckName.c_str());
int cardsinhand = game->players[0]->game->hand->nb_cards;
//almosthumane - mulligan
if ((game->turn < 1) && (cardsinhand != 0)
&& game->currentGamePhase == Constants::MTG_PHASE_FIRSTMAIN
&& game->players[0]->game->inPlay->nb_cards == 0
&& game->players[0]->game->graveyard->nb_cards == 0
&& game->players[0]->game->exile->nb_cards == 0) //1st Play Check
//IF there was no play at the moment automatically mulligan
{
menu->Add( MENUITEM_MULLIGAN, "Mulligan");
}
//END almosthumane - mulligan
menu->Add(MENUITEM_MAIN_MENU, "Back to main menu");
menu->Add(MENUITEM_CANCEL, "Cancel");
}
mGamePhase = DUEL_STATE_MENU;
}
break;
case DUEL_STATE_MENU:
menu->Update(dt);
break;
case DUEL_STATE_CANCEL:
menu->Update(dt);
if (menu->closed) {
mGamePhase = DUEL_STATE_PLAY;
SAFE_DELETE(menu);
}
break;
case DUEL_STATE_BACK_TO_MAIN_MENU:
if(menu){
menu->Update(dt);
if (menu->closed) {
PlayerData * playerdata = NEW PlayerData(mParent->collection);
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);
}
}
void GameStateDuel::Render()
{
WFont * mFont = resources.GetWFont(Fonts::MAIN_FONT);
JRenderer * r = JRenderer::GetInstance();
r->ClearScreen(ARGB(0,0,0,0));
if (game)
game->Render();
switch (mGamePhase)
{
case DUEL_STATE_END:
{
JRenderer * r = JRenderer::GetInstance();
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];
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_CHOOSE_DECK1:
case DUEL_STATE_CHOOSE_DECK1_TO_2:
case DUEL_STATE_CHOOSE_DECK2:
case DUEL_STATE_CHOOSE_DECK2_TO_PLAY:
if (mParent->gameType != GAME_TYPE_CLASSIC)
mFont->DrawString(_("LOADING DECKS").c_str(),0,SCREEN_HEIGHT/2);
else{
if (opponentMenu)
opponentMenu->Render();
else if (deckmenu)
deckmenu->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;
case DUEL_STATE_MENU:
case DUEL_STATE_CANCEL:
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();
}
}
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_OPPONENT:
{
switch(controlId){
case MENUITEM_RANDOM_AI:
loadPlayer(1);
opponentMenu->Close();
mGamePhase = DUEL_STATE_CHOOSE_DECK2_TO_PLAY;
break;
default:
// cancel option. return to player deck selection
if (controlId == MENUITEM_CANCEL)
{
opponentMenu->Close();
deckmenu->Close();
mParent->SetNextState( DUEL_STATE_CHOOSE_DECK1 );
mGamePhase = DUEL_MENU_GAME_MENU;
break;
}
else if ( controlId != MENUITEM_EVIL_TWIN && aiDeckSize > 0) // evil twin
deckNumber = deckManager->getAIDeckOrderList()->at( controlId - 1 )->getDeckId();
loadPlayer(1,deckNumber,1);
OpponentsDeckid=deckNumber;
opponentMenu->Close();
mGamePhase = DUEL_STATE_CHOOSE_DECK2_TO_PLAY;
break;
}
break;
}
case DUEL_MENU_CHOOSE_DECK:
{
if ( controlId == MENUITEM_RANDOM_PLAYER ) // Random Player Deck Selection
{
vector<DeckMetaData *> * playerDeckList = deckManager->getPlayerDeckOrderList();
deckNumber = playerDeckList->at(WRand() * 1001 % (playerDeckList->size()) )->getDeckId();
loadPlayer( 0, deckNumber );
deckmenu->Close();
mGamePhase = DUEL_STATE_CHOOSE_DECK2_TO_PLAY;
break;
}
else if (controlId == MENUITEM_MAIN_MENU ) // user clicked on "Cancel"
{
if (deckmenu)
deckmenu->Close();
mGamePhase = DUEL_STATE_BACK_TO_MAIN_MENU;
break;
}
if (controlId < 0){
mParent->SetNextState(GAME_STATE_DECK_VIEWER);
return;
}
if (mGamePhase == DUEL_STATE_CHOOSE_DECK1){
vector<DeckMetaData *> * playerDeck = deckManager->getPlayerDeckOrderList();
if ( !premadeDeck && controlId > 0 )
deckNumber = playerDeck->at( controlId - 1 )->getDeckId();
loadPlayer(0,deckNumber);
deckmenu->Close();
mGamePhase = DUEL_STATE_CHOOSE_DECK1_TO_2;
}else{
loadPlayer(1,controlId);
deckmenu->Close();
mGamePhase = DUEL_STATE_CHOOSE_DECK2_TO_PLAY;
}
break;
}
default:
{
switch (controlId)
{
case MENUITEM_MAIN_MENU:
menu->Close();
mGamePhase = DUEL_STATE_BACK_TO_MAIN_MENU;
break;
case MENUITEM_CANCEL:
menu->Close();
mGamePhase = DUEL_STATE_CANCEL;
break;
case MENUITEM_MULLIGAN:
//almosthumane - mulligan
{
int cardsinhand = game->players[0]->game->hand->nb_cards;
for (int i = 0 ; i < cardsinhand; i ++) //Discard hand
game->currentPlayer->game->putInZone(game->currentPlayer->game->hand->cards[0],game->currentPlayer->game->hand ,game->currentPlayer->game->library);
game->currentPlayer->game->library->shuffle(); //Shuffle
for (int i = 0; i < (cardsinhand-1); i ++) game->draw(); //Draw hand with 1 less card penalty //almhum
menu->Close();
mGamePhase = DUEL_STATE_CANCEL;
break;
}
//END almosthumane - mulligan
}
}
}
}