From 1b830032ac09381c0b75484195c2a814be5c220d Mon Sep 17 00:00:00 2001 From: Oleg Agafonov Date: Sat, 19 Dec 2020 04:48:55 +0400 Subject: [PATCH] * Militant Angel - fixed rollback error on usage (#7239); --- .../cards/single/gnt/MilitantAngelTest.java | 73 +++++++++++++++++++ Mage/src/main/java/mage/watchers/Watcher.java | 20 +++-- 2 files changed, 87 insertions(+), 6 deletions(-) create mode 100644 Mage.Tests/src/test/java/org/mage/test/cards/single/gnt/MilitantAngelTest.java diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/gnt/MilitantAngelTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/gnt/MilitantAngelTest.java new file mode 100644 index 00000000000..0221ab5a935 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/gnt/MilitantAngelTest.java @@ -0,0 +1,73 @@ +package org.mage.test.cards.single.gnt; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.dynamicvalue.common.AttackedThisTurnOpponentsCount; +import mage.abilities.effects.Effect; +import mage.constants.PhaseStep; +import mage.constants.Zone; +import mage.game.Game; +import mage.players.Player; +import mage.watchers.common.PlayersAttackedThisTurnWatcher; +import org.junit.Assert; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestCommander4Players; + +/** + * @author JayDi85 + */ +public class MilitantAngelTest extends CardTestCommander4Players { + + @Test + public void test_AttackedThisTurnOpponentsCount() { + // Player order: A -> D -> C -> B + + // it's testing counter only (no need to test card -- it's same) + // When Militant Angel enters the battlefield, create a number of 2/2 white Knight creature tokens + // with vigilance equal to the number of opponents you attacked this turn. + //addCard(Zone.BATTLEFIELD, playerA, "Militant Angel", 2); + addCard(Zone.BATTLEFIELD, playerA, "Balduvian Bears", 1); + addCard(Zone.BATTLEFIELD, playerA, "Kitesail Corsair", 1); + + // turn 1: 2x attack -> 1 player = 1 value + mustHaveValue("2x->1 = 1", 1, PhaseStep.PRECOMBAT_MAIN, 0); + attack(1, playerA, "Balduvian Bears", playerB); + attack(1, playerA, "Kitesail Corsair", playerB); + mustHaveValue("2x->1 = 1", 1, PhaseStep.POSTCOMBAT_MAIN, 1); + + // between attacks - no value + mustHaveValue("no attacks = 0", 2, PhaseStep.PRECOMBAT_MAIN, 0); + + // turn 5: 2x attack -> 2 players = 2 value + mustHaveValue("2x->2 = 2", 5, PhaseStep.PRECOMBAT_MAIN, 0); + attack(5, playerA, "Balduvian Bears", playerB); + attack(5, playerA, "Kitesail Corsair", playerC); + mustHaveValue("2x->2 = 2", 5, PhaseStep.POSTCOMBAT_MAIN, 2); + runCode("watcher must be copyable", 5, PhaseStep.POSTCOMBAT_MAIN, playerA, (info, player, game) -> { + PlayersAttackedThisTurnWatcher watcher = game.getState().getWatcher(PlayersAttackedThisTurnWatcher.class); + PlayersAttackedThisTurnWatcher newWatcher = watcher.copy(); + Assert.assertEquals("old watcher", 2, watcher.getAttackedOpponentsCount(player.getId())); + Assert.assertEquals("new watcher", 2, newWatcher.getAttackedOpponentsCount(player.getId())); + }); + + // between attacks - no value + mustHaveValue("no attacks = 0", 6, PhaseStep.PRECOMBAT_MAIN, 0); + + setStrictChooseMode(true); + setStopAt(6, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + } + + private void mustHaveValue(String needInfo, int turnNum, PhaseStep step, int needValue) { + runCode(needInfo, turnNum, step, playerA, (info, player, game) -> { + assertCounterValue(info, player, game, needValue); + }); + } + + private void assertCounterValue(String checkName, Player player, Game game, int needValue) { + Ability fakeAbility = new SimpleStaticAbility((Effect) null); // dynamic value need ability's controllerId + fakeAbility.setControllerId(player.getId()); + Assert.assertEquals(checkName, needValue, AttackedThisTurnOpponentsCount.instance.calculate(game, fakeAbility, null)); + } +} diff --git a/Mage/src/main/java/mage/watchers/Watcher.java b/Mage/src/main/java/mage/watchers/Watcher.java index 2b75cba4d87..96743ceeb5a 100644 --- a/Mage/src/main/java/mage/watchers/Watcher.java +++ b/Mage/src/main/java/mage/watchers/Watcher.java @@ -1,12 +1,14 @@ package mage.watchers; +import mage.constants.WatcherScope; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.players.PlayerList; +import org.apache.log4j.Logger; + import java.io.Serializable; import java.lang.reflect.*; import java.util.*; -import mage.constants.WatcherScope; -import mage.game.Game; -import mage.game.events.GameEvent; -import org.apache.log4j.Logger; /** * watches for certain game events to occur and flags condition @@ -123,6 +125,14 @@ public abstract class Watcher implements Serializable { set.addAll(e.getValue()); target.put(e.getKey(), set); } + } else if (valueType.getTypeName().contains("PlayerList")) { + Map source = (Map) field.get(this); + Map target = (Map) field.get(watcher); + target.clear(); + for (Map.Entry e : source.entrySet()) { + PlayerList list = e.getValue().copy(); + target.put(e.getKey(), list); + } } else if (valueType.getTypeName().contains("List")) { Map> source = (Map>) field.get(this); Map> target = (Map>) field.get(watcher); @@ -141,14 +151,12 @@ public abstract class Watcher implements Serializable { map.putAll(e.getValue()); target.put(e.getKey(), map); } - } else { ((Map) field.get(watcher)).putAll((Map) field.get(this)); } } else if (field.getType() == List.class) { ((List) field.get(watcher)).clear(); ((List) field.get(watcher)).addAll((List) field.get(this)); - } else { field.set(watcher, field.get(this)); }