From 69f9331d876f93444bba5ec70d42ea05ee9405b8 Mon Sep 17 00:00:00 2001 From: Alex Vasile <48962821+Alex-Vasile@users.noreply.github.com> Date: Fri, 8 Jul 2022 21:40:05 -0400 Subject: [PATCH] [AFC] Fix OneOrMoreDiceRolledTriggeredAbility to not trigger from Chaos Dragon (#9201) --- .../afr/VrondissRageOfAncientsTest.java | 46 +++++++++++++++++++ .../OneOrMoreDiceRolledTriggeredAbility.java | 4 +- .../mage/game/events/DiceRolledEvent.java | 16 ++++++- .../java/mage/game/events/RollDiceEvent.java | 18 +++++++- .../java/mage/game/events/RollDieEvent.java | 17 ++++++- .../main/java/mage/players/PlayerImpl.java | 6 +-- 6 files changed, 97 insertions(+), 10 deletions(-) create mode 100644 Mage.Tests/src/test/java/org/mage/test/cards/single/afr/VrondissRageOfAncientsTest.java diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/afr/VrondissRageOfAncientsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/afr/VrondissRageOfAncientsTest.java new file mode 100644 index 0000000000..482e8d1fa9 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/afr/VrondissRageOfAncientsTest.java @@ -0,0 +1,46 @@ +package org.mage.test.cards.single.afr; + +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestMultiPlayerBase; + +/** + * {@link VrondissRageOfAncientsTest Vrondriss, Rage of Ancients} + * Enrage — Whenever Vrondiss, Rage of Ancients is dealt damage, + * you may create a 5/4 red and green Dragon Spirit creature token with + * “When this creature deals damage, sacrifice it.” + * Whenever you roll one or more dice, you may have Vrondiss deal 1 damage to itself. + */ +public class VrondissRageOfAncientsTest extends CardTestMultiPlayerBase { + + /** + * Reported bug: https://github.com/magefree/mage/issues/8189 + * + * Chaos Dragon attacking would cause Vrondiss to trigger off of every player's roll, not just Vrondiss' controller. + * + * {@link mage.cards.c.ChaosDragon Chaos Dragon} + * At the beginning of combat on your turn, each player rolls a d20. + * If one or more opponents had the highest result, + * Chaos Dragon can’t attack those players or planeswalkers they control this combat. + */ + @Test + public void testChaosDragonInteraction() { + addCard(Zone.BATTLEFIELD, playerA, "Vrondiss, Rage of Ancients"); + addCard(Zone.BATTLEFIELD, playerA, "Chaos Dragon"); + + setStrictChooseMode(true); + + attack(1, playerA, "Chaos Dragon", playerB); + setDieRollResult(playerA, 10); + setDieRollResult(playerB, 11); + // setDieRollResult(playerC, 12); NOTE: Range of influence of 1, so playerC does not have to roll + setDieRollResult(playerD, 13); + + // Set choice for Vrondiss triggered ability + setChoice(playerA, "No"); + // Should only be one trigger since it should only trigger off of playerA's roll + + execute(); + assertAllCommandsUsed(); + } +} diff --git a/Mage/src/main/java/mage/abilities/common/OneOrMoreDiceRolledTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/OneOrMoreDiceRolledTriggeredAbility.java index 28b0aa6b99..1afeb97784 100644 --- a/Mage/src/main/java/mage/abilities/common/OneOrMoreDiceRolledTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/OneOrMoreDiceRolledTriggeredAbility.java @@ -8,6 +8,8 @@ import mage.game.events.DiceRolledEvent; import mage.game.events.GameEvent; /** + * Controller rolls one or more dice. + * * @author weirddan455 */ public class OneOrMoreDiceRolledTriggeredAbility extends TriggeredAbilityImpl { @@ -36,7 +38,7 @@ public class OneOrMoreDiceRolledTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { - if (!isControlledBy(event.getPlayerId())) { + if (!isControlledBy(event.getTargetId())) { return false; } int maxRoll = ((DiceRolledEvent) event) diff --git a/Mage/src/main/java/mage/game/events/DiceRolledEvent.java b/Mage/src/main/java/mage/game/events/DiceRolledEvent.java index 1c4a0b51fd..8c01ea8fa4 100644 --- a/Mage/src/main/java/mage/game/events/DiceRolledEvent.java +++ b/Mage/src/main/java/mage/game/events/DiceRolledEvent.java @@ -4,6 +4,7 @@ import mage.abilities.Ability; import java.util.ArrayList; import java.util.List; +import java.util.UUID; /** * @author TheElk801 @@ -13,8 +14,19 @@ public class DiceRolledEvent extends GameEvent { private final int sides; private final List results = new ArrayList<>(); // Integer for numerical and PlanarDieRollResult for planar - public DiceRolledEvent(int sides, List results, Ability source) { - super(EventType.DICE_ROLLED, source.getControllerId(), source, source.getControllerId()); + /** + * The target ID is used to keep track of the distinction between the player who controls the ability that + * started the dice roll and the player who does the rolling. + *

+ * The only times this distinction matters is for Chaos Dragon and Ricochet. + * + * @param sides + * @param results + * @param source + * @param targetId The player who rolled the die + */ + public DiceRolledEvent(int sides, List results, Ability source, UUID targetId) { + super(EventType.DICE_ROLLED, targetId, source, source.getControllerId()); this.sides = sides; this.results.addAll(results); } diff --git a/Mage/src/main/java/mage/game/events/RollDiceEvent.java b/Mage/src/main/java/mage/game/events/RollDiceEvent.java index ce45e477ac..ddb309759c 100644 --- a/Mage/src/main/java/mage/game/events/RollDiceEvent.java +++ b/Mage/src/main/java/mage/game/events/RollDiceEvent.java @@ -4,6 +4,8 @@ import mage.abilities.Ability; import mage.constants.RollDieType; import mage.util.CardUtil; +import java.util.UUID; + /** * @author TheElk801 */ @@ -13,8 +15,20 @@ public class RollDiceEvent extends GameEvent { private int ignoreLowestAmount = 0; // ignore the lowest results private final RollDieType rollDieType; - public RollDiceEvent(Ability source, RollDieType rollDieType, int sides, int rollsAmount) { - super(EventType.ROLL_DICE, source.getControllerId(), source, source.getControllerId(), rollsAmount, false); + /** + * The target ID is used to keep track of the distinction between the player who controls the ability that + * started the dice roll and the player who does the rolling. + *

+ * The only times this distinction matters is for Chaos Dragon and Ricochet. + * + * @param source + * @param targetId The player who is rolling the die + * @param rollDieType + * @param sides + * @param rollsAmount + */ + public RollDiceEvent(Ability source, UUID targetId, RollDieType rollDieType, int sides, int rollsAmount) { + super(EventType.ROLL_DICE, targetId, source, source.getControllerId(), rollsAmount, false); this.sides = sides; this.rollDieType = rollDieType; } diff --git a/Mage/src/main/java/mage/game/events/RollDieEvent.java b/Mage/src/main/java/mage/game/events/RollDieEvent.java index 8dee325adc..7cc81b335d 100644 --- a/Mage/src/main/java/mage/game/events/RollDieEvent.java +++ b/Mage/src/main/java/mage/game/events/RollDieEvent.java @@ -4,6 +4,8 @@ import mage.abilities.Ability; import mage.constants.RollDieType; import mage.util.CardUtil; +import java.util.UUID; + /** * @author TheElk801 */ @@ -16,8 +18,19 @@ public class RollDieEvent extends GameEvent { private int rollsAmount = 1; // rolls X times and choose result from it private int bigIdeaRollsAmount = 0; // rolls 2x and sum result - public RollDieEvent(Ability source, RollDieType rollDieType, int sides) { - super(EventType.ROLL_DIE, source.getControllerId(), source, source.getControllerId()); + /** + * The target ID is used to keep track of the distinction between the player who controls the ability that + * started the dice roll and the player who does the rolling. + *

+ * The only times this distinction matters is for Chaos Dragon and Ricochet. + * + * @param source + * @param targetId The player rolling the die + * @param rollDieType + * @param sides + */ + public RollDieEvent(Ability source, UUID targetId, RollDieType rollDieType, int sides) { + super(EventType.ROLL_DIE, targetId, source, source.getControllerId()); this.rollDieType = rollDieType; this.sides = sides; } diff --git a/Mage/src/main/java/mage/players/PlayerImpl.java b/Mage/src/main/java/mage/players/PlayerImpl.java index cf6619bd5c..d20e17702f 100644 --- a/Mage/src/main/java/mage/players/PlayerImpl.java +++ b/Mage/src/main/java/mage/players/PlayerImpl.java @@ -3062,7 +3062,7 @@ public abstract class PlayerImpl implements Player, Serializable { private List rollDiceInner(Outcome outcome, Ability source, Game game, RollDieType rollDieType, int sidesAmount, int chaosSidesAmount, int planarSidesAmount, int rollsAmount, int ignoreLowestAmount) { - RollDiceEvent rollDiceEvent = new RollDiceEvent(source, rollDieType, sidesAmount, rollsAmount); + RollDiceEvent rollDiceEvent = new RollDiceEvent(source, this.getId(), rollDieType, sidesAmount, rollsAmount); if (ignoreLowestAmount > 0) { rollDiceEvent.incIgnoreLowestAmount(ignoreLowestAmount); } @@ -3079,7 +3079,7 @@ public abstract class PlayerImpl implements Player, Serializable { List dieRolls = new ArrayList<>(); for (int i = 0; i < rollDiceEvent.getAmount(); i++) { // ROLL SINGLE die - RollDieEvent rollDieEvent = new RollDieEvent(source, rollDiceEvent.getRollDieType(), rollDiceEvent.getSides()); + RollDieEvent rollDieEvent = new RollDieEvent(source, this.getId(), rollDiceEvent.getRollDieType(), rollDiceEvent.getSides()); game.replaceEvent(rollDieEvent); Object rollResult; @@ -3186,7 +3186,7 @@ public abstract class PlayerImpl implements Player, Serializable { for (RollDieResult result : dieRolls) { game.fireEvent(new DieRolledEvent(source, rollDiceEvent.getRollDieType(), rollDiceEvent.getSides(), result.naturalResult, result.modifier, result.planarResult)); } - game.fireEvent(new DiceRolledEvent(rollDiceEvent.getSides(), dieResults, source)); + game.fireEvent(new DiceRolledEvent(rollDiceEvent.getSides(), dieResults, source, this.getId())); String resultString = dieResults .stream()