From 2c0b5baab7082b31c9edddf0014f6c04ebbdc67f Mon Sep 17 00:00:00 2001 From: "wagic.the.homebrew" Date: Sun, 8 May 2011 09:06:56 +0000 Subject: [PATCH] Fix for issue 647 (Evil Presence cast on a swamp removes mana ability) --- projects/mtg/bin/Res/test/_tests.txt | 2 ++ .../mtg/bin/Res/test/evil_presence_i647.txt | 21 ++++++++++++ .../mtg/bin/Res/test/evil_presence_i647_2.txt | 33 +++++++++++++++++++ projects/mtg/include/AllAbilities.h | 20 +++++++++-- projects/mtg/include/GameObserver.h | 2 +- projects/mtg/include/MTGCardInstance.h | 1 + projects/mtg/src/CardPrimitive.cpp | 2 +- projects/mtg/src/GameObserver.cpp | 15 +++++---- projects/mtg/src/MTGAbility.cpp | 9 ++--- projects/mtg/src/MTGCardInstance.cpp | 21 ++++++++++++ 10 files changed, 111 insertions(+), 15 deletions(-) create mode 100644 projects/mtg/bin/Res/test/evil_presence_i647.txt create mode 100644 projects/mtg/bin/Res/test/evil_presence_i647_2.txt diff --git a/projects/mtg/bin/Res/test/_tests.txt b/projects/mtg/bin/Res/test/_tests.txt index 1caa963c7..2e5afacee 100644 --- a/projects/mtg/bin/Res/test/_tests.txt +++ b/projects/mtg/bin/Res/test/_tests.txt @@ -260,6 +260,8 @@ erg_raiders_i157.txt evil_presence.txt evil_presence2.txt evil_presence3.txt +evil_presence_i647.txt +evil_presence_i647_2.txt explore.txt Faceless_Butcher.txt fangren_pathcutter.txt diff --git a/projects/mtg/bin/Res/test/evil_presence_i647.txt b/projects/mtg/bin/Res/test/evil_presence_i647.txt new file mode 100644 index 000000000..2e4fe7fe5 --- /dev/null +++ b/projects/mtg/bin/Res/test/evil_presence_i647.txt @@ -0,0 +1,21 @@ +#Testing Evil Presence on a swamp...it should have no visible effect +# Bug: it removes the swamp's ability +#see http://code.google.com/p/wagic/issues/detail?id=647 +[INIT] +FIRSTMAIN +[PLAYER1] +hand:Evil Presence +inplay:Swamp +manapool:{B} +[PLAYER2] +[DO] +Evil Presence +Swamp +Swamp +[ASSERT] +FIRSTMAIN +[PLAYER1] +inplay:Swamp,Evil Presence +manapool:{B} +[PLAYER2] +[END] \ No newline at end of file diff --git a/projects/mtg/bin/Res/test/evil_presence_i647_2.txt b/projects/mtg/bin/Res/test/evil_presence_i647_2.txt new file mode 100644 index 000000000..01548c7f3 --- /dev/null +++ b/projects/mtg/bin/Res/test/evil_presence_i647_2.txt @@ -0,0 +1,33 @@ +#Testing Evil Presence on a swamp...it should have no visible effect +# Bug: it removes the swamp's ability +#In thistest we make sure we don't get a crash during the next turn, when abilities are added/removed from different sources +#see http://code.google.com/p/wagic/issues/detail?id=647 +[INIT] +FIRSTMAIN +[PLAYER1] +hand:Evil Presence, Disenchant +inplay:Swamp,Forest,Plains +manapool:{B} +[PLAYER2] +[DO] +Evil Presence +Swamp +eot +eot +next +#upkeep +next +#draw +next +#main +Forest +Plains +Disenchant +Evil Presence +[ASSERT] +FIRSTMAIN +[PLAYER1] +inplay:Swamp,Forest,Plains +graveyard:Evil Presence,disenchant +[PLAYER2] +[END] \ No newline at end of file diff --git a/projects/mtg/include/AllAbilities.h b/projects/mtg/include/AllAbilities.h index 91f016d35..9ba010580 100644 --- a/projects/mtg/include/AllAbilities.h +++ b/projects/mtg/include/AllAbilities.h @@ -2160,6 +2160,7 @@ class ALord: public ListMaintainerAbility, public NestedAbility public: int includeSelf; map abilities; + vector bermudaTriangle; //Hack: Lost abilities that need to be properly removed if they reappear ALord(int _id, MTGCardInstance * card, TargetChooser * _tc, int _includeSelf, MTGAbility * a) : ListMaintainerAbility(_id, card), NestedAbility(a) @@ -2170,7 +2171,19 @@ public: if(ability->aType == MTGAbility::STANDARD_PREVENT) aType = MTGAbility::STANDARD_PREVENT; } - + + void Update(float dt) + { + ListMaintainerAbility::Update(dt); + + //This is a hack to avoid some abilities "combing back from the dead" because of the loseAbility keyword :/ + for (int i = (int)(bermudaTriangle.size()) - 1 ; i >= 0 ; --i) + { + if (game->removeObserver(bermudaTriangle[i])) + bermudaTriangle.erase(bermudaTriangle.begin()+i); + } + } + int canBeInList(Player *p) { if (tc->canTarget(p)) return 1; @@ -2237,8 +2250,9 @@ public: int removed(MTGCardInstance * card) { if (abilities.find(card) != abilities.end()) - { - game->removeObserver(abilities[card]); + { + if (!game->removeObserver(abilities[card])) + bermudaTriangle.push_back(abilities[card]); abilities.erase(card); } return 1; diff --git a/projects/mtg/include/GameObserver.h b/projects/mtg/include/GameObserver.h index de8fbcff4..0972fb18d 100644 --- a/projects/mtg/include/GameObserver.h +++ b/projects/mtg/include/GameObserver.h @@ -76,7 +76,7 @@ class GameObserver{ void Affinity(); void eventOccured(); void addObserver(MTGAbility * observer); - void removeObserver(ActionElement * observer); + bool removeObserver(ActionElement * observer); void startGame(Rules * rules); void untapPhase(); int isInPlay(MTGCardInstance * card); diff --git a/projects/mtg/include/MTGCardInstance.h b/projects/mtg/include/MTGCardInstance.h index 7cccfed67..47075b9ae 100644 --- a/projects/mtg/include/MTGCardInstance.h +++ b/projects/mtg/include/MTGCardInstance.h @@ -58,6 +58,7 @@ public: bool wasDealtDamage; bool damageToOpponent; bool damageToController; + bool mPropertiesChangedSinceLastUpdate; int reduxamount; int flanked; int regenerateTokens; diff --git a/projects/mtg/src/CardPrimitive.cpp b/projects/mtg/src/CardPrimitive.cpp index 52c878f2f..106baec54 100644 --- a/projects/mtg/src/CardPrimitive.cpp +++ b/projects/mtg/src/CardPrimitive.cpp @@ -274,7 +274,7 @@ void CardPrimitive::setName(const string& value) std::transform(lcname.begin(), lcname.end(), lcname.begin(), ::tolower); //This is a bug fix for plague rats and the "foreach ability" //Right now we add names as types, so that they get recognized - if (lcname.at(value.length() - 1) == 's') + if (value.length() && lcname.at(value.length() - 1) == 's') Subtypes::subtypesList->find(lcname); } diff --git a/projects/mtg/src/GameObserver.cpp b/projects/mtg/src/GameObserver.cpp index 1e6318926..5dc14398c 100644 --- a/projects/mtg/src/GameObserver.cpp +++ b/projects/mtg/src/GameObserver.cpp @@ -303,14 +303,15 @@ void GameObserver::addObserver(MTGAbility * observer) mLayers->actionLayer()->Add(observer); } -void GameObserver::removeObserver(ActionElement * observer) +//Returns true if the Ability was correctly removed from the game, false otherwise +//Main (valid) reason of returning false is an attempt at removing an Ability that has already been removed +bool GameObserver::removeObserver(ActionElement * observer) { - if (observer) - mLayers->actionLayer()->moveToGarbage(observer); + if (!observer) + return false; + + return mLayers->actionLayer()->moveToGarbage(observer); - else - { - } //TODO log error } GameObserver::~GameObserver() @@ -375,6 +376,8 @@ void GameObserver::gameStateBasedEffects() { MTGCardInstance * card = zone->cards[j]; card->afterDamage(); + card->mPropertiesChangedSinceLastUpdate = false; + /////////////////////////////////////////////////////// //Remove auras that don't have a valid target anymore// /////////////////////////////////////////////////////// diff --git a/projects/mtg/src/MTGAbility.cpp b/projects/mtg/src/MTGAbility.cpp index ecaceabe1..dace43901 100644 --- a/projects/mtg/src/MTGAbility.cpp +++ b/projects/mtg/src/MTGAbility.cpp @@ -3767,7 +3767,7 @@ void ListMaintainerAbility::updateTargets() for (map::iterator it = cards.begin(); it != cards.end(); ++it) { MTGCardInstance * card = (*it).first; - if (!canBeInList(card)) + if (!canBeInList(card) || card->mPropertiesChangedSinceLastUpdate) { temp[card] = true; } @@ -3794,11 +3794,12 @@ void ListMaintainerAbility::updateTargets() { for (int j = 0; j < zone->nb_cards; j++) { - if (canBeInList(zone->cards[j])) + MTGCardInstance * card = zone->cards[j]; + if (canBeInList(card)) { - if (cards.find(zone->cards[j]) == cards.end()) + if (cards.find(card) == cards.end()) { - temp[zone->cards[j]] = true; + temp[card] = true; } } } diff --git a/projects/mtg/src/MTGCardInstance.cpp b/projects/mtg/src/MTGCardInstance.cpp index 1681c3f17..9f5ad71f5 100644 --- a/projects/mtg/src/MTGCardInstance.cpp +++ b/projects/mtg/src/MTGCardInstance.cpp @@ -145,6 +145,7 @@ void MTGCardInstance::initMTGCI() wasDealtDamage = false; suspended = false; castMethod = Constants::NOT_CAST; + mPropertiesChangedSinceLastUpdate = false; for (int i = 0; i < ManaCost::MANA_PAID_WITH_RETRACE +1; i++) @@ -233,6 +234,16 @@ void MTGCardInstance::addType(int type) { bool before = hasType(type); CardPrimitive::addType(type); + + if (!before) + mPropertiesChangedSinceLastUpdate = true; + + // If the card name is not set, set it to the type. + //This is a hack for "transform", used in combination with "losesubtypes" on Basic Lands + //See removeType below + if (!name.length()) + setName(Subtypes::subtypesList->find(type)); + WEvent * e = NEW WEventCardChangeType(this, type, before, true); GameObserver * go = GameObserver::GetInstance(); if (go) @@ -267,6 +278,16 @@ int MTGCardInstance::removeType(int id, int removeAll) bool before = hasType(id); int result = CardPrimitive::removeType(id, removeAll); bool after = hasType(id); + if (before != after) + { + mPropertiesChangedSinceLastUpdate = true; + // Basic lands have the same name as their subtypes, and TargetChoosers don't make a distinction between name and type, + // so if we remove a subtype "Forest", we also need to remove its name. + //This means the card might lose its name, but usually when we force remove a type, we add another one just after that. + //see "AddType" above which force sets a name if necessary + if (name.compare(Subtypes::subtypesList->find(id)) == 0) + setName(""); + } WEvent * e = NEW WEventCardChangeType(this, id, before, after); GameObserver * go = GameObserver::GetInstance(); if (go)