diff --git a/forge-ai/src/main/java/forge/ai/ability/DamageDealAi.java b/forge-ai/src/main/java/forge/ai/ability/DamageDealAi.java index e54854afd96..9c22912d9b2 100644 --- a/forge-ai/src/main/java/forge/ai/ability/DamageDealAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/DamageDealAi.java @@ -392,8 +392,13 @@ public class DamageDealAi extends DamageAiBase { } continue; } + } else if ("OppAtTenLife".equals(sa.getParam("AILogic"))) { + for (final Player p : ai.getOpponents()) { + if (sa.canTarget(p) && p.getLife() == 10 && tcs.getNumTargeted() < tgt.getMaxTargets(source, sa)) { + tcs.add(p); + } + } } - // TODO: Improve Damage, we shouldn't just target the player just // because we can else if (sa.canTarget(enemy)) { diff --git a/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java b/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java index 784703b9aed..efdffdd4b6b 100644 --- a/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java +++ b/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java @@ -961,7 +961,17 @@ public class CardFactoryUtil { if (sq[0].contains("YourLifeTotal")) return doXMath(cc.getLife(), m, c); - if (sq[0].contains("OppLifeTotal")) return doXMath(ccOpp.getLife(), m, c); + if (sq[0].contains("OppGreatestLifeTotal")) return doXMath(cc.getOpponentsGreatestLifeTotal(), m, c); + if (sq[0].contains("OppsAtLifeTotal")) { + final int lifeTotal = xCount(c, sq[1]); + int number = 0; + for (final Player opp : cc.getOpponents()) { + if (opp.getLife() == lifeTotal) { + number++; + } + } + return doXMath(number, m, c); + } // Count$TargetedLifeTotal (targeted player's life total) if (sq[0].contains("TargetedLifeTotal")) { diff --git a/forge-game/src/main/java/forge/game/player/Player.java b/forge-game/src/main/java/forge/game/player/Player.java index 35a1320b724..64816d2f171 100644 --- a/forge-game/src/main/java/forge/game/player/Player.java +++ b/forge-game/src/main/java/forge/game/player/Player.java @@ -301,6 +301,22 @@ public class Player extends GameEntity implements Comparable { return result; } + /** + * Find the greatest life total amongst this player's opponents. + * + * @return the life total of the opponent with the most life. + */ + public final int getOpponentsGreatestLifeTotal() { + final List opps = this.getOpponents(); + int greatestLifeTotal = Integer.MIN_VALUE; + for (final Player p : opps) { + if (p.getLife() > greatestLifeTotal) { + greatestLifeTotal = p.getLife(); + } + } + return greatestLifeTotal; + } + /** * returns allied players. * Should keep player relations somewhere in the match structure @@ -2407,6 +2423,10 @@ public class Player extends GameEntity implements Comparable { if (this.getLife() != life) { return false; } + } else if (property.equals("IsPoisoned")) { + if (this.getPoisonCounters() <= 0) { + return false; + } } else if (property.startsWith("withMore")) { final String cardType = property.split("sThan")[0].substring(8); final Player controller = "Active".equals(property.split("sThan")[1]) ? game.getPhaseHandler().getPlayerTurn() : sourceController; @@ -2426,7 +2446,7 @@ public class Player extends GameEntity implements Comparable { return false; } } else if (property.startsWith("hasMore")) { - final Player controller = "Active".equals(property.split("Than")[1]) ? game.getPhaseHandler().getPlayerTurn() : sourceController; + final Player controller = property.contains("Than") && "Active".equals(property.split("Than")[1]) ? game.getPhaseHandler().getPlayerTurn() : sourceController; if (property.substring(7).startsWith("Life") && this.getLife() <= controller.getLife()) { return false; } else if (property.substring(7).startsWith("CardsInHand") diff --git a/forge-game/src/main/java/forge/game/staticability/StaticAbilityCantAttackBlock.java b/forge-game/src/main/java/forge/game/staticability/StaticAbilityCantAttackBlock.java index 04be9826689..00faf0509fa 100644 --- a/forge-game/src/main/java/forge/game/staticability/StaticAbilityCantAttackBlock.java +++ b/forge-game/src/main/java/forge/game/staticability/StaticAbilityCantAttackBlock.java @@ -79,6 +79,12 @@ public class StaticAbilityCantAttackBlock { && defender.equals(hostCard.getGame().getNextPlayerAfter(card.getController(), hostCard.getChosenDirection()))) { return false; } + if (params.containsKey("UnlessDefender")) { + final String type = params.get("UnlessDefender"); + if (defender.hasProperty(type, hostCard.getController(), hostCard)) { + return false; + } + } return true; } diff --git a/forge-gui/res/cardsfolder/c/chained_throatseeker.txt b/forge-gui/res/cardsfolder/c/chained_throatseeker.txt index 847bdf8b693..2af12641274 100644 --- a/forge-gui/res/cardsfolder/c/chained_throatseeker.txt +++ b/forge-gui/res/cardsfolder/c/chained_throatseeker.txt @@ -3,7 +3,6 @@ ManaCost:5 U Types:Creature Horror PT:5/5 K:Infect -S:Mode$ Continuous | Affected$ Card.Self | AddKeyword$ CARDNAME can't attack. | CheckSVar$ X | SVarCompare$ LE0 | Description$ CARDNAME can't attack unless defending player is poisoned. -SVar:X:Count$OppPoisonCounters +S:Mode$ CantAttack | ValidCard$ Card.Self | UnlessDefender$ IsPoisoned | Description$ CARDNAME can't attack unless defending player is poisoned. SVar:Picture:http://www.wizards.com/global/images/magic/general/chained_throatseeker.jpg Oracle:Infect (This creature deals damage to creatures in the form of -1/-1 counters and to players in the form of poison counters.)\nChained Throatseeker can't attack unless defending player is poisoned. diff --git a/forge-gui/res/cardsfolder/h/hidetsugus_second_rite.txt b/forge-gui/res/cardsfolder/h/hidetsugus_second_rite.txt index 225453024ea..34db28a77d7 100644 --- a/forge-gui/res/cardsfolder/h/hidetsugus_second_rite.txt +++ b/forge-gui/res/cardsfolder/h/hidetsugus_second_rite.txt @@ -1,9 +1,9 @@ Name:Hidetsugu's Second Rite ManaCost:3 R Types:Instant -A:SP$ DealDamage | Cost$ 3 R | ValidTgts$ Player | TgtPrompt$ Select target player | ConditionCheckSVar$ X | ConditionSVarCompare$ EQ10 | NumDmg$ 10 | References$ X | SpellDescription$ If target player has exactly 10 life, CARDNAME deals 10 damage to that player. +A:SP$ DealDamage | Cost$ 3 R | ValidTgts$ Player | TgtPrompt$ Select target player | ConditionCheckSVar$ X | ConditionSVarCompare$ EQ10 | NumDmg$ 10 | References$ X | AILogic$ OppAtTenLife | SpellDescription$ If target player has exactly 10 life, CARDNAME deals 10 damage to that player. SVar:X:TargetedPlayer$LifeTotal -SVar:Y:Count$OppLifeTotal -SVar:NeedsToPlayVar:Y EQ10 +SVar:Y:Count$OppsAtLifeTotal.10 +SVar:NeedsToPlayVar:Y GE1 SVar:Picture:http://resources.wizards.com/magic/cards/sok/en-us/card88818.jpg Oracle:If target player has exactly 10 life, Hidetsugu's Second Rite deals 10 damage to that player. diff --git a/forge-gui/res/cardsfolder/k/keeper_of_the_flame.txt b/forge-gui/res/cardsfolder/k/keeper_of_the_flame.txt index ff261fd232e..c5b61c4568a 100644 --- a/forge-gui/res/cardsfolder/k/keeper_of_the_flame.txt +++ b/forge-gui/res/cardsfolder/k/keeper_of_the_flame.txt @@ -2,8 +2,6 @@ Name:Keeper of the Flame ManaCost:R R Types:Creature Human Wizard PT:1/2 -A:AB$ DealDamage | Cost$ R T | ValidTgts$ Opponent | CheckSVar$ X | SVarCompare$ LTY | NumDmg$ 2 | References$ X,Y | SpellDescription$ Choose target opponent who had more life than you did as you activated this ability. CARDNAME deals 2 damage to him or her. -SVar:X:Count$YourLifeTotal -SVar:Y:Count$OppLifeTotal +A:AB$ DealDamage | Cost$ R T | ValidTgts$ Opponent.hasMoreLife | NumDmg$ 2 | SpellDescription$ Choose target opponent who had more life than you did as you activated this ability. CARDNAME deals 2 damage to him or her. SVar:Picture:http://www.wizards.com/global/images/magic/general/keeper_of_the_flame.jpg Oracle:{R}, {T}: Choose target opponent who had more life than you did as you activated this ability. Keeper of the Flame deals 2 damage to him or her. diff --git a/forge-gui/res/cardsfolder/k/keeper_of_the_light.txt b/forge-gui/res/cardsfolder/k/keeper_of_the_light.txt index 38bc7fae964..c7fcde7b115 100644 --- a/forge-gui/res/cardsfolder/k/keeper_of_the_light.txt +++ b/forge-gui/res/cardsfolder/k/keeper_of_the_light.txt @@ -2,9 +2,7 @@ Name:Keeper of the Light ManaCost:W W Types:Creature Human Wizard PT:1/2 -A:AB$ Pump | Cost$ W T | ValidTgts$ Opponent | TgtPrompt$ Choose target opponent with more life than you | CheckSVar$ X | SVarCompare$ LTY | SubAbility$ LightKeepersLife | StackDescription$ None | References$ X,Y | SpellDescription$ Choose target opponent who had more life than you did as you activated this ability. You gain 3 life. +A:AB$ Pump | Cost$ W T | ValidTgts$ Opponent.hasMoreLife | TgtPrompt$ Choose target opponent with more life than you | SubAbility$ LightKeepersLife | StackDescription$ None | SpellDescription$ Choose target opponent who had more life than you did as you activated this ability. You gain 3 life. SVar:LightKeepersLife:DB$ GainLife | Defined$ You | LifeAmount$ 3 -SVar:X:Count$YourLifeTotal -SVar:Y:Count$OppLifeTotal SVar:Picture:http://www.wizards.com/global/images/magic/general/keeper_of_the_light.jpg Oracle:{W}, {T}: Choose target opponent who had more life than you did as you activated this ability. You gain 3 life. diff --git a/forge-gui/res/cardsfolder/r/roiling_horror.txt b/forge-gui/res/cardsfolder/r/roiling_horror.txt index d9ae2d36cb0..d2be7ed4e33 100644 --- a/forge-gui/res/cardsfolder/r/roiling_horror.txt +++ b/forge-gui/res/cardsfolder/r/roiling_horror.txt @@ -10,7 +10,7 @@ SVar:TrigLoseLife:AB$ LoseLife | Cost$ 0 | ValidTgts$ Player | TgtPrompt$ Choose SVar:DBGainLife:DB$ GainLife | Defined$ You | LifeAmount$ 1 SVar:X:Count$xPaid SVar:Y:Count$YourLifeTotal/Minus.Z -SVar:Z:Count$OppLifeTotal +SVar:Z:Count$OppGreatestLifeTotal SVar:RemAIDeck:True SVar:Picture:http://www.wizards.com/global/images/magic/general/roiling_horror.jpg -Oracle:Roiling Horror's power and toughness are each equal to your life total minus the life total of an opponent with the most life.\nSuspend X-{X}{B}{B}{B}. X can't be 0. (Rather than cast this card from your hand, you may pay {X}{B}{B}{B} and exile it with X time counters on it. At the beginning of your upkeep, remove a time counter. When the last is removed, cast it without paying its mana cost. It has haste.)\nWhenever a time counter is removed from Roiling Horror while it's exiled, target player loses 1 life and you gain 1 life. +Oracle:Roiling Horror's power and toughness are each equal to your life total minus the life total of an opponent with the most life.\nSuspend X- {X}{B}{B}{B}. X can't be 0. (Rather than cast this card from your hand, you may pay {X}{B}{B}{B} and exile it with X time counters on it. At the beginning of your upkeep, remove a time counter. When the last is removed, cast it without paying its mana cost. It has haste.)\nWhenever a time counter is removed from Roiling Horror while it's exiled, target player loses 1 life and you gain 1 life.