Added additional test for prevent damage effects, improved 3358e2da80 (#6915)

This commit is contained in:
Oleg Agafonov 2020-08-06 21:16:59 +04:00
parent 3358e2da80
commit 2eeefd91ef
9 changed files with 137 additions and 64 deletions

View file

@ -1,16 +1,16 @@
package mage.cards.b; package mage.cards.b;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.BecomesTargetTriggeredAbility; import mage.abilities.common.BecomesTargetTriggeredAbility;
import mage.abilities.effects.ReplacementEffectImpl;
import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.DamageTargetEffect;
import mage.abilities.effects.common.continuous.DamageCantBePreventedEffect;
import mage.cards.AdventureCard; import mage.cards.AdventureCard;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.*; import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.SetTargetPointer;
import mage.constants.SubType;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.target.common.TargetAnyTarget; import mage.target.common.TargetAnyTarget;
import java.util.UUID; import java.util.UUID;
@ -34,7 +34,7 @@ public final class BonecrusherGiant extends AdventureCard {
// Stomp // Stomp
// Damage cant be prevented this turn. Stomp deals 2 damage to any target. // Damage cant be prevented this turn. Stomp deals 2 damage to any target.
this.getSpellCard().getSpellAbility().addEffect(new StompEffect()); this.getSpellCard().getSpellAbility().addEffect(new DamageCantBePreventedEffect(Duration.EndOfTurn, "Damage can't be prevented this turn", false, false));
this.getSpellCard().getSpellAbility().addEffect(new DamageTargetEffect(2)); this.getSpellCard().getSpellAbility().addEffect(new DamageTargetEffect(2));
this.getSpellCard().getSpellAbility().addTarget(new TargetAnyTarget()); this.getSpellCard().getSpellAbility().addTarget(new TargetAnyTarget());
} }
@ -47,36 +47,4 @@ public final class BonecrusherGiant extends AdventureCard {
public BonecrusherGiant copy() { public BonecrusherGiant copy() {
return new BonecrusherGiant(this); return new BonecrusherGiant(this);
} }
} }
class StompEffect extends ReplacementEffectImpl {
StompEffect() {
super(Duration.EndOfTurn, Outcome.Benefit);
staticText = "Damage can't be prevented this turn.";
}
private StompEffect(final StompEffect effect) {
super(effect);
}
@Override
public StompEffect copy() {
return new StompEffect(this);
}
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
return true;
}
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.PREVENT_DAMAGE;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
return true;
}
}

View file

@ -82,7 +82,7 @@ class QuestingBeastPreventionEffect extends ContinuousRuleModifyingEffectImpl {
QuestingBeastPreventionEffect() { QuestingBeastPreventionEffect() {
super(Duration.WhileOnBattlefield, Outcome.Benefit); super(Duration.WhileOnBattlefield, Outcome.Benefit);
staticText = "Combat damage that would be dealt by creatures you control can't be prevented."; staticText = "Combat damage that would be dealt by creatures you control can't be prevented";
} }
private QuestingBeastPreventionEffect(final QuestingBeastPreventionEffect effect) { private QuestingBeastPreventionEffect(final QuestingBeastPreventionEffect effect) {

View file

@ -80,8 +80,9 @@ class StormwildCapridorEffect extends PreventionEffectImpl {
if (permanent != null) { if (permanent != null) {
permanent.addCounters(CounterType.P1P1.createInstance(preventionEffectData.getPreventedDamage()), source, game); permanent.addCounters(CounterType.P1P1.createInstance(preventionEffectData.getPreventedDamage()), source, game);
} }
return true;
} }
return preventionEffectData.isReplaced(); return false;
} }
@Override @Override
@ -90,11 +91,8 @@ class StormwildCapridorEffect extends PreventionEffectImpl {
|| !super.applies(event, source, game)) { || !super.applies(event, source, game)) {
return false; return false;
} }
if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.PREVENT_DAMAGE, source.getSourceId(), source.getControllerId()))) { DamageCreatureEvent damageEvent = (DamageCreatureEvent) event;
DamageCreatureEvent damageEvent = (DamageCreatureEvent) event; return !damageEvent.isCombatDamage();
return !damageEvent.isCombatDamage();
}
return false;
} }
} }

View file

@ -135,7 +135,7 @@ public class ConditionalPreventionTest extends CardTestPlayerBase {
} }
@Test @Test
public void test_PrentableCombatDamage() { public void test_PreventableCombatDamage() {
// Prevent all damage that would be dealt to creatures. // Prevent all damage that would be dealt to creatures.
addCard(Zone.BATTLEFIELD, playerA, "Bubble Matrix", 1); addCard(Zone.BATTLEFIELD, playerA, "Bubble Matrix", 1);
addCard(Zone.BATTLEFIELD, playerA, "Balduvian Bears", 1); addCard(Zone.BATTLEFIELD, playerA, "Balduvian Bears", 1);
@ -190,4 +190,77 @@ public class ConditionalPreventionTest extends CardTestPlayerBase {
assertLife(playerA, 20); assertLife(playerA, 20);
assertLife(playerB, 20 - 2); assertLife(playerB, 20 - 2);
} }
@Test
public void test_PreventSomeDamage_Normal() {
// Kicker-Sacrifice a land.
// Prevent the next 3 damage that would be dealt this turn to any number of target creatures and/or players, divided as you choose.
// If Pollen Remedy was kicked, prevent the next 6 damage this way instead.
addCard(Zone.HAND, playerA, "Pollen Remedy", 1); // {W}
addCard(Zone.BATTLEFIELD, playerA, "Plains", 1);
addCard(Zone.HAND, playerA, "Swamp", 1); // for kicker
//
addCard(Zone.BATTLEFIELD, playerA, "Balduvian Bears", 1);
//
addCard(Zone.HAND, playerA, "Lightning Bolt", 3);
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3);
// add shield for 3 damage
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Pollen Remedy");
setChoice(playerA, "No"); // no kicker
addTargetAmount(playerA, "Balduvian Bears", 3);
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
checkGraveyardCount("shield", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Pollen Remedy", 1);
// 6 damage to die (if no shield then can cast only 1 bolt)
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", "Balduvian Bears");
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", "Balduvian Bears");
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA);
checkGraveyardCount("after", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", 2);
checkGraveyardCount("after", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Balduvian Bears", 1);
setStrictChooseMode(true);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertAllCommandsUsed();
}
@Test
public void test_PreventSomeDamage_Kicked() {
// Kicker-Sacrifice a land.
// Prevent the next 3 damage that would be dealt this turn to any number of target creatures and/or players, divided as you choose.
// If Pollen Remedy was kicked, prevent the next 6 damage this way instead.
addCard(Zone.HAND, playerA, "Pollen Remedy", 1); // {W}
addCard(Zone.BATTLEFIELD, playerA, "Plains", 1);
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1); // for kicker
//
addCard(Zone.BATTLEFIELD, playerA, "Balduvian Bears", 1);
//
addCard(Zone.HAND, playerA, "Lightning Bolt", 3);
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3);
// add shield for 6 damage
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Pollen Remedy");
setChoice(playerA, "Yes"); // use kicker
setChoice(playerA, "Swamp"); // kicker cost
addTargetAmount(playerA, "Balduvian Bears", 6);
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
checkGraveyardCount("shield", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Pollen Remedy", 1);
// 9 damage to die (if no shield then can cast only 1 bolt)
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", "Balduvian Bears");
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", "Balduvian Bears");
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", "Balduvian Bears");
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA);
checkGraveyardCount("after", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", 3);
checkGraveyardCount("after", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Balduvian Bears", 1);
setStrictChooseMode(true);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertAllCommandsUsed();
}
} }

View file

@ -650,4 +650,43 @@ public class AdventureCardsTest extends CardTestPlayerBase {
execute(); execute();
assertAllCommandsUsed(); assertAllCommandsUsed();
} }
@Test
public void test_BonecrusherGiant_Stopm() {
// bug with non working stopm: https://github.com/magefree/mage/issues/6915
// If noncombat damage would be dealt to Stormwild Capridor, prevent that damage.
// Put a +1/+1 counter on Stormwild Capridor for each 1 damage prevented this way.
addCard(Zone.BATTLEFIELD, playerA, "Stormwild Capridor@storm", 2); // 1/3
//
addCard(Zone.HAND, playerA, "Lightning Bolt", 2);
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2);
//
// Stomp {1}{R}
// Damage cant be prevented this turn. Stomp deals 2 damage to any target.
addCard(Zone.HAND, playerA, "Bonecrusher Giant", 1);
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2);
// prevent
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", "@storm.1");
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
checkGraveyardCount("prevent", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", 1);
checkGraveyardCount("prevent", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "@storm.1", 0);
// prepare protect by stomp
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Stomp");
addTarget(playerA, playerB);
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
// can't prevent
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", "@storm.2");
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
checkGraveyardCount("can't prevent", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", 2);
checkGraveyardCount("can't prevent", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "@storm.2", 1);
setStrictChooseMode(true);
setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
execute();
assertAllCommandsUsed();
}
} }

View file

@ -2450,7 +2450,7 @@ public class TestPlayer implements Player {
//Assert.fail("Wrong target"); //Assert.fail("Wrong target");
} }
this.chooseStrictModeFailed("target", game, getInfo(source, game) + "; " + getInfo(target)); this.chooseStrictModeFailed("target", game, getInfo(source, game) + "\n" + getInfo(target));
return computerPlayer.chooseTarget(outcome, cards, target, source, game); return computerPlayer.chooseTarget(outcome, cards, target, source, game);
} }
@ -3760,7 +3760,7 @@ public class TestPlayer implements Player {
} }
} }
this.chooseStrictModeFailed("target", game, getInfo(source, game) + "; " + getInfo(target)); this.chooseStrictModeFailed("target", game, getInfo(source, game) + "\n" + getInfo(target));
return computerPlayer.chooseTargetAmount(outcome, target, source, game); return computerPlayer.chooseTargetAmount(outcome, target, source, game);
} }

View file

@ -287,7 +287,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
} }
} }
Assert.assertFalse("Wrong stop command on " + this.stopOnTurn + " / " + this.stopAtStep + " (" + this.stopAtStep.getIndex() + ")" Assert.assertFalse("Wrong stop command on " + this.stopOnTurn + " / " + this.stopAtStep + " (" + this.stopAtStep.getIndex() + ")"
+ " (found actions after stop on " + maxTurn + " / " + maxPhase + ")", + " (found actions after stop on " + maxTurn + " / " + maxPhase + ")",
(maxTurn > this.stopOnTurn) || (maxTurn == this.stopOnTurn && maxPhase > this.stopAtStep.getIndex())); (maxTurn > this.stopOnTurn) || (maxTurn == this.stopOnTurn && maxPhase > this.stopAtStep.getIndex()));
if (!currentGame.isPaused()) { if (!currentGame.isPaused()) {
@ -916,7 +916,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
} }
Assert.assertNotNull("There is no such permanent under player's control, player=" + player.getName() Assert.assertNotNull("There is no such permanent under player's control, player=" + player.getName()
+ ", cardName=" + cardName, found); + ", cardName=" + cardName, found);
Assert.assertEquals(amount, found.getAbilities(currentGame).stream() Assert.assertEquals(amount, found.getAbilities(currentGame).stream()
.filter(a -> searchedAbility.isAssignableFrom(a.getClass())).collect(Collectors.toList()).size()); .filter(a -> searchedAbility.isAssignableFrom(a.getClass())).collect(Collectors.toList()).size());
} }
@ -1619,9 +1619,10 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
* @param step * @param step
* @param player * @param player
* @param cardName * @param cardName
* @param targetName for modes you can add "mode=3" before target name, * @param targetName for modes you can add "mode=3" before target name;
* multiple targets can be seperated by ^, not target * multiple targets can be seperated by ^;
* marks as TestPlayer.NO_TARGET * no target marks as TestPlayer.NO_TARGET;
* warning, do not support cards with target adjusters - use addTarget instead
*/ */
public void castSpell(int turnNum, PhaseStep step, TestPlayer player, String cardName, String targetName) { public void castSpell(int turnNum, PhaseStep step, TestPlayer player, String cardName, String targetName) {
//Assert.assertNotEquals("", cardName); //Assert.assertNotEquals("", cardName);

View file

@ -8,6 +8,7 @@ import mage.game.Game;
import mage.game.events.GameEvent; import mage.game.events.GameEvent;
public class DamageCantBePreventedEffect extends ContinuousRuleModifyingEffectImpl { public class DamageCantBePreventedEffect extends ContinuousRuleModifyingEffectImpl {
public DamageCantBePreventedEffect(Duration duration, String staticText, boolean messageToUser, boolean messageToLog) { public DamageCantBePreventedEffect(Duration duration, String staticText, boolean messageToUser, boolean messageToLog) {
super(duration, Outcome.Benefit, messageToUser, messageToLog); super(duration, Outcome.Benefit, messageToUser, messageToLog);
this.staticText = staticText; this.staticText = staticText;

View file

@ -12,14 +12,7 @@ import mage.game.events.GameEvent.EventType;
import mage.players.Player; import mage.players.Player;
import mage.util.RandomUtil; import mage.util.RandomUtil;
import java.util.ArrayList; import java.util.*;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
/** /**
* @author BetaSteward_at_googlemail.com * @author BetaSteward_at_googlemail.com
@ -112,9 +105,9 @@ public abstract class TargetImpl implements Target {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.append("Select ").append(targetName); sb.append("Select ").append(targetName);
if (getMaxNumberOfTargets() > 0 && getMaxNumberOfTargets() != Integer.MAX_VALUE) { if (getMaxNumberOfTargets() > 0 && getMaxNumberOfTargets() != Integer.MAX_VALUE) {
sb.append(" (").append(targets.size()).append('/').append(getMaxNumberOfTargets()).append(')'); sb.append(" (selected ").append(targets.size()).append(" of ").append(getMaxNumberOfTargets()).append(')');
} else { } else {
sb.append(" (").append(targets.size()).append(')'); sb.append(" (selected ").append(targets.size()).append(')');
} }
sb.append(suffix); sb.append(suffix);
return sb.toString(); return sb.toString();