diff --git a/projects/mtg/Android/jni/Android.mk b/projects/mtg/Android/jni/Android.mk index 996b008bd..d160eb345 100644 --- a/projects/mtg/Android/jni/Android.mk +++ b/projects/mtg/Android/jni/Android.mk @@ -30,6 +30,7 @@ LOCAL_SRC_FILES := $(SDL_PATH)/src/main/android/SDL_android_main.cpp \ $(MTG_PATH)/src/ActionElement.cpp \ $(MTG_PATH)/src/ActionLayer.cpp \ $(MTG_PATH)/src/ActionStack.cpp \ + $(MTG_PATH)/src/AIHints.cpp \ $(MTG_PATH)/src/AIMomirPlayer.cpp \ $(MTG_PATH)/src/AIPlayer.cpp \ $(MTG_PATH)/src/AIStats.cpp \ diff --git a/projects/mtg/Makefile b/projects/mtg/Makefile index d027502c6..b2ca186fc 100644 --- a/projects/mtg/Makefile +++ b/projects/mtg/Makefile @@ -1,4 +1,4 @@ -OBJS = objs/ActionElement.o objs/ActionLayer.o objs/ActionStack.o objs/AIMomirPlayer.o objs/AIPlayer.o objs/AIStats.o objs/AllAbilities.o objs/CardGui.o objs/CardDescriptor.o objs/CardDisplay.o objs/CardEffect.o objs/CardPrimitive.o objs/CardSelector.o objs/CardSelectorSingleton.o objs/Counters.o objs/Credits.o objs/Damage.o objs/DamagerDamaged.o objs/DeckDataWrapper.o objs/DeckEditorMenu.o objs/DeckMenu.o objs/DeckMenuItem.o objs/DeckMetaData.o objs/DeckStats.o objs/DuelLayers.o objs/Effects.o objs/ExtraCost.o objs/GameApp.o objs/GameLauncher.o objs/GameObserver.o objs/GameOptions.o objs/GameState.o objs/GameStateAwards.o objs/GameStateDeckViewer.o objs/GameStateDuel.o objs/DeckManager.o objs/GameStateMenu.o objs/GameStateOptions.o objs/GameStateShop.o objs/GameStateStory.o objs/GameStateTransitions.o objs/GuiAvatars.o objs/GuiBackground.o objs/GuiCardsController.o objs/GuiCombat.o objs/GuiFrame.o objs/GuiHand.o objs/GuiLayers.o objs/GuiMana.o objs/GuiPhaseBar.o objs/GuiPlay.o objs/GuiStatic.o objs/ManaCost.o objs/ManaCostHybrid.o objs/MenuItem.o objs/ModRules.o objs/MTGAbility.o objs/MTGCardInstance.o objs/MTGCard.o objs/MTGDeck.o objs/MTGDefinitions.o objs/MTGGamePhase.o objs/MTGGameZones.o objs/MTGPack.o objs/MTGRules.o objs/Navigator.o objs/ObjectAnalytics.o objs/OptionItem.o objs/PhaseRing.o objs/Player.o objs/PlayerData.o objs/PlayGuiObjectController.o objs/PlayGuiObject.o objs/PlayRestrictions.o objs/Pos.o objs/PrecompiledHeader.o objs/PriceList.o objs/ReplacementEffects.o objs/Rules.o objs/SimpleMenu.o objs/SimpleMenuItem.o objs/SimplePad.o objs/SimplePopup.o objs/StoryFlow.o objs/StyleManager.o objs/Subtypes.o objs/TargetChooser.o objs/TargetsList.o objs/TextScroller.o objs/ThisDescriptor.o objs/Token.o objs/Translate.o objs/TranslateKeys.o objs/Trash.o objs/utils.o objs/WEvent.o objs/WResourceManager.o objs/WCachedResource.o objs/WDataSrc.o objs/WGui.o objs/WFilter.o objs/Tasks.o objs/WFont.o +OBJS = objs/ActionElement.o objs/ActionLayer.o objs/ActionStack.o objs/AIHints.o objs/AIMomirPlayer.o objs/AIPlayer.o objs/AIStats.o objs/AllAbilities.o objs/CardGui.o objs/CardDescriptor.o objs/CardDisplay.o objs/CardEffect.o objs/CardPrimitive.o objs/CardSelector.o objs/CardSelectorSingleton.o objs/Counters.o objs/Credits.o objs/Damage.o objs/DamagerDamaged.o objs/DeckDataWrapper.o objs/DeckEditorMenu.o objs/DeckMenu.o objs/DeckMenuItem.o objs/DeckMetaData.o objs/DeckStats.o objs/DuelLayers.o objs/Effects.o objs/ExtraCost.o objs/GameApp.o objs/GameLauncher.o objs/GameObserver.o objs/GameOptions.o objs/GameState.o objs/GameStateAwards.o objs/GameStateDeckViewer.o objs/GameStateDuel.o objs/DeckManager.o objs/GameStateMenu.o objs/GameStateOptions.o objs/GameStateShop.o objs/GameStateStory.o objs/GameStateTransitions.o objs/GuiAvatars.o objs/GuiBackground.o objs/GuiCardsController.o objs/GuiCombat.o objs/GuiFrame.o objs/GuiHand.o objs/GuiLayers.o objs/GuiMana.o objs/GuiPhaseBar.o objs/GuiPlay.o objs/GuiStatic.o objs/ManaCost.o objs/ManaCostHybrid.o objs/MenuItem.o objs/ModRules.o objs/MTGAbility.o objs/MTGCardInstance.o objs/MTGCard.o objs/MTGDeck.o objs/MTGDefinitions.o objs/MTGGamePhase.o objs/MTGGameZones.o objs/MTGPack.o objs/MTGRules.o objs/Navigator.o objs/ObjectAnalytics.o objs/OptionItem.o objs/PhaseRing.o objs/Player.o objs/PlayerData.o objs/PlayGuiObjectController.o objs/PlayGuiObject.o objs/PlayRestrictions.o objs/Pos.o objs/PrecompiledHeader.o objs/PriceList.o objs/ReplacementEffects.o objs/Rules.o objs/SimpleMenu.o objs/SimpleMenuItem.o objs/SimplePad.o objs/SimplePopup.o objs/StoryFlow.o objs/StyleManager.o objs/Subtypes.o objs/TargetChooser.o objs/TargetsList.o objs/TextScroller.o objs/ThisDescriptor.o objs/Token.o objs/Translate.o objs/TranslateKeys.o objs/Trash.o objs/utils.o objs/WEvent.o objs/WResourceManager.o objs/WCachedResource.o objs/WDataSrc.o objs/WGui.o objs/WFilter.o objs/Tasks.o objs/WFont.o DEPS = $(patsubst objs/%.o, deps/%.d, $(OBJS)) RESULT = $(shell psp-config --psp-prefix 2> Makefile.cache) diff --git a/projects/mtg/include/AIHints.h b/projects/mtg/include/AIHints.h new file mode 100644 index 000000000..6d3a764f6 --- /dev/null +++ b/projects/mtg/include/AIHints.h @@ -0,0 +1,43 @@ +#ifndef _AIHINTS_H_ +#define _AIHINTS_H_ + +#include +#include +using std::string; +using std::vector; + +#include "AIPlayer.h" + +class ManaCost; +class MTGAbility; + +class AIHint +{ +public: + string mCondition; + string mAction; + int mSourceId; + AIHint(string line); +}; + + +class AIHints +{ +protected: + AIPlayer * mPlayer; + vector hints; + AIHint * getByCondition (string condition); + AIAction * findAbilityRecursive(AIHint * hint, ManaCost * potentialMana); + vector findAbilities(AIHint * hint); + RankingContainer findActions(AIHint * hint); + string constraintsNotFulfilled(AIAction * a, AIHint * hint, ManaCost * potentialMana); + bool findSource(int sourceId); + bool abilityMatches(MTGAbility * a, AIHint * hint); +public: + AIHints (AIPlayer * player); + AIAction * suggestAbility(ManaCost * potentialMana); + void add(string line); + ~AIHints(); +}; + +#endif \ No newline at end of file diff --git a/projects/mtg/include/AIPlayer.h b/projects/mtg/include/AIPlayer.h index 487781e42..885ebf83a 100644 --- a/projects/mtg/include/AIPlayer.h +++ b/projects/mtg/include/AIPlayer.h @@ -20,6 +20,7 @@ using std::queue; class AIStats; +class AIHints; class AIAction { @@ -72,6 +73,7 @@ class AIPlayer: public Player{ protected: //Variables used by Test suite MTGCardInstance * nextCardToPlay; + AIHints * hints; queue clickstream; bool tapLandsForMana(ManaCost * cost, MTGCardInstance * card = NULL); int orderBlockers(); @@ -87,6 +89,9 @@ protected: // returns 1 if the AI algorithm supports a given cost (ex:simple mana cost), 0 otherwise (ex: cost involves Sacrificing a target) int CanHandleCost(ManaCost * cost); + //Tries to play an ability recommended by the deck creator + int selectHintAbility(); + public: AIStats * stats; int agressivity; diff --git a/projects/mtg/include/MTGDeck.h b/projects/mtg/include/MTGDeck.h index 5b06687cd..98592542e 100644 --- a/projects/mtg/include/MTGDeck.h +++ b/projects/mtg/include/MTGDeck.h @@ -156,6 +156,8 @@ public: map cards; string meta_desc; string meta_name; + vector meta_AIHints; + int meta_id; int totalCards(); int totalPrice(); diff --git a/projects/mtg/include/Player.h b/projects/mtg/include/Player.h index 0ec320a65..4fa974570 100644 --- a/projects/mtg/include/Player.h +++ b/projects/mtg/include/Player.h @@ -30,6 +30,7 @@ public: bool nomaxhandsize; bool isPoisoned; MTGPlayerCards * game; + MTGDeck * mDeck; string deckFile; string deckFileSmall; string deckName; diff --git a/projects/mtg/src/AIHints.cpp b/projects/mtg/src/AIHints.cpp new file mode 100644 index 000000000..5ca268d81 --- /dev/null +++ b/projects/mtg/src/AIHints.cpp @@ -0,0 +1,254 @@ +#include "PrecompiledHeader.h" + +#include "AIHints.h" +#include "AIPlayer.h" +#include "utils.h" +#include "AllAbilities.h" + +#include + +AIHint::AIHint(string _line) +{ + string line = _line; + if (!line.length()) + { + DebugTrace("AIHINTS: line is empty"); + return; + } + std::transform(line.begin(), line.end(), line.begin(), ::tolower); + vector parameters = split(line,':'); + mCondition = (parameters.size() == 1)? "" : parameters[0]; + string action = parameters[parameters.size() - 1]; + + vector splitAction = parseBetween(action, "sourceid(", ")"); + if (splitAction.size()) + { + mAction = splitAction[0]; + mSourceId = atoi(splitAction[1].c_str()); + } + else + { + mAction = action; + mSourceId = 0; + } +} + +AIHints::AIHints(AIPlayer * player): mPlayer(player) +{ +} + +void AIHints::add(string line) +{ + hints.push_back(NEW AIHint(line)); +} + +AIHints::~AIHints() +{ + for (size_t i = 0; i < hints.size(); ++i) + SAFE_DELETE(hints[i]); + hints.clear(); +} + +AIHint * AIHints::getByCondition (string condition) +{ + if (!condition.size()) + return NULL; + + for (size_t i = 0; i < hints.size(); ++i) + { + if (hints[i]->mCondition.compare(condition) == 0) + return hints[i]; + } + return NULL; +} + +//return true if a given ability matches a hint's description +//Eventually this will look awfully similar to the parser...any way to merge them somehow ? +bool AIHints::abilityMatches(MTGAbility * ability, AIHint * hint) +{ + string s = hint->mAction; + + MTGAbility * a = AbilityFactory::getCoreAbility(ability); + + //Here we want to check that the card reacting to the MTGAbility is the one mentioned in the hint, + // to avoid mistaking the MTGAbility with a similar one. + //Ideally we would find all cards with this ID, and see if the ability reacts to a click on one of these cards. + // This is the poor man's version, based on the fact that most cards are the source of their own abilities + if (hint->mSourceId && ((!a->source) || a->source->getMTGId() != hint->mSourceId)) + return false; + + if ( AACounter * counterAbility = dynamic_cast (a) ) + { + vector splitCounter = parseBetween(s, "counter(", ")"); + if (!splitCounter.size()) + return false; + + string counterstring = counterAbility->name; + std::transform(counterstring.begin(), counterstring.end(), counterstring.begin(), ::tolower); + return (splitCounter[1].compare(counterstring) == 0); + } + + if ( ATokenCreator * tokenAbility = dynamic_cast (a) ) + { + vector splitToken = parseBetween(s, "token(", ")"); + if (!splitToken.size()) + return false; + return (tokenAbility->tokenId && tokenAbility->tokenId == atoi(splitToken[1].c_str())); + } + + return false; +} + +//Finds all mtgAbility matching the Hint description +// For now we limit findings +vector AIHints::findAbilities(AIHint * hint) +{ + std::vector elems; + ActionLayer * al = GameObserver::GetInstance()->mLayers->actionLayer(); + + for (int i = 1; i < al->mCount; i++) //0 is not a mtgability...hackish + { + MTGAbility * a = ((MTGAbility *) al->mObjects[i]); + if (abilityMatches(a, hint)) + elems.push_back(a); + } + return elems; + +} + +//Finds a mtgAbility matching the Hint description, and returns a valid AIAction matching this mtgability +RankingContainer AIHints::findActions(AIHint * hint) +{ + RankingContainer ranking; + + vector abilities = findAbilities(hint); + + for (size_t i = 0; i < abilities.size(); ++i) + { + MTGAbility * a = abilities[i]; + + for (int j = 0; j < mPlayer->game->inPlay->nb_cards; j++) + { + MTGCardInstance * card = mPlayer->game->inPlay->cards[j]; + if (a->isReactingToClick(card, a->cost)) + { + mPlayer->createAbilityTargets(a, card, ranking); //TODO make that function static? + break; //For performance... ? + } + } + } + + return ranking; +} + +//Returns true if a card with the given MTG ID exists +bool AIHints::findSource(int sourceId) +{ + for (int i = 0; i < mPlayer->game->inPlay->nb_cards; i++) + { + MTGCardInstance * c = mPlayer->game->inPlay->cards[i]; + if (c->getMTGId() == sourceId) + return true; + } + return false; +} + +string AIHints::constraintsNotFulfilled(AIAction * action, AIHint * hint, ManaCost * potentialMana) +{ + std::stringstream out; + + if (!action) + { + if (hint->mSourceId && !findSource(hint->mSourceId)) + { + out << "needcardinplay[" << hint->mSourceId << "]"; + return out.str(); + } + out << "needability[" << hint->mAction << "]"; + return out.str(); + } + + MTGAbility * a = action->ability; + if (!a) + return "not supported"; + + MTGCardInstance * card = action->click; + if (!card) + return "not supported"; + + //dummy test: would the ability work if we were sure to fulfill its mana requirements? + if (!a->isReactingToClick(card, a->cost)) + { + DebugTrace("This shouldn't happen, this AIAction doesn't seem like a good choice"); + return "not supported"; + } + + if (!a->isReactingToClick(card, potentialMana)) + { + //Not enough Mana, try to find which mana we should get in priority + ManaCost * diff = potentialMana->Diff(a->cost); + for (int i = 0; i < Constants::MTG_NB_COLORS; i++) + { + if(diff->getCost(i) < 0) + { + out << "needmana[" << Constants::MTGColorChars[i] << "]"; + if (Constants::MTGColorChars[i] == 'r') + DebugTrace("Got it"); + SAFE_DELETE(diff); + return out.str(); + } + + } + + //TODO, handle more cases where the cost cannot be paid + return "not supported, can't afford cost for some reason"; + } + + //No problem found, we believe this is a good action to perform + return ""; + +} + +AIAction * AIHints::findAbilityRecursive(AIHint * hint, ManaCost * potentialMana) +{ + RankingContainer ranking = findActions(hint); + + AIAction * a = NULL; + if (ranking.size()) + { + a = NEW AIAction(ranking.begin()->first); + } + + string s = constraintsNotFulfilled(a, hint, potentialMana); + if (s.size()) + { + SAFE_DELETE(a); + AIHint * nextHint = getByCondition(s); + DebugTrace("**I Need " << s << ", this can be provided by " << (nextHint ? nextHint->mAction : "NULL") << "\n\n"); + if (nextHint && nextHint != hint) + return findAbilityRecursive(nextHint, potentialMana); + return NULL; + } + + return a; + +} + +AIAction * AIHints::suggestAbility(ManaCost * potentialMana) +{ + for (size_t i = 0; i < hints.size(); ++i) + { + //Don't suggest abilities that require a condition, for now + if (hints[i]->mCondition.size()) + continue; + + AIAction * a = findAbilityRecursive(hints[i], potentialMana); + if (a) + { + DebugTrace("**I Decided that the best to fulfill " << hints[i]->mAction << " is to play " << a->ability->getMenuText() << "\n\n"); + return a; + } + + } + return NULL; +} \ No newline at end of file diff --git a/projects/mtg/src/AIPlayer.cpp b/projects/mtg/src/AIPlayer.cpp index 4fe4a5de5..e0d41af7a 100644 --- a/projects/mtg/src/AIPlayer.cpp +++ b/projects/mtg/src/AIPlayer.cpp @@ -9,6 +9,7 @@ #include "GuiCombat.h" #include "GameStateDuel.h" #include "DeckManager.h" +#include "AIHints.h" const char * const MTG_LAND_TEXTS[] = { "artifact", "forest", "island", "mountain", "swamp", "plains", "other lands" }; @@ -27,7 +28,7 @@ AIAction::AIAction(MTGCardInstance * c, MTGCardInstance * t) // if we're not in text mode, always get the thumb if (CardSelectorSingleton::Instance()->GetDrawMode() != DrawMode::kText) { - DebugTrace("Prefetching AI card going into play: " << c->getImageName()); + //DebugTrace("Prefetching AI card going into play: " << c->getImageName()); WResourceManager::Instance()->RetrieveCard(c, RETRIEVE_THUMB); // also cache the large image if we're using kNormal mode @@ -71,6 +72,15 @@ AIPlayer::AIPlayer(string file, string fileSmall, MTGDeck * deck) : agressivity = 50; forceBestAbilityUse = false; playMode = Player::MODE_AI; + + //Initialize "AIHints" system + hints = NULL; + if (mDeck && mDeck->meta_AIHints.size()) + { + hints = NEW AIHints(this); + for (size_t i = 0; i < mDeck->meta_AIHints.size(); ++i) + hints->add(mDeck->meta_AIHints[i]); + } } AIPlayer::~AIPlayer() @@ -86,6 +96,7 @@ AIPlayer::~AIPlayer() SAFE_DELETE(action); clickstream.pop(); } + SAFE_DELETE(hints); } MTGCardInstance * AIPlayer::chooseCard(TargetChooser * tc, MTGCardInstance * source, int random) { @@ -125,15 +136,12 @@ bool AIPlayer::tapLandsForMana(ManaCost * cost, MTGCardInstance * target) DebugTrace("Mana cost is NULL. "); return false; } - ManaCost * pMana = NULL; - if(!target) - pMana = getPotentialMana(); - else - pMana = getPotentialMana(target); + ManaCost * pMana = target ? getPotentialMana(target) : getPotentialMana(); + if(!pMana->canAfford(cost)) { - delete pMana; - return false; + delete pMana; + return false; } ManaCost * diff = pMana->Diff(cost); delete (pMana); @@ -670,7 +678,6 @@ int AIAction::getEfficiency() AADrawer * drawer = (AADrawer *)a; //adding this case since i played a few games where Ai litterally decided to mill himself to death. fastest and easiest win ever. //this should help a little, tho ultimately it will be decided later what the best course of action is. - efficiency = 0; //eff of drawing ability is calculated by base 20 + the amount of cards in library minus the amount of cards in hand times 7. //drawing is never going to return a hundred eff because later eff is multiplied by 1.3 if no cards in hand. efficiency = int(20 + p->game->library->nb_cards) - int(p->game->hand->nb_cards * 7); @@ -769,6 +776,32 @@ int AIPlayer::createAbilityTargets(MTGAbility * a, MTGCardInstance * c, RankingC return 1; } +int AIPlayer::selectHintAbility() +{ + if (!hints) + return 0; + + ManaCost * totalPotentialMana = getPotentialMana(); + + AIAction * action = hints->suggestAbility(totalPotentialMana); + if (action && ((WRand() % 100) < 95)) //95% chance + { + if (!clickstream.size()) + { + DebugTrace("AIPlayer:Using Activated ability"); + if (tapLandsForMana(action->ability->cost, action->click)) + { + clickstream.push(action); + SAFE_DELETE(totalPotentialMana); + return 1; + } + } + } + SAFE_DELETE(action); + SAFE_DELETE(totalPotentialMana); + return 0; +} + int AIPlayer::selectAbility() { static bool findingAbility = false; @@ -783,6 +816,15 @@ int AIPlayer::selectAbility() return 0; } findingAbility = true;//im looking now safely! + + + // Try Deck hints first + if (selectHintAbility()) + { + findingAbility = false;//ok to start looking again. + return 1; + } + RankingContainer ranking; list::iterator it; GameObserver * g = GameObserver::GetInstance(); @@ -826,6 +868,7 @@ int AIPlayer::selectAbility() } } } + findingAbility = false;//ok to start looking again. return 1; } @@ -864,16 +907,24 @@ int AIPlayer::chooseTarget(TargetChooser * _tc, Player * forceTarget,MTGCardInst int checkOnly = 0; if (tc) { - if(!Choosencard) - checkOnly = 1; + if(!Choosencard) + checkOnly = 1; } else { - tc = gameObs->getCurrentTargetChooser(); - + tc = gameObs->getCurrentTargetChooser(); } if (!tc) return 0; + + if (tc->source->controller() != this) + { + DebugTrace("AIPLAYER: Error, was asked to chose targets but I don't own the source of the targetController\n"); + return 0; + } + //Make sure we own the decision to choose the targets + assert(tc->source->controller() == this); + tc->initTargets(); //cleanup the targetchooser just in case. if (!(gameObs->currentlyActing() == this)) return 0; @@ -1091,14 +1142,27 @@ int AIPlayer::chooseBlockers() //kick the ai out of this function. map opponentsToughness; int opponentForce = getCreaturesInfo(opponent(), INFO_CREATURESPOWER); + + //Initialize the list of opponent's attacking cards toughness + CardDescriptor cdAttackers; + cdAttackers.init(); + cdAttackers.setType("Creature"); + MTGCardInstance * card = NULL; + while ((card = cdAttackers.nextmatch(opponent()->game->inPlay, card))) + { + if (card->isAttacker()) + opponentsToughness[card] = card->toughness; + } + + //A Descriptor to find untapped creatures in our game CardDescriptor cd; cd.init(); cd.setType("Creature"); cd.unsecureSetTapped(-1); - MTGCardInstance * card = NULL; + card = NULL; MTGAbility * a = g->mLayers->actionLayer()->getAbility(MTGAbility::MTG_BLOCK_RULE); - + // We first try to block the major threats, those that are marked in the Top 3 of our stats while ((card = cd.nextmatch(game->inPlay, card))) { g->mLayers->actionLayer()->reactToClick(a, card); @@ -1130,6 +1194,9 @@ int AIPlayer::chooseBlockers() } } } + + //If blocking one of the major threats is not enough to kill it, + // We change strategy, first we unassign its blockers that where assigned above card = NULL; while ((card = cd.nextmatch(game->inPlay, card))) { @@ -1141,6 +1208,8 @@ int AIPlayer::chooseBlockers() } } } + + //Assign the "free" potential blockers to attacking creatures that are not blocked enough card = NULL; while ((card = cd.nextmatch(game->inPlay, card))) { @@ -1158,8 +1227,7 @@ int AIPlayer::chooseBlockers() { MTGCardInstance * attacker = card->defenser; if (opponentsToughness[attacker] <= 0 || (card->toughness <= attacker->power && opponentForce * 2 < life - && !canFirstStrikeKill(card, attacker)) || attacker->nbOpponents() > 1 - || attacker->controller()->isAI()) + && !canFirstStrikeKill(card, attacker)) || attacker->nbOpponents() > 1) { g->mLayers->actionLayer()->reactToClick(a, card); } @@ -1200,9 +1268,7 @@ int AIPlayer::affectCombatDamages(CombatStep step) //TODO: Deprecate combatDamages int AIPlayer::combatDamages() { - //int result = 0; - GameObserver * gameObs = GameObserver::GetInstance(); - int currentGamePhase = gameObs->getCurrentGamePhase(); + int currentGamePhase = GameObserver::GetInstance()->getCurrentGamePhase(); if (currentGamePhase == Constants::MTG_PHASE_COMBATBLOCKERS) return orderBlockers(); @@ -1609,12 +1675,14 @@ int AIPlayerBaka::Act(float dt) return 0; } interruptIfICan(); + + //computeActions only when i have priority if (!(g->currentlyActing() == this)) { DebugTrace("Cannot interrupt"); return 0; } - if (clickstream.empty() && g->currentlyActing() == this)//computeActions only when i have priority + if (clickstream.empty()) computeActions(); if (clickstream.empty()) { diff --git a/projects/mtg/src/CardGui.cpp b/projects/mtg/src/CardGui.cpp index 2484c6563..7b3f89a1c 100644 --- a/projects/mtg/src/CardGui.cpp +++ b/projects/mtg/src/CardGui.cpp @@ -796,7 +796,7 @@ void CardGui::RenderBig(MTGCard* card, const Pos& pos) return; } - DebugTrace("Unable to fetch image: " << card->getImageName()); + //DebugTrace("Unable to fetch image: " << card->getImageName()); // If we come here, we do not have the picture. AlternateRender(card, pos); diff --git a/projects/mtg/src/MTGDeck.cpp b/projects/mtg/src/MTGDeck.cpp index 395edb676..e1cc6e21a 100644 --- a/projects/mtg/src/MTGDeck.cpp +++ b/projects/mtg/src/MTGDeck.cpp @@ -720,6 +720,12 @@ MTGDeck::MTGDeck(const char * config_file, MTGAllCards * _allcards, int meta_onl meta_desc.append(s.substr(found + 5)); continue; } + found = s.find("HINT:"); + if (found != string::npos) + { + meta_AIHints.push_back(s.substr(found + 5)); + continue; + } continue; } if (meta_only) break; @@ -874,7 +880,8 @@ int MTGDeck::add(MTGDeck * deck) int MTGDeck::add(int cardid) { - if (!database->getCardById(cardid)) return 0; + if (!database->getCardById(cardid)) + return 0; if (cards.find(cardid) == cards.end()) { cards[cardid] = 1; @@ -890,7 +897,8 @@ int MTGDeck::add(int cardid) int MTGDeck::add(MTGCard * card) { - if (!card) return 0; + if (!card) + return 0; return (add(card->getId())); } diff --git a/projects/mtg/src/Player.cpp b/projects/mtg/src/Player.cpp index c9334e2ea..63607df47 100644 --- a/projects/mtg/src/Player.cpp +++ b/projects/mtg/src/Player.cpp @@ -8,12 +8,8 @@ Player::Player(string file, string fileSmall, MTGDeck * deck) : Damageable(20) { - bool deleteDeckPlease = false; if(deck == NULL && file != "testsuite" && file != "remote") - { deck = NEW MTGDeck(file.c_str(), MTGCollection()); - deleteDeckPlease = true; - } game = NULL; deckFile = file; @@ -28,14 +24,11 @@ Damageable(20) playMode = MODE_HUMAN; if (deck != NULL) { - game = NEW MTGPlayerCards(deck); - game->setOwner(this); - deckName = deck->meta_name; - } - if(deleteDeckPlease) - { - SAFE_DELETE(deck); + game = NEW MTGPlayerCards(deck); + game->setOwner(this); + deckName = deck->meta_name; } + mDeck = deck; } /*Method to call at the end of a game, before all objects involved in the game are destroyed */ @@ -50,6 +43,7 @@ Player::~Player() SAFE_DELETE(game); WResourceManager::Instance()->Release(mAvatarTex); mAvatarTex = NULL; + SAFE_DELETE(mDeck); } void Player::loadAvatar(string file) diff --git a/projects/mtg/src/Rules.cpp b/projects/mtg/src/Rules.cpp index 1ce83e774..9a57e4dea 100644 --- a/projects/mtg/src/Rules.cpp +++ b/projects/mtg/src/Rules.cpp @@ -336,7 +336,6 @@ Player * Rules::loadPlayerMomir(int isAI) else player = NEW AIMomirPlayer(options.profileFile("momir.txt", "", true).c_str(), deckFileSmall, empty, tempDeck); - delete tempDeck; return player; } @@ -371,7 +370,6 @@ Player * Rules::loadPlayerRandom(int isAI, int mode) else player = NEW AIPlayerBaka(deckFile, deckFileSmall, "", tempDeck); - delete tempDeck; return player; } @@ -518,7 +516,8 @@ void Rules::postUpdateInit() if (postUpdateInitDone) return; for (int i = 0; i < 2; ++ i) - GameObserver::GetInstance()->players[i]->getManaPool()->copy(initState.playerData[i].manapool); + GameObserver::GetInstance()->players[i]->getManaPool()->add(initState.playerData[i].manapool); + // GameObserver::GetInstance()->players[i]->getManaPool()->copy(initState.playerData[i].manapool); postUpdateInitDone = true; } diff --git a/projects/mtg/src/WResourceManager.cpp b/projects/mtg/src/WResourceManager.cpp index 697013b92..83bd055d2 100644 --- a/projects/mtg/src/WResourceManager.cpp +++ b/projects/mtg/src/WResourceManager.cpp @@ -1178,7 +1178,7 @@ cacheItem* WCache::Get(int id, const string& filename, i if (!it->second) { mError = CACHE_ERROR_404; - DebugTrace("cache hit, no item??"); + //DebugTrace("cache hit, no item??"); //assert(false); } return it->second; //A hit, or maybe a miss. diff --git a/projects/mtg/template.vcxproj b/projects/mtg/template.vcxproj index ab4af142b..519f5bf71 100644 --- a/projects/mtg/template.vcxproj +++ b/projects/mtg/template.vcxproj @@ -301,6 +301,7 @@ + @@ -431,6 +432,7 @@ + diff --git a/projects/mtg/template.vcxproj.filters b/projects/mtg/template.vcxproj.filters index 25457ba1e..af1c60c7c 100644 --- a/projects/mtg/template.vcxproj.filters +++ b/projects/mtg/template.vcxproj.filters @@ -307,6 +307,9 @@ src + + src + @@ -636,6 +639,9 @@ inc + + inc +