diff --git a/projects/mtg/bin/Res/sets/primitives/M20.txt b/projects/mtg/bin/Res/sets/primitives/M20.txt index b885168a8..40242b788 100644 --- a/projects/mtg/bin/Res/sets/primitives/M20.txt +++ b/projects/mtg/bin/Res/sets/primitives/M20.txt @@ -1616,7 +1616,7 @@ toughness=2 name=Angel of Vitality abilities=flying 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. mana={2}{W} type=Creature diff --git a/projects/mtg/include/AllAbilities.h b/projects/mtg/include/AllAbilities.h index b8ff0c4e8..681f63385 100644 --- a/projects/mtg/include/AllAbilities.h +++ b/projects/mtg/include/AllAbilities.h @@ -1736,8 +1736,9 @@ public: TargetChooser * fromTc; int type;//this allows damagenoncombat and combatdamage to share this trigger 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) : - Trigger(observer, id, source, once , tc), fromTc(fromTc), type(type) , sourceUntapped(sourceUntapped) , thiscontroller(thiscontroller) , thisopponent(thisopponent) + MTGCardInstance * gainException; //added exception to avid a gainlife loop (eg. Angels of Vitality) + 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; if (!tc->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 == 0 && (e->amount < 0)) return 0; if(thiscontroller) @@ -6983,7 +6985,7 @@ public: MTGCardInstance * card = d->source; if (d->damage > 0 && card && (card == source || card == source->target)) { - source->owner->gainLife(d->damage); + source->owner->gainLife(d->damage, source); return 1; } } diff --git a/projects/mtg/include/Player.h b/projects/mtg/include/Player.h index 9369ea79a..c578e0edf 100644 --- a/projects/mtg/include/Player.h +++ b/projects/mtg/include/Player.h @@ -69,9 +69,10 @@ public: int afterDamage(); - int gainLife(int value); - int loseLife(int value); - int gainOrLoseLife(int value); + // Added source of life gain/loss in order to check later a possible exception. + int gainLife(int value, MTGCardInstance* source); + int loseLife(int value, MTGCardInstance* source); + int gainOrLoseLife(int value, MTGCardInstance* source); bool isPoisoned() {return (poisonCount > 0);} int poisoned(); diff --git a/projects/mtg/include/WEvent.h b/projects/mtg/include/WEvent.h index 9cb1788a7..7a6cda611 100644 --- a/projects/mtg/include/WEvent.h +++ b/projects/mtg/include/WEvent.h @@ -71,7 +71,8 @@ struct WEventCounters : public WEvent { struct WEventLife : public WEvent { Player * player; int amount; - WEventLife(Player * player,int amount); + MTGCardInstance * source; + WEventLife(Player * player,int amount, MTGCardInstance * source); virtual Targetable * getTarget(int target); }; diff --git a/projects/mtg/src/AllAbilities.cpp b/projects/mtg/src/AllAbilities.cpp index 9ec0dc2f6..f8f5c399b 100644 --- a/projects/mtg/src/AllAbilities.cpp +++ b/projects/mtg/src/AllAbilities.cpp @@ -4033,9 +4033,9 @@ int AALifer::resolve() _target = ((MTGCardInstance *) _target)->controller(); } 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)) - source->controller()->gainOrLoseLife(slife); + source->controller()->gainOrLoseLife(slife, source); return 1; } @@ -4222,7 +4222,7 @@ int AALifeSet::resolve() return 0; int lifeDiff = life->getValue() - p->life ; - p->gainOrLoseLife(lifeDiff); + p->gainOrLoseLife(lifeDiff, source); return 1; } @@ -6509,14 +6509,14 @@ int AAExchangeLife::resolve() if(oldlife > targetOldLife) { increaser = oldlife - targetOldLife; - player->gainOrLoseLife(modifier * -1); + player->gainOrLoseLife(modifier * -1, source); card->addToToughness(increaser+toughMod); } else { _target->life = oldlife; card->toughness = oldlife; - player->gainOrLoseLife(modifier); + player->gainOrLoseLife(modifier, source); } return 1; @@ -6524,13 +6524,13 @@ int AAExchangeLife::resolve() Player * opponent = (Player*)_target; if(oldlife > targetOldLife) { - player->gainOrLoseLife(modifier * -1); - opponent->gainOrLoseLife(modifier); + player->gainOrLoseLife(modifier * -1, source); + opponent->gainOrLoseLife(modifier, source); } else { - player->gainOrLoseLife(modifier); - opponent->gainOrLoseLife(modifier * -1); + player->gainOrLoseLife(modifier, source); + opponent->gainOrLoseLife(modifier * -1, source); } return 1; } diff --git a/projects/mtg/src/Damage.cpp b/projects/mtg/src/Damage.cpp index 597f746c9..ed2f88ae9 100644 --- a/projects/mtg/src/Damage.cpp +++ b/projects/mtg/src/Damage.cpp @@ -269,7 +269,7 @@ int Damage::resolve() 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); } } diff --git a/projects/mtg/src/ExtraCost.cpp b/projects/mtg/src/ExtraCost.cpp index 26c781988..0311a1f3d 100644 --- a/projects/mtg/src/ExtraCost.cpp +++ b/projects/mtg/src/ExtraCost.cpp @@ -299,7 +299,7 @@ int LifeCost::doPay() MTGCardInstance * _target = (MTGCardInstance *) target; - _target->controller()->loseLife(1); + _target->controller()->loseLife(1, source); target = NULL; if (tc) tc->initTargets(); @@ -345,7 +345,7 @@ int SpecificLifeCost::doPay() MTGCardInstance * _target = (MTGCardInstance *) target; - _target->controller()->loseLife(slc); + _target->controller()->loseLife(slc, source); target = NULL; if (tc) tc->initTargets(); @@ -407,7 +407,7 @@ int LifeorManaCost::doPay() } else { - _target->controller()->loseLife(2); + _target->controller()->loseLife(2, source); } target = NULL; if (tc) diff --git a/projects/mtg/src/MTGAbility.cpp b/projects/mtg/src/MTGAbility.cpp index 16ee47ffa..abe868d60 100644 --- a/projects/mtg/src/MTGAbility.cpp +++ b/projects/mtg/src/MTGAbility.cpp @@ -1248,42 +1248,66 @@ TriggeredAbility * AbilityFactory::parseTrigger(string s, string, int id, Spell if (TargetChooser * tc = parseSimpleTC(s, "lifeof", card)) { TargetChooser *fromTc = parseSimpleTC(s, "from", card); - return NEW TrLifeGained(observer, id, card, tc, fromTc, 0,sourceUntapped,once,true,false); + 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); } //Lifed current opponent if (TargetChooser * tc = parseSimpleTC(s, "lifefoeof", card)) { TargetChooser *fromTc = parseSimpleTC(s, "from", card); - return NEW TrLifeGained(observer, id, card, tc, fromTc, 0,sourceUntapped,once,false,true); + 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); } //Lifed static if (TargetChooser * tc = parseSimpleTC(s, "lifed", 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 if (TargetChooser * tc = parseSimpleTC(s, "lifelostof", card)) { TargetChooser *fromTc = parseSimpleTC(s, "from", card); - return NEW TrLifeGained(observer, id, card, tc, fromTc,1,sourceUntapped,once,true,false); + 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); } //Life Loss current opponent if (TargetChooser * tc = parseSimpleTC(s, "lifelostfoeof", card)) { TargetChooser *fromTc = parseSimpleTC(s, "from", card); - return NEW TrLifeGained(observer, id, card, tc, fromTc,1,sourceUntapped,once,false,true); + 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); } //Life Loss static if (TargetChooser * tc = parseSimpleTC(s, "lifeloss", 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 @@ -5174,7 +5198,7 @@ void AbilityFactory::addAbilities(int _id, Spell * spell) observer->mLayers->stackLayer()->addDamage(card, target, x); if (target->life < x) x = target->life; - observer->currentlyActing()->gainLife(x); + observer->currentlyActing()->gainLife(x, card); break; } case 1159: //Erg Raiders @@ -5316,7 +5340,7 @@ void AbilityFactory::addAbilities(int _id, Spell * spell) if (current->hasType("Artifact")) { 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) player->game->putInZone(library->cards[library->nb_cards - 1], library, player->game->graveyard); } - observer->currentlyActing()->gainLife(x); + observer->currentlyActing()->gainLife(x, card); break; } diff --git a/projects/mtg/src/MTGRules.cpp b/projects/mtg/src/MTGRules.cpp index c2828e82f..ea2d901da 100644 --- a/projects/mtg/src/MTGRules.cpp +++ b/projects/mtg/src/MTGRules.cpp @@ -3838,7 +3838,7 @@ int MTGLifelinkRule::receiveEvent(WEvent * event) MTGCardInstance * card = d->source; 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; } } diff --git a/projects/mtg/src/Player.cpp b/projects/mtg/src/Player.cpp index 42ca1b60e..363a46cfd 100644 --- a/projects/mtg/src/Player.cpp +++ b/projects/mtg/src/Player.cpp @@ -159,7 +159,7 @@ ManaPool * Player::getManaPool() return manaPool; } -int Player::gainOrLoseLife(int value) +int Player::gainOrLoseLife(int value, MTGCardInstance* source) { if (!value) 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 - WEvent * lifed = NEW WEventLife(this,value); + WEvent * lifed = NEW WEventLife(this, value, source); observer->receiveEvent(lifed); return value; } -int Player::gainLife(int value) +int Player::gainLife(int value, MTGCardInstance* source) { if (value <0) { DebugTrace("PLAYER.CPP: don't call gainLife on a negative value, use loseLife instead"); return 0; } - return gainOrLoseLife(value); + return gainOrLoseLife(value, source); } -int Player::loseLife(int value) +int Player::loseLife(int value, MTGCardInstance* source) { if (value <0) { DebugTrace("PLAYER.CPP: don't call loseLife on a negative value, use gainLife instead"); return 0; } - return gainOrLoseLife(-value); + return gainOrLoseLife(-value, source); } int Player::afterDamage() diff --git a/projects/mtg/src/WEvent.cpp b/projects/mtg/src/WEvent.cpp index a88aa85d3..5a4f36d78 100644 --- a/projects/mtg/src/WEvent.cpp +++ b/projects/mtg/src/WEvent.cpp @@ -22,8 +22,8 @@ WEventDamage::WEventDamage(Damage *damage) : { } -WEventLife::WEventLife(Player * player,int amount) : - WEvent(), player(player),amount(amount) +WEventLife::WEventLife(Player * player, int amount, MTGCardInstance* source) : + WEvent(), player(player), amount(amount), source(source) { }