From c50ea49e7451dacabc54117f5a9ea00411d58f87 Mon Sep 17 00:00:00 2001 From: "wagic.the.homebrew" Date: Sun, 16 Nov 2008 10:37:13 +0000 Subject: [PATCH] Erwan - Adding new icons from J - fixed a bug with Zombie Master (for real this time, I swear !) - The AI should play Wrath of god in a more "clever" way --- projects/mtg/bin/Res/graphics/menuicons.png | Bin 0 -> 27181 bytes projects/mtg/bin/Res/test/_tests.txt | 3 +- projects/mtg/bin/Res/test/zombie_master.txt | 24 + projects/mtg/include/AllAbilities.h | 3 +- projects/mtg/include/MTGAbility.h | 9 +- projects/mtg/src/AIPlayer.cpp | 43 +- projects/mtg/src/MTGAbility.cpp | 521 +++++++++++--------- projects/mtg/src/TestSuiteAI.cpp | 6 +- 8 files changed, 334 insertions(+), 275 deletions(-) create mode 100644 projects/mtg/bin/Res/graphics/menuicons.png create mode 100644 projects/mtg/bin/Res/test/zombie_master.txt diff --git a/projects/mtg/bin/Res/graphics/menuicons.png b/projects/mtg/bin/Res/graphics/menuicons.png new file mode 100644 index 0000000000000000000000000000000000000000..aec30e1c36d7d1d90b1ba3f0e2e8a3f94f0afc04 GIT binary patch literal 27181 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 literal 0 HcmV?d00001 diff --git a/projects/mtg/bin/Res/test/_tests.txt b/projects/mtg/bin/Res/test/_tests.txt index 1e6abccad..c2c8f6204 100644 --- a/projects/mtg/bin/Res/test/_tests.txt +++ b/projects/mtg/bin/Res/test/_tests.txt @@ -50,4 +50,5 @@ stasis.txt terror.txt volcanic_island.txt white_knight1.txt -wrath_of_god.txt \ No newline at end of file +wrath_of_god.txt +zombie_master.txt \ No newline at end of file diff --git a/projects/mtg/bin/Res/test/zombie_master.txt b/projects/mtg/bin/Res/test/zombie_master.txt new file mode 100644 index 000000000..09cc8e5da --- /dev/null +++ b/projects/mtg/bin/Res/test/zombie_master.txt @@ -0,0 +1,24 @@ +#Testing Zombie Master crash ? +[INIT] +COMBATATTACKERS +[PLAYER1] +inplay:1188,129693,135216 +[PLAYER2] +inplay:1299 +[DO] +129693 +1188 +next +1299 +next +next +129693 +[ASSERT] +COMBATEND +[PLAYER1] +inplay:135216,129693 +graveyard:1188 +[PLAYER2] +life:18 +inplay:1299 +[END] \ No newline at end of file diff --git a/projects/mtg/include/AllAbilities.h b/projects/mtg/include/AllAbilities.h index 14e6b34dc..17e3becd9 100644 --- a/projects/mtg/include/AllAbilities.h +++ b/projects/mtg/include/AllAbilities.h @@ -882,7 +882,8 @@ class ALord:public ListMaintainerAbility{ card->addToToughness(toughness); if (ability != -1) card->basicAbilities[ability] +=1; if (regenCost){ - AStandardRegenerate * regen = NEW AStandardRegenerate(0, card, card, regenCost); + ManaCost * _regenCost = NEW ManaCost(regenCost); + AStandardRegenerate * regen = NEW AStandardRegenerate(0, card, card, _regenCost); regenerations[card] = regen; game->addObserver(regen); } diff --git a/projects/mtg/include/MTGAbility.h b/projects/mtg/include/MTGAbility.h index ebb1096bc..ac0653396 100644 --- a/projects/mtg/include/MTGAbility.h +++ b/projects/mtg/include/MTGAbility.h @@ -22,10 +22,11 @@ using std::map; //Two stupid variables used to give a hint to the AI: // Should I cast a spell on an enemy or friendly unit ? -#define BAKA_EFFECT_GOOD 10 -#define BAKA_EFFECT_BAD 11 - +#define BAKA_EFFECT_GOOD 1 +#define BAKA_EFFECT_BAD -1 +#define BAKA_EFFECT_DONTKNOW 0 +#define COUNT_POWER 1 class MTGAbility: public ActionElement{ protected: @@ -183,6 +184,7 @@ class GenericTriggeredAbility:public TriggeredAbility{ /* Ability Factory */ class AbilityFactory{ private: + int countCards(TargetChooser * tc, Player * player = NULL, int option = 0); int destroyAllInPlay(TargetChooser * tc, int bury = 0); int putInPlayFromZone(MTGCardInstance * card, MTGGameZone * zone, Player * p); Trigger * parseTrigger(string magicText); @@ -195,3 +197,4 @@ class AbilityFactory{ #include "MTGCardInstance.h" #endif + diff --git a/projects/mtg/src/AIPlayer.cpp b/projects/mtg/src/AIPlayer.cpp index f56822432..22aa7e50e 100644 --- a/projects/mtg/src/AIPlayer.cpp +++ b/projects/mtg/src/AIPlayer.cpp @@ -76,31 +76,7 @@ void AIPlayer::tapLandsForMana(ManaCost * potentialMana, ManaCost * cost){ delete(diff); - /* - for (int i=MTG_NB_COLORS-1; i>= 0; i--){ - #if defined (WIN32) || defined (LINUX) - char buf[4096]; - sprintf(buf,"Testing %s \n" ,MTG_LAND_TEXTS[i]); - OutputDebugString(buf); - #endif - currentCost = cost->getCost(i); - while(currentCost){ - #if defined (WIN32) || defined (LINUX) - sprintf(buf,"Cost for %s is %i \n" ,MTG_LAND_TEXTS[i], currentCost); - OutputDebugString(buf); - #endif - MTGCardInstance * card = NULL; - while(currentCost && (card = cd.nextmatch(game->inPlay, card))){ - if (i==MTG_COLOR_ARTIFACT || card->hasSubtype(MTG_LAND_TEXTS[i]) ){ - currentCost--; - gameObs->cardClick(card); - } - } - } - } - - */ #if defined (WIN32) || defined (LINUX) OutputDebugString("ok land tapped"); #endif @@ -167,7 +143,7 @@ int AIPlayer::effectBadOrGood(MTGCardInstance * card){ int autoGuess = af->magicText(id,NULL,card); delete af; if (autoGuess) return autoGuess; - return BAKA_EFFECT_BAD; + return BAKA_EFFECT_DONTKNOW; } int AIPlayer::chooseTarget(TargetChooser * tc){ @@ -184,7 +160,7 @@ int AIPlayer::chooseTarget(TargetChooser * tc){ if (!(gameObs->currentlyActing() == this)) return 0; Player * target = this; int cardEffect = effectBadOrGood(tc->source); - if (cardEffect == BAKA_EFFECT_BAD){ + if (cardEffect != BAKA_EFFECT_GOOD){ target = this->opponent(); } @@ -464,9 +440,18 @@ MTGCardInstance * AIPlayerBaka::FindCardToPlay(ManaCost * potentialMana, const c TargetChooser * tc = tcf->createTargetChooser(card); delete tcf; if (tc){ - int hasTarget = (chooseTarget(tc)); - delete tc; - if (!hasTarget)continue; + int hasTarget = (chooseTarget(tc)); + delete tc; + if (!hasTarget)continue; + }else{ + int shouldPlayPercentage = 10; + int shouldPlay = effectBadOrGood(card); + if (shouldPlay == BAKA_EFFECT_GOOD){ + shouldPlayPercentage = 90; + }else if(BAKA_EFFECT_DONTKNOW == shouldPlay){ + shouldPlayPercentage = 70; + } + if (rand() % 100 > shouldPlayPercentage) continue; } nextCardToPlay = card; maxCost = currentCost; diff --git a/projects/mtg/src/MTGAbility.cpp b/projects/mtg/src/MTGAbility.cpp index 55dd8ec57..5d6aaf780 100644 --- a/projects/mtg/src/MTGAbility.cpp +++ b/projects/mtg/src/MTGAbility.cpp @@ -9,243 +9,288 @@ #include "../include/MTGDeck.h" -int AbilityFactory::destroyAllInPlay(TargetChooser * tc, int bury){ - tc->source = NULL; // This is to prevent protection from... as objects that destroy all do not actually target - GameObserver * game = GameObserver::GetInstance(); - for (int i = 0; i < 2 ; i++){ - for (int j = 0; j < game->players[i]->game->inPlay->nb_cards; j++){ - MTGCardInstance * current = game->players[i]->game->inPlay->cards[j]; - if (tc->canTarget(current)){ - if (bury){ - game->players[i]->game->putInGraveyard(current); - }else{ - game->mLayers->stackLayer()->addPutInGraveyard(current); - } - } - } - } - return 1; -} - - -int AbilityFactory::putInPlayFromZone(MTGCardInstance * card, MTGGameZone * zone, Player * p){ - Spell * spell = NEW Spell(card); - p->game->putInZone(card, zone, p->game->stack); - spell->resolve(); - delete spell; - return 1; -} - - -Trigger * AbilityFactory::parseTrigger(string magicText){ - size_t found = magicText.find("@"); - if (found == string::npos) return NULL; - - //Next Time... - found = magicText.find("next"); - if (found != string::npos){ - for (int i = 0; i < NB_MTG_PHASES; i++){ - found = magicText.find(MTGPhaseCodeNames[i]); - if (found != string::npos){ - return NEW TriggerNextPhase(i); - } - } - } - - return NULL; -} - -//Some basic functionalities that can be added automatically in the text file -/* - * Several objects are computed from the text string, and have a direct influence on what action we should take - * (direct impact on the game such as draw a card immediately, or create a new GameObserver and add it to the Abilities,etc..) - * These objects are: - * - trigger (if there is an "@" in the string, this is a triggered ability) - * - target (if there ie a "target(" in the string, then this is a TargetAbility) - * - doTap (a dirty way to know if tapping is included in the cost... - */ -int AbilityFactory::magicText(int id, Spell * spell, MTGCardInstance * card){ - int dryMode = 0; - if (!spell) dryMode = 1; - GameObserver * game = GameObserver::GetInstance(); - if (!card) card = spell->source; - MTGCardInstance * target = card->target; - if (!target) target = card; - string magicText = card->magicText; - if (card->alias && magicText.size() == 0){ - //An awful way to get access to the aliasedcard - magicText = GameObserver::GetInstance()->players[0]->game->collection->getCardById(card->alias)->magicText; - } - string s; - int size = magicText.size(); - if (size == 0) return 0; - unsigned int found; - int result = id; - - - while (magicText.size()){ - found = magicText.find("\n"); - if (found != string::npos){ - s = magicText.substr(0,found); - magicText = magicText.substr(found+1); - }else{ - s = magicText; - magicText = ""; - } -#if defined (WIN32) || defined (LINUX) - char buf[4096]; - sprintf(buf, "AUTO ACTION: %s\n", s.c_str()); - OutputDebugString(buf); -#endif - - TargetChooser * tc = NULL; - int doTap = 0; - string lordType = ""; - - Trigger * trigger = parseTrigger(s); - //Dirty way to remove the trigger text (could get in the way) - if (trigger){ - found = s.find(":"); - s = s.substr(found+1); - } - - //Tap in the cost ? - if (s.find("{t}") != string::npos) doTap = 1; - - //Target Abilities - found = s.find("target("); - if (found != string::npos){ - int end = s.find(")"); - string starget = s.substr(found + 7,end - found - 7); - TargetChooserFactory tcf; - tc = tcf.createTargetChooser(starget, card); - - } - - //Lord - found = s.find("lord("); - if (found != string::npos){ - if (dryMode) return BAKA_EFFECT_GOOD; - unsigned int end = s.find(")", found+5); - if (end != string::npos){ - lordType = s.substr(found+5,end-found-5).c_str(); - } - } - - //Champion. Very basic, needs to be improved ! - found = s.find("champion(name:"); - if (found != string::npos){ - if (dryMode) return BAKA_EFFECT_GOOD; - unsigned int end = s.find(")", found+14); - if (end != string::npos){ - string type = s.substr(found+14,end-found-14).c_str(); - game->addObserver(NEW APlagueRats(id,card,type.c_str())); - result++; - continue; - } - } - - //Untapper (Ley Druid...) - found = s.find("untap"); - if (found != string::npos){ - if (dryMode) return BAKA_EFFECT_GOOD; - ManaCost * cost = ManaCost::parseManaCost(s); - if (tc){ - game->addObserver(NEW AUntaper(id, card, cost, tc)); - }else{ - target->tapped = 0; - } - - result++; - continue; - } - - //Tapper (icy manipulator) - found = s.find("tap"); - if (found != string::npos){ - if (dryMode) return BAKA_EFFECT_GOOD; - ManaCost * cost = ManaCost::parseManaCost(s); - if (tc){ - game->addObserver(NEW ATapper(id, card, cost, tc)); - }else{ - target->tapped = 1; - } - - result++; - continue; - } - - //Regeneration - found = s.find("}:regenerate"); - if (found != string::npos){ - if (dryMode) return BAKA_EFFECT_GOOD; - ManaCost * cost = ManaCost::parseManaCost(s); - - if (lordType.size() > 0){ - game->addObserver(NEW ALord(id,card,lordType.c_str(),0,0,-1,cost)); - }else{ - - if (tc){ - //TODO - }else{ - game->addObserver(NEW AStandardRegenerate(id, card, target, cost)); - //TODO death ward ! - } - } - result++; - continue; - } - - //Bury - found = s.find("bury"); - if (found != string::npos){ - if (dryMode) return BAKA_EFFECT_BAD; - if (trigger){ - BuryEvent * action = NEW BuryEvent(); - game->addObserver(NEW GenericTriggeredAbility(id, card,trigger,action)); - }else{ - found = s.find("all("); - if (found != string::npos){ - int end = s.find(")"); - string starget = s.substr(found + 4,end - found - 4); - TargetChooserFactory tcf; - TargetChooser * targetAll = tcf.createTargetChooser(starget, card); - this->destroyAllInPlay(targetAll,1); - delete targetAll; - }else{ - if (tc){ - game->addObserver(NEW ABurier(id, card,tc)); - }else{ - target->controller()->game->putInGraveyard(target); - } - } - } - result++; - continue; - } - - //Destroy - found = s.find("destroy"); - if (found != string::npos){ - if (dryMode) return BAKA_EFFECT_BAD; //TODO compute according to nb in case of destroy all - found = s.find("all("); - if (found != string::npos){ - int end = s.find(")"); - string starget = s.substr(found + 4,end - found - 4); - TargetChooserFactory tcf; - TargetChooser * targetAll = tcf.createTargetChooser(starget, card); - this->destroyAllInPlay(targetAll); - delete targetAll; - }else{ - if (tc){ - game->addObserver(NEW ADestroyer(id, card,tc)); - }else{ - game->mLayers->stackLayer()->addPutInGraveyard(target); - } - } - result++; - continue; - } +int AbilityFactory::countCards(TargetChooser * tc, Player * player, int option){ + int result = 0; + GameObserver * game = GameObserver::GetInstance(); + for (int i = 0; i < 2 ; i++){ + if (player && player!= game->players[i]) continue; + for (int j = game->players[i]->game->inPlay->nb_cards-1; j >=0 ; j--){ + MTGCardInstance * current = game->players[i]->game->inPlay->cards[j]; + if (tc->canTarget(current)){ + switch (option){ + case COUNT_POWER: + result+= current->power; + break; + default: + result++; + break; + } + } + } + } + return result; +} + +int AbilityFactory::destroyAllInPlay(TargetChooser * tc, int bury){ + tc->source = NULL; // This is to prevent protection from... as objects that destroy all do not actually target + GameObserver * game = GameObserver::GetInstance(); + for (int i = 0; i < 2 ; i++){ + for (int j = game->players[i]->game->inPlay->nb_cards-1; j >=0 ; j--){ + MTGCardInstance * current = game->players[i]->game->inPlay->cards[j]; + if (tc->canTarget(current)){ + if (bury){ + game->players[i]->game->putInGraveyard(current); + }else{ + game->mLayers->stackLayer()->addPutInGraveyard(current); + } + } + } + } + return 1; +} + + +int AbilityFactory::putInPlayFromZone(MTGCardInstance * card, MTGGameZone * zone, Player * p){ + Spell * spell = NEW Spell(card); + p->game->putInZone(card, zone, p->game->stack); + spell->resolve(); + delete spell; + return 1; +} + + +Trigger * AbilityFactory::parseTrigger(string magicText){ + int found = magicText.find("@"); + if (found == string::npos) return NULL; + + //Next Time... + found = magicText.find("next"); + if (found != string::npos){ + for (int i = 0; i < NB_MTG_PHASES; i++){ + found = magicText.find(MTGPhaseCodeNames[i]); + if (found != string::npos){ + return NEW TriggerNextPhase(i); + } + } + } + + return NULL; +} + +//Some basic functionalities that can be added automatically in the text file +/* + * Several objects are computed from the text string, and have a direct influence on what action we should take + * (direct impact on the game such as draw a card immediately, or create a new GameObserver and add it to the Abilities,etc..) + * These objects are: + * - trigger (if there is an "@" in the string, this is a triggered ability) + * - target (if there ie a "target(" in the string, then this is a TargetAbility) + * - doTap (a dirty way to know if tapping is included in the cost... + */ +int AbilityFactory::magicText(int id, Spell * spell, MTGCardInstance * card){ + int dryMode = 0; + if (!spell) dryMode = 1; + GameObserver * game = GameObserver::GetInstance(); + if (!card) card = spell->source; + MTGCardInstance * target = card->target; + if (!target) target = card; + string magicText = card->magicText; + if (card->alias && magicText.size() == 0){ + //An awful way to get access to the aliasedcard + magicText = GameObserver::GetInstance()->players[0]->game->collection->getCardById(card->alias)->magicText; + } + string s; + int size = magicText.size(); + if (size == 0) return 0; + unsigned int found; + int result = id; + + + while (magicText.size()){ + found = magicText.find("\n"); + if (found != string::npos){ + s = magicText.substr(0,found); + magicText = magicText.substr(found+1); + }else{ + s = magicText; + magicText = ""; + } +#if defined (WIN32) || defined (LINUX) + char buf[4096]; + sprintf(buf, "AUTO ACTION: %s\n", s.c_str()); + OutputDebugString(buf); +#endif + + TargetChooser * tc = NULL; + int doTap = 0; + string lordType = ""; + + Trigger * trigger = parseTrigger(s); + //Dirty way to remove the trigger text (could get in the way) + if (trigger){ + found = s.find(":"); + s = s.substr(found+1); + } + + //Tap in the cost ? + if (s.find("{t}") != string::npos) doTap = 1; + + //Target Abilities + found = s.find("target("); + if (found != string::npos){ + int end = s.find(")"); + string starget = s.substr(found + 7,end - found - 7); + TargetChooserFactory tcf; + tc = tcf.createTargetChooser(starget, card); + + } + + //Lord + found = s.find("lord("); + if (found != string::npos){ + if (dryMode) return BAKA_EFFECT_GOOD; + unsigned int end = s.find(")", found+5); + if (end != string::npos){ + lordType = s.substr(found+5,end-found-5).c_str(); + } + } + + //Champion. Very basic, needs to be improved ! + found = s.find("champion(name:"); + if (found != string::npos){ + if (dryMode) return BAKA_EFFECT_GOOD; + unsigned int end = s.find(")", found+14); + if (end != string::npos){ + string type = s.substr(found+14,end-found-14).c_str(); + game->addObserver(NEW APlagueRats(id,card,type.c_str())); + result++; + continue; + } + } + + //Untapper (Ley Druid...) + found = s.find("untap"); + if (found != string::npos){ + if (dryMode) return BAKA_EFFECT_GOOD; + ManaCost * cost = ManaCost::parseManaCost(s); + if (tc){ + game->addObserver(NEW AUntaper(id, card, cost, tc)); + }else{ + target->tapped = 0; + } + + result++; + continue; + } + + //Tapper (icy manipulator) + found = s.find("tap"); + if (found != string::npos){ + if (dryMode) return BAKA_EFFECT_GOOD; + ManaCost * cost = ManaCost::parseManaCost(s); + if (tc){ + game->addObserver(NEW ATapper(id, card, cost, tc)); + }else{ + target->tapped = 1; + } + + result++; + continue; + } + + //Regeneration + found = s.find("}:regenerate"); + if (found != string::npos){ + if (dryMode) return BAKA_EFFECT_GOOD; + ManaCost * cost = ManaCost::parseManaCost(s); + + if (lordType.size() > 0){ + game->addObserver(NEW ALord(id,card,lordType.c_str(),0,0,-1,cost)); + }else{ + + if (tc){ + //TODO + }else{ + game->addObserver(NEW AStandardRegenerate(id, card, target, cost)); + //TODO death ward ! + } + } + result++; + continue; + } + + //Bury + found = s.find("bury"); + if (found != string::npos){ + if (trigger){ + if (dryMode) return BAKA_EFFECT_BAD; + BuryEvent * action = NEW BuryEvent(); + game->addObserver(NEW GenericTriggeredAbility(id, card,trigger,action)); + }else{ + found = s.find("all("); + if (found != string::npos){ + int end = s.find(")"); + string starget = s.substr(found + 4,end - found - 4); + TargetChooserFactory tcf; + TargetChooser * targetAll = tcf.createTargetChooser(starget, card); + if (dryMode){ + int myNbCards = countCards(targetAll,card->controller()); + int opponentNbCards = countCards(targetAll, card->controller()->opponent()); + int myCardsPower = countCards(targetAll,card->controller(),COUNT_POWER); + int opponentCardsPower = countCards(targetAll, card->controller()->opponent(),COUNT_POWER); + delete targetAll; + if (myNbCards < opponentNbCards || myCardsPower < opponentCardsPower) return BAKA_EFFECT_GOOD; + return BAKA_EFFECT_BAD; + }else{ + this->destroyAllInPlay(targetAll,1); + delete targetAll; + } + + }else{ + if (dryMode) return BAKA_EFFECT_BAD; + if (tc){ + game->addObserver(NEW ABurier(id, card,tc)); + }else{ + target->controller()->game->putInGraveyard(target); + } + } + } + result++; + continue; + } + + //Destroy + found = s.find("destroy"); + if (found != string::npos){ + + found = s.find("all("); + if (found != string::npos){ + int end = s.find(")"); + string starget = s.substr(found + 4,end - found - 4); + TargetChooserFactory tcf; + TargetChooser * targetAll = tcf.createTargetChooser(starget, card); + if (dryMode){ + int myNbCards = countCards(targetAll,card->controller()); + int opponentNbCards = countCards(targetAll, card->controller()->opponent()); + int myCardsPower = countCards(targetAll,card->controller(),COUNT_POWER); + int opponentCardsPower = countCards(targetAll, card->controller()->opponent(),COUNT_POWER); + delete targetAll; + if (myNbCards < opponentNbCards || myCardsPower < opponentCardsPower) return BAKA_EFFECT_GOOD; + return BAKA_EFFECT_BAD; + }else{ + this->destroyAllInPlay(targetAll); + delete targetAll; + } + }else{ + if (dryMode) return BAKA_EFFECT_BAD; + if (tc){ + game->addObserver(NEW ADestroyer(id, card,tc)); + }else{ + game->mLayers->stackLayer()->addPutInGraveyard(target); + } + } + result++; + continue; + } //Damage found = s.find("damage"); @@ -1804,4 +1849,4 @@ GenericTriggeredAbility::~GenericTriggeredAbility(){ delete t; delete te; SAFE_DELETE(dc); -} +} diff --git a/projects/mtg/src/TestSuiteAI.cpp b/projects/mtg/src/TestSuiteAI.cpp index 9c2b045c5..8cc99f6d4 100644 --- a/projects/mtg/src/TestSuiteAI.cpp +++ b/projects/mtg/src/TestSuiteAI.cpp @@ -294,9 +294,9 @@ int TestSuite::assertGame(){ } for (int k = 0; k < endState.playerData[i].zones[j].nbitems; k++){ int cardid = endState.playerData[i].zones[j].cards[k]; - int realcardid = zone->cards[k]->getMTGId(); - if ( realcardid!= cardid){ - sprintf(result, "==Card ID not the same. Expected %i, got %i==
", cardid, realcardid); + MTGCardInstance * card = getCardByMTGId(cardid); + if (!card || !zone->hasCard(card)){ + sprintf(result, "==Card ID not the same. Didn't find %i
", cardid); Log(result); error++; }