Fixed Angel of Vitality in M20 set and added new keyword "except" for @lifeof trigger in order to avoid a life gain loop when a card needs to increment life gaining in that phase (eg. Angel of Vitality).

This commit is contained in:
valfieri
2019-09-10 17:02:50 +02:00
parent 6ecd762d18
commit 06ec97676e
11 changed files with 67 additions and 39 deletions
+1 -1
View File
@@ -1616,7 +1616,7 @@ toughness=2
name=Angel of Vitality name=Angel of Vitality
abilities=flying abilities=flying
auto=this(controllerlife > 24) 2/2 auto=this(controllerlife > 24) 2/2
auto=@lifeof(player): may life:1 auto=@lifeof(player) except(Angel of Vitality): life:1
text=Flying -- If you would gain life, you gain that much life plus 1 instead. -- Angel of Vitality gets +2/+2 as long as you have 25 or more life. text=Flying -- If you would gain life, you gain that much life plus 1 instead. -- Angel of Vitality gets +2/+2 as long as you have 25 or more life.
mana={2}{W} mana={2}{W}
type=Creature type=Creature
+5 -3
View File
@@ -1736,8 +1736,9 @@ public:
TargetChooser * fromTc; TargetChooser * fromTc;
int type;//this allows damagenoncombat and combatdamage to share this trigger int type;//this allows damagenoncombat and combatdamage to share this trigger
bool sourceUntapped, thiscontroller, thisopponent; bool sourceUntapped, thiscontroller, thisopponent;
TrLifeGained(GameObserver* observer, int id, MTGCardInstance * source, TargetChooser * tc, TargetChooser * fromTc = NULL, int type = 0,bool sourceUntapped = false,bool once = false, bool thiscontroller = false, bool thisopponent = false) : MTGCardInstance * gainException; //added exception to avid a gainlife loop (eg. Angels of Vitality)
Trigger(observer, id, source, once , tc), fromTc(fromTc), type(type) , sourceUntapped(sourceUntapped) , thiscontroller(thiscontroller) , thisopponent(thisopponent) TrLifeGained(GameObserver* observer, int id, MTGCardInstance * source, TargetChooser * tc, TargetChooser * fromTc = NULL, int type = 0,bool sourceUntapped = false,bool once = false, bool thiscontroller = false, bool thisopponent = false, MTGCardInstance * gainException = NULL) :
Trigger(observer, id, source, once , tc), fromTc(fromTc), type(type) , sourceUntapped(sourceUntapped) , thiscontroller(thiscontroller) , thisopponent(thisopponent), gainException(gainException)
{ {
} }
@@ -1749,6 +1750,7 @@ public:
return 0; return 0;
if (!tc->canTarget(e->player)) return 0; if (!tc->canTarget(e->player)) return 0;
if (fromTc && !fromTc->canTarget(e->player)) return 0; if (fromTc && !fromTc->canTarget(e->player)) return 0;
if (gainException && e->source && !strcmp(gainException->data->name.c_str(), e->source->data->name.c_str())) return 0; //If the source of life gain it's the exception card don't gain life (loop avoidance);
if (type == 1 && (e->amount > 0)) return 0; if (type == 1 && (e->amount > 0)) return 0;
if (type == 0 && (e->amount < 0)) return 0; if (type == 0 && (e->amount < 0)) return 0;
if(thiscontroller) if(thiscontroller)
@@ -6983,7 +6985,7 @@ public:
MTGCardInstance * card = d->source; MTGCardInstance * card = d->source;
if (d->damage > 0 && card && (card == source || card == source->target)) if (d->damage > 0 && card && (card == source || card == source->target))
{ {
source->owner->gainLife(d->damage); source->owner->gainLife(d->damage, source);
return 1; return 1;
} }
} }
+4 -3
View File
@@ -69,9 +69,10 @@ public:
int afterDamage(); int afterDamage();
int gainLife(int value); // Added source of life gain/loss in order to check later a possible exception.
int loseLife(int value); int gainLife(int value, MTGCardInstance* source);
int gainOrLoseLife(int value); int loseLife(int value, MTGCardInstance* source);
int gainOrLoseLife(int value, MTGCardInstance* source);
bool isPoisoned() {return (poisonCount > 0);} bool isPoisoned() {return (poisonCount > 0);}
int poisoned(); int poisoned();
+2 -1
View File
@@ -71,7 +71,8 @@ struct WEventCounters : public WEvent {
struct WEventLife : public WEvent { struct WEventLife : public WEvent {
Player * player; Player * player;
int amount; int amount;
WEventLife(Player * player,int amount); MTGCardInstance * source;
WEventLife(Player * player,int amount, MTGCardInstance * source);
virtual Targetable * getTarget(int target); virtual Targetable * getTarget(int target);
}; };
+9 -9
View File
@@ -4033,9 +4033,9 @@ int AALifer::resolve()
_target = ((MTGCardInstance *) _target)->controller(); _target = ((MTGCardInstance *) _target)->controller();
} }
Player *player = (Player*)_target; Player *player = (Player*)_target;
int slife = abs(player->gainOrLoseLife(life.getValue())); int slife = abs(player->gainOrLoseLife(life.getValue(), source));
if(siphon && (slife > 0) && (life.getValue() < 0)) if(siphon && (slife > 0) && (life.getValue() < 0))
source->controller()->gainOrLoseLife(slife); source->controller()->gainOrLoseLife(slife, source);
return 1; return 1;
} }
@@ -4222,7 +4222,7 @@ int AALifeSet::resolve()
return 0; return 0;
int lifeDiff = life->getValue() - p->life ; int lifeDiff = life->getValue() - p->life ;
p->gainOrLoseLife(lifeDiff); p->gainOrLoseLife(lifeDiff, source);
return 1; return 1;
} }
@@ -6509,14 +6509,14 @@ int AAExchangeLife::resolve()
if(oldlife > targetOldLife) if(oldlife > targetOldLife)
{ {
increaser = oldlife - targetOldLife; increaser = oldlife - targetOldLife;
player->gainOrLoseLife(modifier * -1); player->gainOrLoseLife(modifier * -1, source);
card->addToToughness(increaser+toughMod); card->addToToughness(increaser+toughMod);
} }
else else
{ {
_target->life = oldlife; _target->life = oldlife;
card->toughness = oldlife; card->toughness = oldlife;
player->gainOrLoseLife(modifier); player->gainOrLoseLife(modifier, source);
} }
return 1; return 1;
@@ -6524,13 +6524,13 @@ int AAExchangeLife::resolve()
Player * opponent = (Player*)_target; Player * opponent = (Player*)_target;
if(oldlife > targetOldLife) if(oldlife > targetOldLife)
{ {
player->gainOrLoseLife(modifier * -1); player->gainOrLoseLife(modifier * -1, source);
opponent->gainOrLoseLife(modifier); opponent->gainOrLoseLife(modifier, source);
} }
else else
{ {
player->gainOrLoseLife(modifier); player->gainOrLoseLife(modifier, source);
opponent->gainOrLoseLife(modifier * -1); opponent->gainOrLoseLife(modifier * -1, source);
} }
return 1; return 1;
} }
+1 -1
View File
@@ -269,7 +269,7 @@ int Damage::resolve()
source->controller()->prowledTypes.push_back(values[i]); source->controller()->prowledTypes.push_back(values[i]);
} }
} }
WEvent * lifed = NEW WEventLife((Player*)target,-damage); WEvent * lifed = NEW WEventLife((Player*)target,-damage, source);
observer->receiveEvent(lifed); observer->receiveEvent(lifed);
} }
} }
+3 -3
View File
@@ -299,7 +299,7 @@ int LifeCost::doPay()
MTGCardInstance * _target = (MTGCardInstance *) target; MTGCardInstance * _target = (MTGCardInstance *) target;
_target->controller()->loseLife(1); _target->controller()->loseLife(1, source);
target = NULL; target = NULL;
if (tc) if (tc)
tc->initTargets(); tc->initTargets();
@@ -345,7 +345,7 @@ int SpecificLifeCost::doPay()
MTGCardInstance * _target = (MTGCardInstance *) target; MTGCardInstance * _target = (MTGCardInstance *) target;
_target->controller()->loseLife(slc); _target->controller()->loseLife(slc, source);
target = NULL; target = NULL;
if (tc) if (tc)
tc->initTargets(); tc->initTargets();
@@ -407,7 +407,7 @@ int LifeorManaCost::doPay()
} }
else else
{ {
_target->controller()->loseLife(2); _target->controller()->loseLife(2, source);
} }
target = NULL; target = NULL;
if (tc) if (tc)
+29 -5
View File
@@ -1248,6 +1248,10 @@ TriggeredAbility * AbilityFactory::parseTrigger(string s, string, int id, Spell
if (TargetChooser * tc = parseSimpleTC(s, "lifeof", card)) if (TargetChooser * tc = parseSimpleTC(s, "lifeof", card))
{ {
TargetChooser *fromTc = parseSimpleTC(s, "from", card); TargetChooser *fromTc = parseSimpleTC(s, "from", card);
TargetChooser *exception = parseSimpleTC(s, "except", card); // Added a new keyword except to specify a life gain/loss card exception in order to avoid life gain loop (eg. Angels of Vitality)
if(exception)
return NEW TrLifeGained(observer, id, card, tc, fromTc, 0,sourceUntapped,once,true,false, exception->source);
else
return NEW TrLifeGained(observer, id, card, tc, fromTc, 0,sourceUntapped,once,true,false); return NEW TrLifeGained(observer, id, card, tc, fromTc, 0,sourceUntapped,once,true,false);
} }
@@ -1255,6 +1259,10 @@ TriggeredAbility * AbilityFactory::parseTrigger(string s, string, int id, Spell
if (TargetChooser * tc = parseSimpleTC(s, "lifefoeof", card)) if (TargetChooser * tc = parseSimpleTC(s, "lifefoeof", card))
{ {
TargetChooser *fromTc = parseSimpleTC(s, "from", card); TargetChooser *fromTc = parseSimpleTC(s, "from", card);
TargetChooser *exception = parseSimpleTC(s, "except", card); // Added a new keyword except to specify a life gain/loss card exception in order to avoid life gain loop (eg. Angels of Vitality)
if(exception)
return NEW TrLifeGained(observer, id, card, tc, fromTc, 0,sourceUntapped,once,false,true, exception->source);
else
return NEW TrLifeGained(observer, id, card, tc, fromTc, 0,sourceUntapped,once,false,true); return NEW TrLifeGained(observer, id, card, tc, fromTc, 0,sourceUntapped,once,false,true);
} }
@@ -1262,13 +1270,21 @@ TriggeredAbility * AbilityFactory::parseTrigger(string s, string, int id, Spell
if (TargetChooser * tc = parseSimpleTC(s, "lifed", card)) if (TargetChooser * tc = parseSimpleTC(s, "lifed", card))
{ {
TargetChooser *fromTc = parseSimpleTC(s, "from", card); TargetChooser *fromTc = parseSimpleTC(s, "from", card);
return NEW TrLifeGained(observer, id, card, tc, fromTc, 0,sourceUntapped,once); TargetChooser *exception = parseSimpleTC(s, "except", card); // Added a new keyword except to specify a life gain/loss card exception in order to avoid life gain loop (eg. Angels of Vitality)
if(exception)
return NEW TrLifeGained(observer, id, card, tc, fromTc, 0,sourceUntapped,once,false,false, exception->source);
else
return NEW TrLifeGained(observer, id, card, tc, fromTc, 0,sourceUntapped,once,false,false);
} }
//Life Loss current player //Life Loss current player
if (TargetChooser * tc = parseSimpleTC(s, "lifelostof", card)) if (TargetChooser * tc = parseSimpleTC(s, "lifelostof", card))
{ {
TargetChooser *fromTc = parseSimpleTC(s, "from", card); TargetChooser *fromTc = parseSimpleTC(s, "from", card);
TargetChooser *exception = parseSimpleTC(s, "except", card); // Added a new keyword except to specify a life gain/loss card exception in order to avoid life gain loop (eg. Angels of Vitality)
if(exception)
return NEW TrLifeGained(observer, id, card, tc, fromTc, 1,sourceUntapped,once,true,false, exception->source);
else
return NEW TrLifeGained(observer, id, card, tc, fromTc, 1,sourceUntapped,once,true,false); return NEW TrLifeGained(observer, id, card, tc, fromTc, 1,sourceUntapped,once,true,false);
} }
@@ -1276,6 +1292,10 @@ TriggeredAbility * AbilityFactory::parseTrigger(string s, string, int id, Spell
if (TargetChooser * tc = parseSimpleTC(s, "lifelostfoeof", card)) if (TargetChooser * tc = parseSimpleTC(s, "lifelostfoeof", card))
{ {
TargetChooser *fromTc = parseSimpleTC(s, "from", card); TargetChooser *fromTc = parseSimpleTC(s, "from", card);
TargetChooser *exception = parseSimpleTC(s, "except", card); // Added a new keyword except to specify a life gain/loss card exception in order to avoid life gain loop (eg. Angels of Vitality)
if(exception)
return NEW TrLifeGained(observer, id, card, tc, fromTc, 1,sourceUntapped,once,false,true, exception->source);
else
return NEW TrLifeGained(observer, id, card, tc, fromTc, 1,sourceUntapped,once,false,true); return NEW TrLifeGained(observer, id, card, tc, fromTc, 1,sourceUntapped,once,false,true);
} }
@@ -1283,7 +1303,11 @@ TriggeredAbility * AbilityFactory::parseTrigger(string s, string, int id, Spell
if (TargetChooser * tc = parseSimpleTC(s, "lifeloss", card)) if (TargetChooser * tc = parseSimpleTC(s, "lifeloss", card))
{ {
TargetChooser *fromTc = parseSimpleTC(s, "from", card); TargetChooser *fromTc = parseSimpleTC(s, "from", card);
return NEW TrLifeGained(observer, id, card, tc, fromTc,1,sourceUntapped,once); TargetChooser *exception = parseSimpleTC(s, "except", card); // Added a new keyword except to specify a life gain/loss card exception in order to avoid life gain loop (eg. Angels of Vitality)
if(exception)
return NEW TrLifeGained(observer, id, card, tc, fromTc, 1,sourceUntapped,once,false,false, exception->source);
else
return NEW TrLifeGained(observer, id, card, tc, fromTc, 1,sourceUntapped,once,false,false);
} }
//Card Damaged and killed by a creature this turn //Card Damaged and killed by a creature this turn
@@ -5174,7 +5198,7 @@ void AbilityFactory::addAbilities(int _id, Spell * spell)
observer->mLayers->stackLayer()->addDamage(card, target, x); observer->mLayers->stackLayer()->addDamage(card, target, x);
if (target->life < x) if (target->life < x)
x = target->life; x = target->life;
observer->currentlyActing()->gainLife(x); observer->currentlyActing()->gainLife(x, card);
break; break;
} }
case 1159: //Erg Raiders case 1159: //Erg Raiders
@@ -5316,7 +5340,7 @@ void AbilityFactory::addAbilities(int _id, Spell * spell)
if (current->hasType("Artifact")) if (current->hasType("Artifact"))
{ {
observer->players[i]->game->putInGraveyard(current); observer->players[i]->game->putInGraveyard(current);
current->controller()->gainLife(current->getManaCost()->getConvertedCost()); current->controller()->gainLife(current->getManaCost()->getConvertedCost(), card);
} }
} }
} }
@@ -5416,7 +5440,7 @@ void AbilityFactory::addAbilities(int _id, Spell * spell)
if (library->nb_cards) if (library->nb_cards)
player->game->putInZone(library->cards[library->nb_cards - 1], library, player->game->graveyard); player->game->putInZone(library->cards[library->nb_cards - 1], library, player->game->graveyard);
} }
observer->currentlyActing()->gainLife(x); observer->currentlyActing()->gainLife(x, card);
break; break;
} }
+1 -1
View File
@@ -3838,7 +3838,7 @@ int MTGLifelinkRule::receiveEvent(WEvent * event)
MTGCardInstance * card = d->source; MTGCardInstance * card = d->source;
if (d->damage > 0 && card && (card->basicAbilities[(int)Constants::LIFELINK]||card->LKIbasicAbilities[(int)Constants::LIFELINK])) if (d->damage > 0 && card && (card->basicAbilities[(int)Constants::LIFELINK]||card->LKIbasicAbilities[(int)Constants::LIFELINK]))
{ {
card->controller()->gainLife(d->damage); card->controller()->gainLife(d->damage, source);
return 1; return 1;
} }
} }
+6 -6
View File
@@ -159,7 +159,7 @@ ManaPool * Player::getManaPool()
return manaPool; return manaPool;
} }
int Player::gainOrLoseLife(int value) int Player::gainOrLoseLife(int value, MTGCardInstance* source)
{ {
if (!value) if (!value)
return 0; //Don't do anything if there's no actual life change return 0; //Don't do anything if there's no actual life change
@@ -179,30 +179,30 @@ int Player::gainOrLoseLife(int value)
} }
//Send life event to listeners //Send life event to listeners
WEvent * lifed = NEW WEventLife(this,value); WEvent * lifed = NEW WEventLife(this, value, source);
observer->receiveEvent(lifed); observer->receiveEvent(lifed);
return value; return value;
} }
int Player::gainLife(int value) int Player::gainLife(int value, MTGCardInstance* source)
{ {
if (value <0) if (value <0)
{ {
DebugTrace("PLAYER.CPP: don't call gainLife on a negative value, use loseLife instead"); DebugTrace("PLAYER.CPP: don't call gainLife on a negative value, use loseLife instead");
return 0; return 0;
} }
return gainOrLoseLife(value); return gainOrLoseLife(value, source);
} }
int Player::loseLife(int value) int Player::loseLife(int value, MTGCardInstance* source)
{ {
if (value <0) if (value <0)
{ {
DebugTrace("PLAYER.CPP: don't call loseLife on a negative value, use gainLife instead"); DebugTrace("PLAYER.CPP: don't call loseLife on a negative value, use gainLife instead");
return 0; return 0;
} }
return gainOrLoseLife(-value); return gainOrLoseLife(-value, source);
} }
int Player::afterDamage() int Player::afterDamage()
+2 -2
View File
@@ -22,8 +22,8 @@ WEventDamage::WEventDamage(Damage *damage) :
{ {
} }
WEventLife::WEventLife(Player * player,int amount) : WEventLife::WEventLife(Player * player, int amount, MTGCardInstance* source) :
WEvent(), player(player),amount(amount) WEvent(), player(player), amount(amount), source(source)
{ {
} }