From 9e81362ea45f9f9e1b1fc92fb3c518f50f61f59f Mon Sep 17 00:00:00 2001 From: xenohedron Date: Thu, 27 Jul 2023 00:23:27 -0400 Subject: [PATCH] Add logic to PlayerImpl for protection effects when damage can't be prevented (#10652) * add failing test * Check against prevent damage event when damaging player * Add back game log message --- .../continuous/ConditionalPreventionTest.java | 18 ++++++++++ .../main/java/mage/players/PlayerImpl.java | 35 +++++++++---------- 2 files changed, 35 insertions(+), 18 deletions(-) diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/continuous/ConditionalPreventionTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/ConditionalPreventionTest.java index ed2c429bdbf..4372a3c187d 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/continuous/ConditionalPreventionTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/ConditionalPreventionTest.java @@ -184,6 +184,24 @@ public class ConditionalPreventionTest extends CardTestPlayerBase { assertLife(playerB, 20 - 2); } + @Test + public void test_UnpreventableCombatDamageToPlayer() { + // Combat damage that would be dealt by creatures you control can't be prevented. + addCard(Zone.BATTLEFIELD, playerB, "Questing Beast", 1); + // When The One Ring enters the battlefield, if you cast it, you gain protection from everything until your next turn. + addCard(Zone.HAND, playerA, "The One Ring", 1); + addCard(Zone.BATTLEFIELD, playerA, "Island", 4); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "The One Ring"); + attack(2, playerB, "Questing Beast"); + + setStrictChooseMode(true); + setStopAt(2, PhaseStep.END_TURN); + execute(); + + assertLife(playerA, 20 - 4); // Damage should not be prevented + } + @Test public void test_PreventSomeDamage_Normal() { // Kicker-Sacrifice a land. diff --git a/Mage/src/main/java/mage/players/PlayerImpl.java b/Mage/src/main/java/mage/players/PlayerImpl.java index d6ceca2497e..321e04fbf87 100644 --- a/Mage/src/main/java/mage/players/PlayerImpl.java +++ b/Mage/src/main/java/mage/players/PlayerImpl.java @@ -2124,20 +2124,12 @@ public abstract class PlayerImpl implements Player, Serializable { if (damage < 1) { return 0; } - if (!canDamage(game.getObject(attackerId), game)) { - MageObject sourceObject = game.getObject(attackerId); - game.informPlayers(damage + " damage " - + (sourceObject == null ? "" : "from " + sourceObject.getLogName()) - + " to " + getLogName() - + (damage > 1 ? " were" : "was") + " prevented because of protection"); - return 0; - } DamageEvent event = new DamagePlayerEvent(playerId, attackerId, playerId, damage, preventable, combatDamage); event.setAppliedEffects(appliedEffects); if (game.replaceEvent(event)) { return 0; } - int actualDamage = event.getAmount(); + int actualDamage = checkProtectionAbilities(event, attackerId, source, game); if (actualDamage < 1) { return 0; } @@ -2200,6 +2192,22 @@ public abstract class PlayerImpl implements Player, Serializable { return actualDamage; } + private int checkProtectionAbilities(GameEvent event, UUID attackerId, Ability source, Game game) { + MageObject attacker = game.getObject(attackerId); + if (attacker != null && hasProtectionFrom(attacker, game)) { + GameEvent preventEvent = new PreventDamageEvent(playerId, attackerId, source, playerId, event.getAmount(), ((DamageEvent) event).isCombatDamage()); + if (!game.replaceEvent(preventEvent)) { + int preventedDamage = event.getAmount(); + event.setAmount(0); + game.fireEvent(new PreventedDamageEvent(playerId, attackerId, source, playerId, preventedDamage)); + game.informPlayers(preventedDamage + " damage from " + attacker.getLogName() + " to " + getLogName() + + (preventedDamage > 1 ? " were" : "was") + " prevented because of protection"); + return 0; + } + } + return event.getAmount(); + } + @Override public boolean addCounters(Counter counter, UUID playerAddingCounters, Ability source, Game game) { boolean returnCode = true; @@ -2267,15 +2275,6 @@ public abstract class PlayerImpl implements Player, Serializable { game.fireEvent(event); } - protected boolean canDamage(MageObject source, Game game) { - for (ProtectionAbility ability : abilities.getProtectionAbilities()) { - if (!ability.canTarget(source, game)) { - return false; - } - } - return true; - } - @Override public Abilities getAbilities() { return this.abilities;