Fix for issue 647 (Evil Presence cast on a swamp removes mana ability)

This commit is contained in:
wagic.the.homebrew
2011-05-08 09:06:56 +00:00
parent b2ba514d7a
commit 2c0b5baab7
10 changed files with 111 additions and 15 deletions
+2
View File
@@ -260,6 +260,8 @@ erg_raiders_i157.txt
evil_presence.txt evil_presence.txt
evil_presence2.txt evil_presence2.txt
evil_presence3.txt evil_presence3.txt
evil_presence_i647.txt
evil_presence_i647_2.txt
explore.txt explore.txt
Faceless_Butcher.txt Faceless_Butcher.txt
fangren_pathcutter.txt fangren_pathcutter.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]
@@ -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]
+17 -3
View File
@@ -2160,6 +2160,7 @@ class ALord: public ListMaintainerAbility, public NestedAbility
public: public:
int includeSelf; int includeSelf;
map<Damageable *, MTGAbility *> abilities; map<Damageable *, MTGAbility *> abilities;
vector<MTGAbility *> bermudaTriangle; //Hack: Lost abilities that need to be properly removed if they reappear
ALord(int _id, MTGCardInstance * card, TargetChooser * _tc, int _includeSelf, MTGAbility * a) : ALord(int _id, MTGCardInstance * card, TargetChooser * _tc, int _includeSelf, MTGAbility * a) :
ListMaintainerAbility(_id, card), NestedAbility(a) ListMaintainerAbility(_id, card), NestedAbility(a)
@@ -2170,7 +2171,19 @@ public:
if(ability->aType == MTGAbility::STANDARD_PREVENT) if(ability->aType == MTGAbility::STANDARD_PREVENT)
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) int canBeInList(Player *p)
{ {
if (tc->canTarget(p)) return 1; if (tc->canTarget(p)) return 1;
@@ -2237,8 +2250,9 @@ public:
int removed(MTGCardInstance * card) int removed(MTGCardInstance * card)
{ {
if (abilities.find(card) != abilities.end()) if (abilities.find(card) != abilities.end())
{ {
game->removeObserver(abilities[card]); if (!game->removeObserver(abilities[card]))
bermudaTriangle.push_back(abilities[card]);
abilities.erase(card); abilities.erase(card);
} }
return 1; return 1;
+1 -1
View File
@@ -76,7 +76,7 @@ class GameObserver{
void Affinity(); void Affinity();
void eventOccured(); void eventOccured();
void addObserver(MTGAbility * observer); void addObserver(MTGAbility * observer);
void removeObserver(ActionElement * observer); bool removeObserver(ActionElement * observer);
void startGame(Rules * rules); void startGame(Rules * rules);
void untapPhase(); void untapPhase();
int isInPlay(MTGCardInstance * card); int isInPlay(MTGCardInstance * card);
+1
View File
@@ -58,6 +58,7 @@ public:
bool wasDealtDamage; bool wasDealtDamage;
bool damageToOpponent; bool damageToOpponent;
bool damageToController; bool damageToController;
bool mPropertiesChangedSinceLastUpdate;
int reduxamount; int reduxamount;
int flanked; int flanked;
int regenerateTokens; int regenerateTokens;
+1 -1
View File
@@ -274,7 +274,7 @@ void CardPrimitive::setName(const string& value)
std::transform(lcname.begin(), lcname.end(), lcname.begin(), ::tolower); std::transform(lcname.begin(), lcname.end(), lcname.begin(), ::tolower);
//This is a bug fix for plague rats and the "foreach ability" //This is a bug fix for plague rats and the "foreach ability"
//Right now we add names as types, so that they get recognized //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); Subtypes::subtypesList->find(lcname);
} }
+9 -6
View File
@@ -303,14 +303,15 @@ void GameObserver::addObserver(MTGAbility * observer)
mLayers->actionLayer()->Add(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) if (!observer)
mLayers->actionLayer()->moveToGarbage(observer); return false;
return mLayers->actionLayer()->moveToGarbage(observer);
else
{
} //TODO log error
} }
GameObserver::~GameObserver() GameObserver::~GameObserver()
@@ -375,6 +376,8 @@ void GameObserver::gameStateBasedEffects()
{ {
MTGCardInstance * card = zone->cards[j]; MTGCardInstance * card = zone->cards[j];
card->afterDamage(); card->afterDamage();
card->mPropertiesChangedSinceLastUpdate = false;
/////////////////////////////////////////////////////// ///////////////////////////////////////////////////////
//Remove auras that don't have a valid target anymore// //Remove auras that don't have a valid target anymore//
/////////////////////////////////////////////////////// ///////////////////////////////////////////////////////
+5 -4
View File
@@ -3767,7 +3767,7 @@ void ListMaintainerAbility::updateTargets()
for (map<MTGCardInstance *, bool>::iterator it = cards.begin(); it != cards.end(); ++it) for (map<MTGCardInstance *, bool>::iterator it = cards.begin(); it != cards.end(); ++it)
{ {
MTGCardInstance * card = (*it).first; MTGCardInstance * card = (*it).first;
if (!canBeInList(card)) if (!canBeInList(card) || card->mPropertiesChangedSinceLastUpdate)
{ {
temp[card] = true; temp[card] = true;
} }
@@ -3794,11 +3794,12 @@ void ListMaintainerAbility::updateTargets()
{ {
for (int j = 0; j < zone->nb_cards; j++) 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;
} }
} }
} }
+21
View File
@@ -145,6 +145,7 @@ void MTGCardInstance::initMTGCI()
wasDealtDamage = false; wasDealtDamage = false;
suspended = false; suspended = false;
castMethod = Constants::NOT_CAST; castMethod = Constants::NOT_CAST;
mPropertiesChangedSinceLastUpdate = false;
for (int i = 0; i < ManaCost::MANA_PAID_WITH_RETRACE +1; i++) 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); bool before = hasType(type);
CardPrimitive::addType(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); WEvent * e = NEW WEventCardChangeType(this, type, before, true);
GameObserver * go = GameObserver::GetInstance(); GameObserver * go = GameObserver::GetInstance();
if (go) if (go)
@@ -267,6 +278,16 @@ int MTGCardInstance::removeType(int id, int removeAll)
bool before = hasType(id); bool before = hasType(id);
int result = CardPrimitive::removeType(id, removeAll); int result = CardPrimitive::removeType(id, removeAll);
bool after = hasType(id); 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); WEvent * e = NEW WEventCardChangeType(this, id, before, after);
GameObserver * go = GameObserver::GetInstance(); GameObserver * go = GameObserver::GetInstance();
if (go) if (go)