- Modified DeckManager class to not use a global instance anymore when used within the game engine

- Modified DuelLayers to not use a global MTGPhaseGame instance anymore
- Moved the reset of currentActionCard out of the ActionLayer render function : that fixes the remaing problematic tests in the multithreaded testsuite
- Added a method in ActionLayer converting a card ability into a menu index
- Used this new method in the game observer to log correctly AI ability actions
- Added a DumpAssert method in the game observer, it can be used to dump the game and assert in order to easy crash reproduction
- Cleaned up TargetList properties access
- Added an optimisation in GuiMana to not compute update code if the rendering is not used (multi-threaded mode)
- Added a deadlock detection in the test AI vs AI multithreaded mode
- Fixed minor bugs in test AI vs AI multithreaded mode
- Added a games/second counter in the test AI vs AI rendering
This commit is contained in:
Xawotihs
2011-11-23 19:11:48 +00:00
parent dca6d3ad38
commit 29132073de
20 changed files with 153 additions and 73 deletions

View File

@@ -37,6 +37,7 @@ public:
int receiveEventPlus(WEvent * event);
int reactToTargetClick(Targetable * card);
int isReactingToClick(MTGCardInstance * card);
bool getMenuIdFromCardAbility(MTGCardInstance *card, MTGAbility *ability, int& menuId);
int reactToClick(MTGCardInstance * card);
int reactToClick(ActionElement * ability, MTGCardInstance * card);
int reactToTargetClick(ActionElement * ability, Targetable * card);

View File

@@ -8,21 +8,19 @@ using namespace std;
class DeckManager
{
private:
static bool instanceFlag;
vector<DeckMetaData*> playerDeckOrderList;
vector<DeckMetaData*> aiDeckOrderList;
map<string, StatsWrapper*> playerDeckStatsMap;
map<string, StatsWrapper*> aiDeckStatsMap;
static DeckManager *mInstance;
public:
DeckManager()
{
//private constructor
}
public:
vector<DeckMetaData*> playerDeckOrderList;
vector<DeckMetaData*> aiDeckOrderList;
map<string, StatsWrapper*> playerDeckStatsMap;
map<string, StatsWrapper*> aiDeckStatsMap;
void updateMetaDataList(vector<DeckMetaData*>* refList, bool isAI);
vector<DeckMetaData*> * getPlayerDeckOrderList();
vector<DeckMetaData*> * getAIDeckOrderList();
@@ -40,7 +38,7 @@ public:
//convenience method to get the difficulty rating between two decks. This should be refined a little more
//since the eventual move of all deck meta data should be managed by this class
static int getDifficultyRating(Player *statsPlayer, Player *player);
int getDifficultyRating(Player *statsPlayer, Player *player);
~DeckManager();

View File

@@ -14,6 +14,7 @@ class GuiCombat;
class GuiAvatars;
class CardSelectorBase;
struct Pos;
class MTGGamePhase;
class DuelLayers
{
@@ -27,6 +28,7 @@ protected:
GuiHandSelf *hand;
GuiAvatars * avatars;
GameObserver* observer;
MTGGamePhase* phaseHandler;
public:
DuelLayers();
@@ -36,6 +38,7 @@ public:
ActionStack * stackLayer();
GuiCombat * combatLayer();
GuiAvatars * GetAvatars();
MTGGamePhase* getPhaseHandler() {return phaseHandler;};
void init(GameObserver* go);
virtual void Update(float dt, Player * player);
void CheckUserInput(int isAI);

View File

@@ -23,6 +23,7 @@ class TargetChooser;
class Rules;
class TestSuiteGame;
class Trash;
class DeckManager;
using namespace std;
class GameObserver{
@@ -37,6 +38,8 @@ class GameObserver{
RandomGenerator randomGenerator;
WResourceManager* mResourceManager;
JGE* mJGE;
DeckManager* mDeckManager;
size_t updateCtr;
#ifdef ACTION_LOGGING_TESTING
GameObserver* oldGame;
@@ -139,6 +142,8 @@ class GameObserver{
CardSelectorBase* getCardSelector() { return mLayers->mCardSelector;};
bool operator==(const GameObserver& aGame);
JGE* getInput(){return mJGE;};
DeckManager* getDeckManager(){ return mDeckManager; };
void dumpAssert(bool val);
};

View File

@@ -57,6 +57,7 @@ public:
#endif
#ifdef AI_CHANGE_TESTING
int startTime;
int totalTestGames;
int testPlayer2Victories;
int totalAIDecks;

View File

@@ -13,12 +13,10 @@ protected:
float animation;
int currentState;
WFont * mFont;
static MTGGamePhase* instance;
GameObserver* observer;
public:
MTGGamePhase(GameObserver* g, int id);
static MTGGamePhase* GetInstance() { return instance; };
virtual void Update(float dt);
bool CheckUserInput(JButton key);
virtual MTGGamePhase * clone() const;

View File

@@ -14,15 +14,16 @@ using std::vector;
class TargetsList
{
private:
protected:
size_t iterateTarget(Targetable * previous);
vector<Targetable*> targets;
public:
TargetsList();
TargetsList(Targetable * _targets[], int nbtargets);
vector<Targetable*> targets;
int alreadyHasTarget(Targetable * target);
int removeTarget(Targetable * _card);
int toggleTarget(Targetable * _card);
size_t getNbTargets() {return targets.size();};
virtual int addTarget(Targetable * _target);
MTGCardInstance * getNextCardTarget(MTGCardInstance * previous = 0);
Player * getNextPlayerTarget(Player * previous = 0);

View File

@@ -236,7 +236,7 @@ AIPlayer * AIPlayerFactory::createAIPlayer(GameObserver *observer, MTGAllCards *
deckid = 1 + WRand() % (nbdecks);
}
sprintf(deckFile, "ai/baka/deck%i.txt", deckid);
DeckMetaData *aiMeta = DeckManager::GetInstance()->getDeckMetaDataByFilename( deckFile, true);
DeckMetaData *aiMeta = observer->getDeckManager()->getDeckMetaDataByFilename( deckFile, true);
avatarFilename = aiMeta->getAvatarFilename();
sprintf(deckFileSmall, "ai_baka_deck%i", deckid);
}
@@ -245,7 +245,7 @@ AIPlayer * AIPlayerFactory::createAIPlayer(GameObserver *observer, MTGAllCards *
if ( opponent )
{
bool isOpponentAI = opponent->isAI() == 1;
DeckMetaData *meta = DeckManager::GetInstance()->getDeckMetaDataByFilename( opponent->deckFile, isOpponentAI);
DeckMetaData *meta = observer->getDeckManager()->getDeckMetaDataByFilename( opponent->deckFile, isOpponentAI);
if ( meta && meta->getVictoryPercentage() >= 65)
deckSetting = HARD;
}
@@ -320,7 +320,7 @@ AIPlayer * AIPlayerFactory::createAIPlayerTest(GameObserver *observer, MTGAllCar
deckid = 1 + WRand() % (nbdecks);
sprintf(deckFile, "%sdeck%i.txt", folder.c_str(), deckid);
DeckMetaData *aiMeta = DeckManager::GetInstance()->getDeckMetaDataByFilename( deckFile, true);
DeckMetaData *aiMeta = observer->getDeckManager()->getDeckMetaDataByFilename( deckFile, true);
avatarFilename = aiMeta->getAvatarFilename();
sprintf(deckFileSmall, "ai_baka_deck%i", deckid);
@@ -329,7 +329,7 @@ AIPlayer * AIPlayerFactory::createAIPlayerTest(GameObserver *observer, MTGAllCar
if ( opponent )
{
bool isOpponentAI = opponent->isAI() == 1;
DeckMetaData *meta = DeckManager::GetInstance()->getDeckMetaDataByFilename( opponent->deckFile, isOpponentAI);
DeckMetaData *meta = observer->getDeckManager()->getDeckMetaDataByFilename( opponent->deckFile, isOpponentAI);
if ( meta->getVictoryPercentage() >= 65)
deckSetting = HARD;
}

View File

@@ -1188,7 +1188,7 @@ int AIPlayerBaka::createAbilityTargets(MTGAbility * a, MTGCardInstance * c, Rank
vector<Targetable*>realTargets;
if(a->getActionTc()->maxtargets != 1)
{
if(a->getActionTc()->targets.size() && a->getActionTc()->attemptsToFill > 4)
if(a->getActionTc()->getNbTargets() && a->getActionTc()->attemptsToFill > 4)
{
a->getActionTc()->done = true;
return 0;

View File

@@ -178,7 +178,7 @@ void ActionLayer::Update(float dt)
without this, the game locks into a freeze state while you try to select the targets and dont have enough to
fill the maxtargets list.
*/
if(int(ae->getActionTc()->targets.size()) == countTargets-1)
if(int(ae->getActionTc()->getNbTargets()) == countTargets-1)
ae->getActionTc()->done = true;
}
}
@@ -192,7 +192,7 @@ void ActionLayer::Render()
abilitiesMenu->Render();
return;
}
currentActionCard = NULL;
for (size_t i = 0; i < mObjects.size(); i++)
{
if (mObjects[i] != NULL)
@@ -290,6 +290,29 @@ int ActionLayer::reactToTargetClick(Targetable * card)
return result;
}
bool ActionLayer::getMenuIdFromCardAbility(MTGCardInstance *card, MTGAbility *ability, int& menuId)
{
int ctr = 0;
for (size_t i = 0; i < mObjects.size(); i++)
{
ActionElement * currentAction = (ActionElement *) mObjects[i];
if (currentAction->isReactingToClick(card))
{
if(currentAction == ability) {
menuId = ctr;
}
ctr++;
}
}
// ability not working with card or only one ability possible
if(ctr == 0 || ctr == 1)
return false;
else
// several abilities working with card, menuId set
return true;
}
//TODO Simplify with only object !!!
int ActionLayer::isReactingToClick(MTGCardInstance * card)
{
@@ -422,11 +445,13 @@ void ActionLayer::ButtonPressed(int controllerid, int controlid)
ActionElement * currentAction = (ActionElement *) mObjects[controlid];
currentAction->reactToTargetClick(menuObject);
menuObject = 0;
currentActionCard = NULL;
}
else if (controlid == kCancelMenuID)
{
observer->mLayers->stackLayer()->endOfInterruption(false);
menuObject = 0;
currentActionCard = NULL;
}
else
{
@@ -462,6 +487,7 @@ void ActionLayer::ButtonPressedOnMultipleChoice(int choice)
observer->mLayers->stackLayer()->endOfInterruption(false);
}
menuObject = 0;
currentActionCard = NULL;
}
ActionLayer::ActionLayer(GameObserver *observer)

View File

@@ -216,8 +216,12 @@ Interruptible(observer, id), tc(tc), cost(_cost), payResult(payResult)
_source->backupTargets.clear();
if (tc)
{
for(size_t i = 0;i < tc->targets.size();i++)
_source->backupTargets.push_back(tc->targets[i]);
Targetable* t = NULL;
for(size_t i = 0;i < tc->getNbTargets();i++)
{
t = tc->getNextTarget(t);
_source->backupTargets.push_back(t);
}
}
// fill information on how the card came into this zone. Right now the quickest way is to do it here, based on how the mana was paid...
@@ -356,7 +360,7 @@ int Spell::getNbTargets()
{
if (!tc)
return 0;
return (int) (tc->targets.size());
return (int) (tc->getNbTargets());
}
void Spell::Render()

View File

@@ -206,7 +206,6 @@ StatsWrapper * DeckManager::getExtendedDeckStats( DeckMetaData *selectedDeck, MT
DeckManager * DeckManager::mInstance = NULL;
bool DeckManager::instanceFlag = false;
void DeckManager::EndInstance()
{
@@ -215,10 +214,9 @@ void DeckManager::EndInstance()
DeckManager* DeckManager::GetInstance()
{
if (!instanceFlag)
if (!mInstance)
{
mInstance = NEW DeckManager();
instanceFlag = true;
}
return mInstance;
@@ -230,7 +228,7 @@ int DeckManager::getDifficultyRating(Player *statsPlayer, Player *player)
{
if(player->deckFile != "")
{
DeckMetaData *meta = DeckManager::GetInstance()->getDeckMetaDataByFilename(player->deckFile, (player->isAI() == 1) );
DeckMetaData *meta = getDeckMetaDataByFilename(player->deckFile, (player->isAI() == 1) );
return meta->getDifficulty();
}
else
@@ -239,23 +237,22 @@ int DeckManager::getDifficultyRating(Player *statsPlayer, Player *player)
DeckManager::~DeckManager()
{
instanceFlag = false;
map<string, StatsWrapper *>::iterator it;
vector<DeckMetaData *>::iterator metaDataIter;
for (it = mInstance->aiDeckStatsMap.begin(); it != mInstance->aiDeckStatsMap.end(); it++){
for (it = aiDeckStatsMap.begin(); it != aiDeckStatsMap.end(); it++){
SAFE_DELETE(it->second);
}
for (it = mInstance->playerDeckStatsMap.begin(); it != mInstance->playerDeckStatsMap.end(); it++){
for (it = playerDeckStatsMap.begin(); it != playerDeckStatsMap.end(); it++){
SAFE_DELETE(it->second);
}
for( metaDataIter = mInstance->aiDeckOrderList.begin(); metaDataIter != mInstance->aiDeckOrderList.end(); ++metaDataIter)
for( metaDataIter = aiDeckOrderList.begin(); metaDataIter != aiDeckOrderList.end(); ++metaDataIter)
{
SAFE_DELETE( *metaDataIter );
}
for( metaDataIter = mInstance->playerDeckOrderList.begin(); metaDataIter != mInstance->playerDeckOrderList.end(); ++metaDataIter)
for( metaDataIter = playerDeckOrderList.begin(); metaDataIter != playerDeckOrderList.end(); ++metaDataIter)
{
SAFE_DELETE( *metaDataIter );
}

View File

@@ -19,7 +19,7 @@ void DuelLayers::init(GameObserver* go)
mCardSelector = NEW CardSelector(go, this);
//1 Action Layer
action = NEW ActionLayer(go);
action->Add(NEW MTGGamePhase(go, action->getMaxId())); //Phases handler
action->Add(phaseHandler = NEW MTGGamePhase(go, action->getMaxId())); //Phases handler
action->Add(NEW OtherAbilitiesEventReceiver(go, -1)); //autohand, etc... handler
//Other display elements
action->Add(NEW HUDDisplay(go, -1));

View File

@@ -13,6 +13,7 @@
#include "AIPlayerBaka.h"
#include "MTGRules.h"
#include "Trash.h"
#include "DeckManager.h"
#ifdef TESTSUITE
#include "TestSuiteAI.h"
#endif
@@ -69,6 +70,8 @@ GameObserver::~GameObserver()
ExtraRules = 0;
LOG("==GameObserver Destroyed==");
SAFE_DELETE(mTrash);
SAFE_DELETE(mDeckManager);
}
GameObserver::GameObserver(WResourceManager *output, JGE* input)
@@ -99,6 +102,7 @@ GameObserver::GameObserver(WResourceManager *output, JGE* input)
mLoading = false;
mLayers = NULL;
mTrash = new Trash();
mDeckManager = new DeckManager();
}
int GameObserver::getCurrentGamePhase()
@@ -475,6 +479,16 @@ bool GameObserver::operator==(const GameObserver& aGame)
return (error == 0);
}
void GameObserver::dumpAssert(bool val)
{
if(!val)
{
cerr << *this << endl;
assert(0);
}
}
void GameObserver::Update(float dt)
{
/*******************/
@@ -489,7 +503,7 @@ void GameObserver::Update(float dt)
oldGame = new GameObserver();
oldGame->mRules = mRules;
oldGame->load(stream.str());
assert(*this == *oldGame);
DumpAssert(*this == *oldGame);
}
#endif // ACTION_LOGGING_TESTING
@@ -526,7 +540,7 @@ void GameObserver::Update(float dt)
//Handles game state based effects
void GameObserver::gameStateBasedEffects()
{
if(getCurrentTargetChooser() && int(getCurrentTargetChooser()->targets.size()) == getCurrentTargetChooser()->maxtargets)
if(getCurrentTargetChooser() && int(getCurrentTargetChooser()->getNbTargets()) == getCurrentTargetChooser()->maxtargets)
getCurrentTargetChooser()->done = true;
if (mLayers->stackLayer()->count(0, NOT_RESOLVED) != 0)
return;
@@ -993,7 +1007,7 @@ void GameObserver::ButtonPressed(PlayGuiObject * target)
}
else if (dynamic_cast<GuiPhaseBar*>(target))
{
MTGGamePhase::GetInstance()->NextGamePhase();
mLayers->getPhaseHandler()->NextGamePhase();
}
}
@@ -1042,9 +1056,20 @@ bool GameObserver::WaitForExtraPayment(MTGCardInstance * card)
int GameObserver::cardClick(MTGCardInstance * card, MTGAbility *ability)
{
MTGGameZone* zone = card->currentZone;
size_t index = card->currentZone->getIndex(card);
size_t index = 0;
if(zone)
index = zone->getIndex(card);
int choice;
bool logChoice = mLayers->actionLayer()->getMenuIdFromCardAbility(card, ability, choice);
int result = ability->reactToClick(card);
logAction(card, zone, index, result);
if(logChoice) {
stringstream stream;
stream << "choice " << choice;
logAction(currentActionPlayer, stream.str());
}
return result;
}
@@ -1089,7 +1114,7 @@ int GameObserver::cardClick(MTGCardInstance * card, Targetable * object)
if (card == cardWaitingForTargets)
{
int _result = targetChooser->ForceTargetListReady();
if(targetChooser->targetMin && int(targetChooser->targets.size()) < targetChooser->maxtargets)
if(targetChooser->targetMin && int(targetChooser->getNbTargets()) < targetChooser->maxtargets)
_result = 0;
if (_result)
{
@@ -1548,7 +1573,7 @@ bool GameObserver::processActions(bool undo)
size_t begin = s.find("[")+1;
size_t size = s.find("]")-begin;
size_t index = atoi(s.substr(begin, size).c_str());
assert(index < zone->cards.size());
dumpAssert(index < zone->cards.size());
cardClick(zone->cards[index], zone->cards[index]);
} else if (s.find("yes") != string::npos) {
mLayers->stackLayer()->setIsInterrupting(p);
@@ -1571,20 +1596,20 @@ bool GameObserver::processActions(bool undo)
// that would allow the AI to use it as well.
shuffleLibrary(p);
} else {
assert(0);
dumpAssert(0);
}
size_t nb = actionsList.size();
for (int i = 0; i<3; i++)
for (int i = 0; i<5; i++)
{
// let's fake an update
Update(counter);
counter += 1.000f;
}
assert(actionsList.back() == *loadingite);
assert(nb == actionsList.size());
assert(cmdIndex == (actionsList.size()-1));
dumpAssert(actionsList.back() == *loadingite);
dumpAssert(nb == actionsList.size());
dumpAssert(cmdIndex == (actionsList.size()-1));
}
mLoading = false;
@@ -1618,7 +1643,7 @@ void GameObserver::logAction(const string& s)
if(mLoading)
{
string toCheck = *loadingite;
assert(toCheck == s);
dumpAssert(toCheck == s);
}
actionsList.push_back(s);
};
@@ -1645,8 +1670,10 @@ void GameObserver::createPlayer(const string& playerMode)
{
case Player::MODE_AI:
AIPlayerFactory playerCreator;
// FIXME: gonna break in AI vs AI mode
players.push_back(playerCreator.createAIPlayer(this, MTGCollection(), players[0]));
if(players.size())
players.push_back(playerCreator.createAIPlayer(this, MTGCollection(), players[0]));
else
players.push_back(playerCreator.createAIPlayer(this, MTGCollection(), 0));
break;
case Player::MODE_HUMAN:
players.push_back(new HumanPlayer(this, "", ""));

View File

@@ -284,12 +284,28 @@ void GameStateDuel::ThreadProc(void* inParam)
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_TESTSUITE);
observer.loadPlayer(1, PLAYER_TYPE_TESTSUITE);
observer.startGame(instance->mParent->gameType, instance->mParent->rules);
while(!observer.gameOver)
while(!observer.gameOver) {
if(observer.turn == oldTurn && observer.currentGamePhase == oldPhase) {
stagnationCounter++;
} else {
stagnationCounter = 0;
oldTurn = observer.turn;
oldPhase = observer.currentGamePhase;
}
if(stagnationCounter >= 1000)
{
observer.dumpAssert(false);
}
observer.Update(counter++);
}
instance->handleResults(&observer);
}
@@ -441,22 +457,25 @@ void GameStateDuel::Update(float dt)
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;
#ifdef QT_CONFIG
thread_count = QThread::idealThreadCount();
#endif
for(size_t i = 0; i < (thread_count-1); i++)
mWorkerThread.push_back(boost::thread(ThreadProc, this));
}
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();
#endif
for(size_t i = 0; i < (thread_count-1); i++)
mWorkerThread.push_back(boost::thread(ThreadProc, this));
}
}
#endif
if (mParent->players[0] == PLAYER_TYPE_CPU && mParent->players[1] == PLAYER_TYPE_CPU)
{
@@ -566,6 +585,7 @@ void GameStateDuel::Render()
if (game && totalTestGames)
{
char buf[4096];
int currentTime = JGEGetTime();
if (totalTestGames < 2.5 * totalAIDecks)
{
@@ -580,7 +600,8 @@ void GameStateDuel::Render()
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", testPlayer2Victories, totalTestGames);
sprintf(buf, "Victories Player 2/total Games: %i/%i - Games/second: %f",
testPlayer2Victories, totalTestGames, (float)(1000*totalTestGames)/(currentTime - startTime));
mFont->DrawString(buf,0,SCREEN_HEIGHT/2);
}
#endif

View File

@@ -303,6 +303,7 @@ bool remove_dead(ManaIcon* m)
void GuiMana::Update(float dt)
{
if(observer->getResourceManager())
{
float shift = 0;
for (vector<ManaIcon*>::iterator it = manas.begin(); it != manas.end(); ++it)

View File

@@ -2834,7 +2834,7 @@ int AbilityFactory::magicText(int id, Spell * spell, MTGCardInstance * card, int
a->canBeInterrupted = false;
}
bool moreThanOneTarget = spell && spell->tc && spell->tc->targets.size() > 1;
bool moreThanOneTarget = spell && spell->tc && spell->tc->getNbTargets() > 1;
if(moreThanOneTarget)
a->target = spell->getNextTarget();
@@ -2850,7 +2850,7 @@ int AbilityFactory::magicText(int id, Spell * spell, MTGCardInstance * card, int
}
else
{
if(!aMay || (aMay && a->target == spell->tc->targets[0]))
if(!aMay || (aMay && a->target == spell->tc->getNextTarget(0)))
{
MTGAbility * mClone = a->clone();
mClone->addToGame();
@@ -3990,7 +3990,7 @@ int TargetAbility::resolve()
t = tc->getNextTarget(t);
ability->target = t;
}
tc->targets.clear();
tc->initTargets();
return 1;
}
else
@@ -4002,7 +4002,7 @@ int TargetAbility::resolve()
t = tc->getNextTarget(t);
ability->target = t;
}
tc->targets.clear();
tc->initTargets();
return 1;
}
}

View File

@@ -3,8 +3,6 @@
#include "MTGGamePhase.h"
#include "GuiPhaseBar.h"
MTGGamePhase* MTGGamePhase::instance = 0;
MTGGamePhase::MTGGamePhase(GameObserver* g, int id) :
ActionElement(id), observer(g)
{
@@ -12,7 +10,6 @@ MTGGamePhase::MTGGamePhase(GameObserver* g, int id) :
currentState = -1;
mFont = WResourceManager::Instance()->GetWFont(Fonts::MAIN_FONT);
mFont->SetBase(0); // using 2nd font
instance = this;
}
void MTGGamePhase::Update(float dt)

View File

@@ -268,7 +268,7 @@ bool Player::parseLine(const string& s)
if ( opponent() )
{
bool isOpponentAI = opponent()->isAI() == 1;
DeckMetaData *meta = DeckManager::GetInstance()->getDeckMetaDataByFilename( opponent()->deckFile, isOpponentAI);
DeckMetaData *meta = observer->getDeckManager()->getDeckMetaDataByFilename( opponent()->deckFile, isOpponentAI);
if ( meta && meta->getVictoryPercentage() >= 65)
deckSetting = HARD;
}

View File

@@ -163,7 +163,7 @@ void Rules::addExtraRules(GameObserver* g)
#endif //NETWORK_SUPPORT
)//keep this out of momir and other game modes.
{
difficultyRating = DeckManager::getDifficultyRating(g->players[0], g->players[1]);
difficultyRating = g->getDeckManager()->getDifficultyRating(g->players[0], g->players[1]);
}
if (a)