new LifeCompareCondition, with tests (#12221)

This commit is contained in:
xenohedron 2024-05-04 23:25:07 -04:00 committed by GitHub
parent 3ea0e88268
commit dc13384c52
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
19 changed files with 279 additions and 237 deletions

View file

@ -1,20 +1,16 @@
package mage.cards.a; package mage.cards.a;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.Condition; import mage.abilities.condition.Condition;
import mage.abilities.condition.common.LifeCompareCondition;
import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.decorator.ConditionalContinuousEffect;
import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect;
import mage.abilities.effects.common.replacement.GainPlusOneLifeReplacementEffect; import mage.abilities.effects.common.replacement.GainPlusOneLifeReplacementEffect;
import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.*;
import mage.constants.Duration;
import mage.constants.SubType;
import mage.game.Game;
import mage.players.Player;
import java.util.UUID; import java.util.UUID;
@ -23,6 +19,8 @@ import java.util.UUID;
*/ */
public final class AngelOfVitality extends CardImpl { public final class AngelOfVitality extends CardImpl {
private static final Condition condition = new LifeCompareCondition(TargetController.YOU, ComparisonType.OR_GREATER, 25);
public AngelOfVitality(UUID ownerId, CardSetInfo setInfo) { public AngelOfVitality(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}");
@ -39,7 +37,7 @@ public final class AngelOfVitality extends CardImpl {
// Angel of Vitality gets +2/+2 as long as you have 25 or more life. // Angel of Vitality gets +2/+2 as long as you have 25 or more life.
this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect(
new BoostSourceEffect(2, 2, Duration.WhileOnBattlefield), new BoostSourceEffect(2, 2, Duration.WhileOnBattlefield),
AngelOfVitalityCondition.instance, "{this} gets +2/+2 as long as you have 25 or more life" condition, "{this} gets +2/+2 as long as you have 25 or more life"
))); )));
} }
@ -52,13 +50,3 @@ public final class AngelOfVitality extends CardImpl {
return new AngelOfVitality(this); return new AngelOfVitality(this);
} }
} }
enum AngelOfVitalityCondition implements Condition {
instance;
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
return player != null && player.getLife() >= 25;
}
}

View file

@ -97,7 +97,7 @@ class BloodBaronOfVizkopaEffect extends ContinuousEffectImpl {
} }
for (UUID opponentId : game.getOpponents(controller.getId())) { for (UUID opponentId : game.getOpponents(controller.getId())) {
Player opponent = game.getPlayer(opponentId); Player opponent = game.getPlayer(opponentId);
if (opponent != null && opponent.getLife() <= 10) { if (opponent != null && opponent.isInGame() && opponent.getLife() <= 10) {
return true; return true;
} }
} }

View file

@ -1,11 +1,10 @@
package mage.cards.b; package mage.cards.b;
import mage.MageInt; import mage.MageInt;
import mage.abilities.common.CantBlockAbility; import mage.abilities.common.CantBlockAbility;
import mage.abilities.common.LandfallAbility; import mage.abilities.common.LandfallAbility;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.common.XorLessLifeCondition; import mage.abilities.condition.common.LifeCompareCondition;
import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.decorator.ConditionalContinuousEffect;
import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.ContinuousEffect;
import mage.abilities.effects.common.ReturnSourceFromGraveyardToBattlefieldEffect; import mage.abilities.effects.common.ReturnSourceFromGraveyardToBattlefieldEffect;
@ -13,10 +12,7 @@ import mage.abilities.effects.common.continuous.GainAbilitySourceEffect;
import mage.abilities.keyword.HasteAbility; import mage.abilities.keyword.HasteAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.*;
import mage.constants.Duration;
import mage.constants.SubType;
import mage.constants.Zone;
import java.util.UUID; import java.util.UUID;
@ -37,7 +33,7 @@ public final class Bloodghast extends CardImpl {
// Bloodghast has haste as long as an opponent has 10 or less life. // Bloodghast has haste as long as an opponent has 10 or less life.
ContinuousEffect effect = new GainAbilitySourceEffect(HasteAbility.getInstance(), Duration.WhileOnBattlefield); ContinuousEffect effect = new GainAbilitySourceEffect(HasteAbility.getInstance(), Duration.WhileOnBattlefield);
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect(effect, this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect(effect,
new XorLessLifeCondition(XorLessLifeCondition.CheckType.AN_OPPONENT, 10), new LifeCompareCondition(TargetController.OPPONENT, ComparisonType.OR_LESS, 10),
"{this} has haste as long as an opponent has 10 or less life"))); "{this} has haste as long as an opponent has 10 or less life")));
// Landfall Whenever a land enters the battlefield under your control, you may return Bloodghast from your graveyard to the battlefield. // Landfall Whenever a land enters the battlefield under your control, you may return Bloodghast from your graveyard to the battlefield.
this.addAbility(new LandfallAbility(Zone.GRAVEYARD, new ReturnSourceFromGraveyardToBattlefieldEffect(false, false), true)); this.addAbility(new LandfallAbility(Zone.GRAVEYARD, new ReturnSourceFromGraveyardToBattlefieldEffect(false, false), true));

View file

@ -1,12 +1,9 @@
package mage.cards.c; package mage.cards.c;
import java.util.UUID;
import mage.abilities.TriggeredAbility; import mage.abilities.TriggeredAbility;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.condition.common.XorLessLifeCondition; import mage.abilities.condition.common.FatefulHourCondition;
import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.GainLifeEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
@ -14,6 +11,8 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.TargetController; import mage.constants.TargetController;
import java.util.UUID;
/** /**
* *
* @author fireshoes * @author fireshoes
@ -24,10 +23,10 @@ public final class ConvalescentCare extends CardImpl {
super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{W}{W}"); super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{W}{W}");
// At the beginning of your upkeep, if you have 5 or less life, you gain 3 life and draw a card. // At the beginning of your upkeep, if you have 5 or less life, you gain 3 life and draw a card.
Effect effect = new DrawCardSourceControllerEffect(1);
TriggeredAbility ability = new BeginningOfUpkeepTriggeredAbility(new GainLifeEffect(3), TargetController.YOU, false); TriggeredAbility ability = new BeginningOfUpkeepTriggeredAbility(new GainLifeEffect(3), TargetController.YOU, false);
ability.addEffect(effect); ability.addEffect(new DrawCardSourceControllerEffect(1));
this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, new XorLessLifeCondition(XorLessLifeCondition.CheckType.CONTROLLER, 5), "At the beginning of your upkeep, if you have 5 or less life, you gain 3 life and draw a card.")); this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, FatefulHourCondition.instance,
"At the beginning of your upkeep, if you have 5 or less life, you gain 3 life and draw a card."));
} }
private ConvalescentCare(final ConvalescentCare card) { private ConvalescentCare(final ConvalescentCare card) {

View file

@ -1,12 +1,9 @@
package mage.cards.c; package mage.cards.c;
import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.common.EntersBattlefieldTappedAbility; import mage.abilities.common.EntersBattlefieldTappedAbility;
import mage.abilities.condition.common.XorLessLifeCondition; import mage.abilities.condition.common.LifeCompareCondition;
import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.common.LoseLifeAllPlayersEffect; import mage.abilities.effects.common.LoseLifeAllPlayersEffect;
import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.effects.common.TransformSourceEffect;
@ -15,8 +12,11 @@ import mage.abilities.mana.AnyColorManaAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.ComparisonType;
import mage.constants.TargetController; import mage.constants.TargetController;
import java.util.UUID;
/** /**
* @author fireshoes * @author fireshoes
*/ */
@ -31,16 +31,16 @@ public final class CryptolithFragment extends CardImpl {
this.addAbility(new EntersBattlefieldTappedAbility()); this.addAbility(new EntersBattlefieldTappedAbility());
// {T}: Add one mana of any color. Each player loses 1 life. // {T}: Add one mana of any color. Each player loses 1 life.
Ability AnyColorManaAbility = new AnyColorManaAbility(); Ability anyColorManaAbility = new AnyColorManaAbility();
AnyColorManaAbility.addEffect(new LoseLifeAllPlayersEffect(1)); anyColorManaAbility.addEffect(new LoseLifeAllPlayersEffect(1));
this.addAbility(AnyColorManaAbility); this.addAbility(anyColorManaAbility);
// At the beginning of your upkeep, if each player has 10 or less life, transform Cryptolith Fragment. // At the beginning of your upkeep, if each player has 10 or less life, transform Cryptolith Fragment.
this.addAbility(new TransformAbility()); this.addAbility(new TransformAbility());
this.addAbility(new ConditionalInterveningIfTriggeredAbility( this.addAbility(new ConditionalInterveningIfTriggeredAbility(
new BeginningOfUpkeepTriggeredAbility(new TransformSourceEffect(), TargetController.YOU, false), new BeginningOfUpkeepTriggeredAbility(new TransformSourceEffect(), TargetController.YOU, false),
new XorLessLifeCondition(XorLessLifeCondition.CheckType.EACH_PLAYER, 10), new LifeCompareCondition(TargetController.EACH_PLAYER, ComparisonType.OR_LESS, 10),
"At the beginning of your upkeep, if each player has 10 or less life, transform Cryptolith Fragment.")); "At the beginning of your upkeep, if each player has 10 or less life, transform {this}."));
} }
private CryptolithFragment(final CryptolithFragment card) { private CryptolithFragment(final CryptolithFragment card) {

View file

@ -4,7 +4,7 @@ import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.Mode; import mage.abilities.Mode;
import mage.abilities.common.DiesSourceTriggeredAbility; import mage.abilities.common.DiesSourceTriggeredAbility;
import mage.abilities.condition.Condition; import mage.abilities.condition.common.LifeCompareCondition;
import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.effects.common.ExileGraveyardAllTargetPlayerEffect; import mage.abilities.effects.common.ExileGraveyardAllTargetPlayerEffect;
import mage.abilities.effects.common.LoseLifeSourceControllerEffect; import mage.abilities.effects.common.LoseLifeSourceControllerEffect;
@ -12,9 +12,9 @@ import mage.abilities.effects.common.LoseLifeTargetEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.ComparisonType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.game.Game; import mage.constants.TargetController;
import mage.players.Player;
import mage.target.common.TargetOpponent; import mage.target.common.TargetOpponent;
import java.util.UUID; import java.util.UUID;
@ -36,7 +36,7 @@ public final class DiscipleOfPerdition extends CardImpl {
// * You draw a card and you lose 1 life. // * You draw a card and you lose 1 life.
Ability ability = new DiesSourceTriggeredAbility(new DrawCardSourceControllerEffect(1, "you"), false); Ability ability = new DiesSourceTriggeredAbility(new DrawCardSourceControllerEffect(1, "you"), false);
ability.getModes().setChooseText("choose one. If you have exactly 13 life, you may choose both."); ability.getModes().setChooseText("choose one. If you have exactly 13 life, you may choose both.");
ability.getModes().setMoreCondition(DiscipleOfPerditionCondition.instance); ability.getModes().setMoreCondition(new LifeCompareCondition(TargetController.YOU, ComparisonType.EQUAL_TO, 13));
ability.addEffect(new LoseLifeSourceControllerEffect(1).concatBy("and")); ability.addEffect(new LoseLifeSourceControllerEffect(1).concatBy("and"));
// * Exile target opponent's graveyard. That player loses 1 life. // * Exile target opponent's graveyard. That player loses 1 life.
@ -56,13 +56,3 @@ public final class DiscipleOfPerdition extends CardImpl {
return new DiscipleOfPerdition(this); return new DiscipleOfPerdition(this);
} }
} }
enum DiscipleOfPerditionCondition implements Condition {
instance;
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
return player != null && player.getLife() == 13;
}
}

View file

@ -1,23 +1,17 @@
package mage.cards.d; package mage.cards.d;
import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.Condition; import mage.abilities.condition.common.LifeCompareCondition;
import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.decorator.ConditionalContinuousEffect;
import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect;
import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.FlyingAbility;
import mage.abilities.keyword.LifelinkAbility; import mage.abilities.keyword.LifelinkAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.*;
import mage.constants.SubType;
import mage.constants.Duration; import java.util.UUID;
import mage.constants.Zone;
import mage.game.Game;
import mage.players.Player;
/** /**
* *
@ -41,7 +35,7 @@ public final class DivinityOfPride extends CardImpl {
// Divinity of Pride gets +4/+4 as long as you have 25 or more life. // Divinity of Pride gets +4/+4 as long as you have 25 or more life.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD,
new ConditionalContinuousEffect(new BoostSourceEffect(4, 4, Duration.WhileOnBattlefield), new ConditionalContinuousEffect(new BoostSourceEffect(4, 4, Duration.WhileOnBattlefield),
new DivinityOfPrideCondition(), new LifeCompareCondition(TargetController.YOU, ComparisonType.OR_GREATER, 25),
"{this} gets +4/+4 as long as you have 25 or more life"))); "{this} gets +4/+4 as long as you have 25 or more life")));
} }
@ -54,12 +48,3 @@ public final class DivinityOfPride extends CardImpl {
return new DivinityOfPride(this); return new DivinityOfPride(this);
} }
} }
class DivinityOfPrideCondition implements Condition {
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
return player != null && player.getLife() >= 25;
}
}

View file

@ -1,22 +1,19 @@
package mage.cards.g; package mage.cards.g;
import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.Condition; import mage.abilities.condition.Condition;
import mage.abilities.condition.common.XorLessLifeCondition; import mage.abilities.condition.common.LifeCompareCondition;
import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.decorator.ConditionalContinuousEffect;
import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect;
import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect;
import mage.abilities.keyword.IntimidateAbility; import mage.abilities.keyword.IntimidateAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.*;
import mage.constants.SubType;
import mage.constants.Duration; import java.util.UUID;
import mage.constants.Zone;
/** /**
* *
@ -24,6 +21,7 @@ import mage.constants.Zone;
*/ */
public final class GuulDrazVampire extends CardImpl { public final class GuulDrazVampire extends CardImpl {
private static final Condition condition = new LifeCompareCondition(TargetController.OPPONENT, ComparisonType.OR_LESS, 10);
private static final String rule1 = "As long as an opponent has 10 or less life, {this} gets +2/+1"; private static final String rule1 = "As long as an opponent has 10 or less life, {this} gets +2/+1";
private static final String rule2 = "and has intimidate. <i>(It can't be blocked except by artifact creatures and/or creatures that share a color with it.)</i>"; private static final String rule2 = "and has intimidate. <i>(It can't be blocked except by artifact creatures and/or creatures that share a color with it.)</i>";
@ -37,7 +35,6 @@ public final class GuulDrazVampire extends CardImpl {
this.toughness = new MageInt(1); this.toughness = new MageInt(1);
// As long as an opponent has 10 or less life, Guul Draz Vampire gets +2/+1 and has intimidate. (It can't be blocked except by artifact creatures and/or creatures that share a color with it.) // As long as an opponent has 10 or less life, Guul Draz Vampire gets +2/+1 and has intimidate. (It can't be blocked except by artifact creatures and/or creatures that share a color with it.)
Condition condition = new XorLessLifeCondition(XorLessLifeCondition.CheckType.AN_OPPONENT, 10);
ConditionalContinuousEffect effect1 = new ConditionalContinuousEffect(new BoostSourceEffect(2, 1, Duration.WhileOnBattlefield), condition, rule1); ConditionalContinuousEffect effect1 = new ConditionalContinuousEffect(new BoostSourceEffect(2, 1, Duration.WhileOnBattlefield), condition, rule1);
Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, effect1); Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, effect1);
ability.addEffect(new ConditionalContinuousEffect(new GainAbilitySourceEffect(IntimidateAbility.getInstance()), condition, rule2)); ability.addEffect(new ConditionalContinuousEffect(new GainAbilitySourceEffect(IntimidateAbility.getInstance()), condition, rule2));

View file

@ -40,7 +40,7 @@ class HidetsugusSecondRiteEffect extends OneShotEffect {
HidetsugusSecondRiteEffect() { HidetsugusSecondRiteEffect() {
super(Outcome.Damage); super(Outcome.Damage);
this.staticText = "If target player has exactly 10 life, Hidetsugu's Second Rite deals 10 damage to that player"; this.staticText = "If target player has exactly 10 life, {this} deals 10 damage to that player";
} }
private HidetsugusSecondRiteEffect(final HidetsugusSecondRiteEffect effect) { private HidetsugusSecondRiteEffect(final HidetsugusSecondRiteEffect effect) {

View file

@ -1,20 +1,16 @@
package mage.cards.h; package mage.cards.h;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.Condition; import mage.abilities.condition.Condition;
import mage.abilities.condition.common.LifeCompareCondition;
import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.decorator.ConditionalContinuousEffect;
import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect;
import mage.abilities.effects.common.replacement.GainPlusOneLifeReplacementEffect; import mage.abilities.effects.common.replacement.GainPlusOneLifeReplacementEffect;
import mage.abilities.keyword.VigilanceAbility; import mage.abilities.keyword.VigilanceAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.*;
import mage.constants.Duration;
import mage.constants.SubType;
import mage.game.Game;
import mage.players.Player;
import java.util.UUID; import java.util.UUID;
@ -23,6 +19,8 @@ import java.util.UUID;
*/ */
public final class HonorTroll extends CardImpl { public final class HonorTroll extends CardImpl {
private static final Condition condition = new LifeCompareCondition(TargetController.YOU, ComparisonType.OR_GREATER, 25);
public HonorTroll(UUID ownerId, CardSetInfo setInfo) { public HonorTroll(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}");
@ -40,7 +38,7 @@ public final class HonorTroll extends CardImpl {
// Honor Troll gets +2/+1 as long as you have 25 or more life. // Honor Troll gets +2/+1 as long as you have 25 or more life.
this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect(
new BoostSourceEffect(2, 1, Duration.WhileOnBattlefield), new BoostSourceEffect(2, 1, Duration.WhileOnBattlefield),
HonorTrollCondition.instance, "{this} gets +2/+1 as long as you have 25 or more life" condition, "{this} gets +2/+1 as long as you have 25 or more life"
))); )));
} }
@ -53,13 +51,3 @@ public final class HonorTroll extends CardImpl {
return new HonorTroll(this); return new HonorTroll(this);
} }
} }
enum HonorTrollCondition implements Condition {
instance;
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
return player != null && player.getLife() >= 25;
}
}

View file

@ -1,32 +1,30 @@
package mage.cards.n; package mage.cards.n;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.TriggeredAbility;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.condition.Condition; import mage.abilities.condition.common.LifeCompareCondition;
import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.common.WinGameSourceControllerEffect; import mage.abilities.effects.common.WinGameSourceControllerEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.ComparisonType;
import mage.constants.TargetController; import mage.constants.TargetController;
import mage.game.Game;
import java.util.UUID;
/** /**
*
* @author jeffwadsworth * @author jeffwadsworth
*/ */
public final class NearDeathExperience extends CardImpl { public final class NearDeathExperience extends CardImpl {
public NearDeathExperience(UUID ownerId, CardSetInfo setInfo) { public NearDeathExperience(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{W}{W}{W}"); super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}{W}{W}");
// At the beginning of your upkeep, if you have exactly 1 life, you win the game. // At the beginning of your upkeep, if you have exactly 1 life, you win the game.
TriggeredAbility ability = new BeginningOfUpkeepTriggeredAbility(new WinGameSourceControllerEffect(), TargetController.YOU, false); this.addAbility(new ConditionalInterveningIfTriggeredAbility(
this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, new OneLifeCondition(), "At the beginning of your upkeep, if you have exactly 1 life, you win the game.")); new BeginningOfUpkeepTriggeredAbility(new WinGameSourceControllerEffect(), TargetController.YOU, false),
new LifeCompareCondition(TargetController.YOU, ComparisonType.EQUAL_TO, 1),
"At the beginning of your upkeep, if you have exactly 1 life, you win the game."));
} }
private NearDeathExperience(final NearDeathExperience card) { private NearDeathExperience(final NearDeathExperience card) {
@ -38,11 +36,3 @@ public final class NearDeathExperience extends CardImpl {
return new NearDeathExperience(this); return new NearDeathExperience(this);
} }
} }
class OneLifeCondition implements Condition {
@Override
public boolean apply(Game game, Ability source) {
return game.getPlayer(source.getControllerId()).getLife() == 1;
}
}

View file

@ -1,18 +1,15 @@
package mage.cards.r; package mage.cards.r;
import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.common.XorLessLifeCondition; import mage.abilities.condition.common.LifeCompareCondition;
import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.decorator.ConditionalContinuousEffect;
import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.*;
import mage.constants.SubType;
import mage.constants.Duration; import java.util.UUID;
import mage.constants.Zone;
/** /**
* *
@ -31,7 +28,7 @@ public final class RuthlessCullblade extends CardImpl {
// Ruthless Cullblade gets +2/+1 as long as an opponent has 10 or less life. // Ruthless Cullblade gets +2/+1 as long as an opponent has 10 or less life.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD,
new ConditionalContinuousEffect(new BoostSourceEffect(2, 1, Duration.WhileOnBattlefield), new ConditionalContinuousEffect(new BoostSourceEffect(2, 1, Duration.WhileOnBattlefield),
new XorLessLifeCondition(XorLessLifeCondition.CheckType.AN_OPPONENT, 10), new LifeCompareCondition(TargetController.OPPONENT, ComparisonType.OR_LESS, 10),
"{this} gets +2/+1 as long as an opponent has 10 or less life."))); "{this} gets +2/+1 as long as an opponent has 10 or less life.")));
} }

View file

@ -1,10 +1,8 @@
package mage.cards.s; package mage.cards.s;
import java.util.UUID;
import mage.abilities.TriggeredAbility; import mage.abilities.TriggeredAbility;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.condition.common.XorLessLifeCondition; import mage.abilities.condition.common.FatefulHourCondition;
import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.common.SacrificeSourceEffect; import mage.abilities.effects.common.SacrificeSourceEffect;
import mage.abilities.effects.common.turn.AddExtraTurnControllerEffect; import mage.abilities.effects.common.turn.AddExtraTurnControllerEffect;
@ -14,6 +12,8 @@ import mage.constants.CardType;
import mage.constants.TargetController; import mage.constants.TargetController;
import mage.constants.Zone; import mage.constants.Zone;
import java.util.UUID;
/** /**
* *
* @author Plopman * @author Plopman
@ -23,12 +23,11 @@ public final class SecondChance extends CardImpl {
public SecondChance(UUID ownerId, CardSetInfo setInfo) { public SecondChance(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{U}"); super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{U}");
// At the beginning of your upkeep, if you have 5 or less life, sacrifice Second Chance and take an extra turn after this one. // At the beginning of your upkeep, if you have 5 or less life, sacrifice Second Chance and take an extra turn after this one.
TriggeredAbility ability = new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, new SacrificeSourceEffect(), TargetController.YOU, false); TriggeredAbility ability = new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, new SacrificeSourceEffect(), TargetController.YOU, false);
ability.addEffect(new AddExtraTurnControllerEffect()); ability.addEffect(new AddExtraTurnControllerEffect());
this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, new XorLessLifeCondition(XorLessLifeCondition.CheckType.CONTROLLER, 5), "At the beginning of your upkeep, if you have 5 or less life, sacrifice {this} and take an extra turn after this one")); this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, FatefulHourCondition.instance,
"At the beginning of your upkeep, if you have 5 or less life, sacrifice {this} and take an extra turn after this one"));
} }
private SecondChance(final SecondChance card) { private SecondChance(final SecondChance card) {

View file

@ -2,7 +2,7 @@ package mage.cards.t;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.common.XorLessLifeCondition; import mage.abilities.condition.common.FatefulHourCondition;
import mage.abilities.effects.common.cost.SpellCostReductionSourceEffect; import mage.abilities.effects.common.cost.SpellCostReductionSourceEffect;
import mage.abilities.effects.common.search.SearchTargetGraveyardHandLibraryForCardNameAndExileEffect; import mage.abilities.effects.common.search.SearchTargetGraveyardHandLibraryForCardNameAndExileEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
@ -28,12 +28,10 @@ public final class TheEnd extends CardImpl {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{B}{B}"); super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{B}{B}");
// This spell costs {2} less to cast if your life total is 5 or less. // This spell costs {2} less to cast if your life total is 5 or less.
this.addAbility(new SimpleStaticAbility( this.addAbility(new SimpleStaticAbility(Zone.ALL,
Zone.ALL, new SpellCostReductionSourceEffect(2, FatefulHourCondition.instance)
new SpellCostReductionSourceEffect( .setCanWorksOnStackOnly(true)
2, .setText("This spell costs {2} less to cast if your life total is 5 or less.")
new XorLessLifeCondition(XorLessLifeCondition.CheckType.CONTROLLER, 5)
).setCanWorksOnStackOnly(true).setText("This spell costs {2} less to cast if your life total is 5 or less.")
).setRuleAtTheTop(true)); ).setRuleAtTheTop(true));
// Exile target creature or planeswalker. Search its controller's graveyard, hand, and library for any number of cards with the same name as that permanent and exile them. That player shuffles, then draws card for each card exiled from their hand this way. // Exile target creature or planeswalker. Search its controller's graveyard, hand, and library for any number of cards with the same name as that permanent and exile them. That player shuffles, then draws card for each card exiled from their hand this way.

View file

@ -1,22 +1,17 @@
package mage.cards.t; package mage.cards.t;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.GainLifeControllerTriggeredAbility; import mage.abilities.common.GainLifeControllerTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.Condition; import mage.abilities.condition.common.LifeCompareCondition;
import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.decorator.ConditionalContinuousEffect;
import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.abilities.keyword.DoubleStrikeAbility; import mage.abilities.keyword.DoubleStrikeAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.*;
import mage.constants.Duration;
import mage.constants.SubType;
import mage.counters.CounterType; import mage.counters.CounterType;
import mage.game.Game;
import mage.players.Player;
import java.util.UUID; import java.util.UUID;
@ -41,7 +36,8 @@ public final class TwinbladePaladin extends CardImpl {
// As long as you have 25 or more life, Twinblade Paladin has double strike. // As long as you have 25 or more life, Twinblade Paladin has double strike.
this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect(
new GainAbilitySourceEffect(DoubleStrikeAbility.getInstance(), Duration.WhileOnBattlefield), new GainAbilitySourceEffect(DoubleStrikeAbility.getInstance(), Duration.WhileOnBattlefield),
TwinbladePaladinCondition.instance, "As long as you have 25 or more life, {this} has double strike." new LifeCompareCondition(TargetController.YOU, ComparisonType.OR_GREATER, 25),
"As long as you have 25 or more life, {this} has double strike."
))); )));
} }
@ -54,13 +50,3 @@ public final class TwinbladePaladin extends CardImpl {
return new TwinbladePaladin(this); return new TwinbladePaladin(this);
} }
} }
enum TwinbladePaladinCondition implements Condition {
instance;
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
return player != null && player.getLife() > 24;
}
}

View file

@ -1,25 +1,28 @@
package mage.cards.v; package mage.cards.v;
import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.condition.InvertCondition; import mage.abilities.condition.Condition;
import mage.abilities.condition.common.XorLessLifeCondition; import mage.abilities.condition.common.LifeCompareCondition;
import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.decorator.ConditionalOneShotEffect;
import mage.abilities.effects.common.LoseLifeSourceControllerEffect; import mage.abilities.effects.common.LoseLifeSourceControllerEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.ComparisonType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.TargetController; import mage.constants.TargetController;
import java.util.UUID;
/** /**
* *
* @author maurer.it_at_gmail.com * @author maurer.it_at_gmail.com
*/ */
public final class VampireLacerator extends CardImpl { public final class VampireLacerator extends CardImpl {
private static final Condition condition = new LifeCompareCondition(TargetController.OPPONENT, ComparisonType.MORE_THAN, 10);
public VampireLacerator(UUID ownerId, CardSetInfo setInfo) { public VampireLacerator(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{B}"); super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{B}");
this.subtype.add(SubType.VAMPIRE); this.subtype.add(SubType.VAMPIRE);
@ -28,11 +31,10 @@ public final class VampireLacerator extends CardImpl {
this.power = new MageInt(2); this.power = new MageInt(2);
this.toughness = new MageInt(2); this.toughness = new MageInt(2);
this.addAbility(new BeginningOfUpkeepTriggeredAbility( this.addAbility(new BeginningOfUpkeepTriggeredAbility(new ConditionalOneShotEffect(
new ConditionalOneShotEffect( new LoseLifeSourceControllerEffect(1), condition,
new LoseLifeSourceControllerEffect(1), "you lose 1 life unless an opponent has 10 or less life"
new InvertCondition( new XorLessLifeCondition(XorLessLifeCondition.CheckType.AN_OPPONENT, 10) ), ), TargetController.YOU, false));
"you lose 1 life unless an opponent has 10 or less life"), TargetController.YOU, false));
} }
private VampireLacerator(final VampireLacerator card) { private VampireLacerator(final VampireLacerator card) {

View file

@ -0,0 +1,83 @@
package org.mage.test.cards.conditional;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
* @author xenohedron
*/
public class LifeCompareConditionTest extends CardTestPlayerBase {
@Test
public void test10OrLess() {
String lacerator = "Vampire Lacerator"; // B 2/2
// At the beginning of your upkeep, you lose 1 life unless an opponent has 10 or less life.
String cullblade = "Ruthless Cullblade"; // 1B 2/1
// Ruthless Cullblade gets +2/+1 as long as an opponent has 10 or less life.
String vengeance = "Sorin's Vengeance"; // 4BBB Sorcery
// Sorins Vengeance deals 10 damage to target player or planeswalker and you gain 10 life.
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 7);
addCard(Zone.HAND, playerA, lacerator, 2);
addCard(Zone.BATTLEFIELD, playerA, cullblade, 1);
addCard(Zone.HAND, playerA, vengeance);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, lacerator);
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, lacerator);
checkPT("opp at 20", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, cullblade, 2, 1);
setChoice(playerA, "At the beginning"); // turn 3 upkeep, order triggers
checkPT("opp at 20", 3, PhaseStep.PRECOMBAT_MAIN, playerA, cullblade, 2, 1);
checkLife("2 life lost", 3, PhaseStep.PRECOMBAT_MAIN, playerA, 18);
checkLife("no damage dealt", 3, PhaseStep.PRECOMBAT_MAIN, playerB, 20);
setChoice(playerA, "At the beginning"); // turn 5 upkeep, order triggers
castSpell(5, PhaseStep.PRECOMBAT_MAIN, playerA, vengeance, playerB);
checkPT("opp at 10", 5, PhaseStep.POSTCOMBAT_MAIN, playerA, cullblade, 4, 2);
checkLife("4 life lost, 10 gained", 5, PhaseStep.POSTCOMBAT_MAIN, playerA, 26);
checkLife("10 damage dealt", 5, PhaseStep.POSTCOMBAT_MAIN, playerB, 10);
setChoice(playerA, "At the beginning"); // turn 7 upkeep, order triggers but no life lost
setStopAt(7, PhaseStep.END_TURN);
setStrictChooseMode(true);
execute();
assertLife(playerA, 26);
assertLife(playerB, 10);
}
@Test
public void test25orMore() {
String angel = "Angel of Vitality"; // 2W 2/2 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.
String missionary = "Lone Missionary"; // 1W 2/1
// When Lone Missionary enters the battlefield, you gain 4 life.
addCard(Zone.BATTLEFIELD, playerA, "Plains", 2);
addCard(Zone.HAND, playerA, missionary);
addCard(Zone.BATTLEFIELD, playerA, angel);
checkPT("20 life", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, angel, 2, 2);
castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, missionary);
setStopAt(3, PhaseStep.END_TURN);
setStrictChooseMode(true);
execute();
assertLife(playerA, 25);
assertLife(playerB, 20);
assertPowerToughness(playerA, angel, 4, 4);
assertPowerToughness(playerA, missionary, 2, 1);
}
}

View file

@ -0,0 +1,113 @@
package mage.abilities.condition.common;
import mage.abilities.Ability;
import mage.abilities.condition.Condition;
import mage.constants.ComparisonType;
import mage.constants.TargetController;
import mage.game.Game;
import mage.players.Player;
import java.util.Objects;
/**
* @author xenohedron
*/
public class LifeCompareCondition implements Condition {
private final TargetController targetController;
private final ComparisonType comparisonType;
private final int amount;
/**
* "As long as [player] has [number] or [more/less] life"
* @param targetController YOU, OPPONENT, ANY, EACH_PLAYER
* @param comparisonType comparison operator
* @param amount life threshold
*/
public LifeCompareCondition(TargetController targetController, ComparisonType comparisonType, int amount) {
this.targetController = targetController;
this.comparisonType = comparisonType;
this.amount = amount;
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller == null) {
return false;
}
switch (targetController) {
case YOU:
return ComparisonType.compare(controller.getLife(), comparisonType, amount);
case OPPONENT:
return game.getOpponents(controller.getId())
.stream()
.map(game::getPlayer)
.filter(Objects::nonNull)
.filter(Player::isInGame) // Once a player leaves the game, their life check is no longer valid.
.map(Player::getLife)
.anyMatch(l -> ComparisonType.compare(l, comparisonType, amount));
case ANY:
return game.getState().getPlayersInRange(controller.getId(), game)
.stream()
.map(game::getPlayer)
.filter(Objects::nonNull)
.filter(Player::isInGame)
.map(Player::getLife)
.anyMatch(l -> ComparisonType.compare(l, comparisonType, amount));
case EACH_PLAYER:
return game.getState().getPlayersInRange(controller.getId(), game)
.stream()
.map(game::getPlayer)
.filter(Objects::nonNull)
.filter(Player::isInGame)
.map(Player::getLife)
.allMatch(l -> ComparisonType.compare(l, comparisonType, amount));
default:
throw new IllegalArgumentException("Unsupported TargetController in LifeCompareCondition: " + targetController);
}
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
switch (targetController) {
case YOU:
sb.append("you have ");
break;
case OPPONENT:
sb.append("an opponent has ");
break;
case ANY:
sb.append("a player has ");
break;
case EACH_PLAYER:
sb.append("each player has ");
break;
default:
throw new IllegalArgumentException("Unsupported TargetController in LifeCompareCondition: " + targetController);
}
switch (comparisonType) {
case MORE_THAN:
sb.append("more than ").append(amount);
break;
case FEWER_THAN:
sb.append("less than ").append(amount);
break;
case EQUAL_TO:
sb.append("exactly ").append(amount);
break;
case OR_GREATER:
sb.append(amount).append(" or more");
break;
case OR_LESS:
sb.append(amount).append(" or less");
break;
default:
throw new IllegalArgumentException("Unsupported ComparisonType in LifeCompareCondition: " + comparisonType);
}
sb.append(" life");
return sb.toString();
}
}

View file

@ -1,69 +0,0 @@
package mage.abilities.condition.common;
import mage.abilities.Ability;
import mage.abilities.condition.Condition;
import mage.game.Game;
import mage.players.Player;
import mage.players.PlayerList;
import java.util.UUID;
/**
*
* @author maurer.it_at_gmail.com
*/
public class XorLessLifeCondition implements Condition {
public enum CheckType { AN_OPPONENT, CONTROLLER, TARGET_OPPONENT, EACH_PLAYER }
private final CheckType type;
private final int amount;
public XorLessLifeCondition ( CheckType type , int amount) {
this.type = type;
this.amount = amount;
}
@Override
public boolean apply(Game game, Ability source) {
boolean conditionApplies = false;
/*
104.5. If a player loses the game, that player leaves the game.
Once a player leaves the game, their life check is no longer valid. IE Anya, Merciless Angel
*/
switch ( this.type ) {
case AN_OPPONENT:
for ( UUID opponentUUID : game.getOpponents(source.getControllerId()) ) {
conditionApplies |= game.getPlayer(opponentUUID).isInGame()
&& game.getPlayer(opponentUUID).getLife() <= amount;
}
break;
case CONTROLLER:
conditionApplies = game.getPlayer(source.getControllerId()).getLife() <= amount;
break;
case TARGET_OPPONENT:
//TODO: Implement this.
break;
case EACH_PLAYER:
int maxLife = 0;
PlayerList playerList = game.getState().getPlayersInRange(source.getControllerId(), game);
for ( UUID pid : playerList ) {
Player p = game.getPlayer(pid);
if (p != null
&& p.isInGame()) {
if (maxLife < p.getLife()) {
maxLife = p.getLife();
}
}
}
conditionApplies = maxLife <= amount;
break;
}
return conditionApplies;
}
}