* Mana pay to cast - fixed random values in games with AI (example: Marath, Will of the Wild, see #8204);

This commit is contained in:
Oleg Agafonov 2021-09-04 20:34:32 +04:00
parent 3a8e04f2bc
commit 473a81e13c
3 changed files with 73 additions and 1 deletions

View file

@ -3,6 +3,9 @@ package org.mage.test.cards.single.c13;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import mage.counters.CounterType;
import mage.game.permanent.Permanent;
import mage.watchers.common.ManaPaidSourceWatcher;
import org.junit.Assert;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestCommanderDuelBase;
@ -31,6 +34,32 @@ public class MarathWillOfTheWildTest extends CardTestCommanderDuelBase {
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
checkPermanentCounters("after first cast must have 3x counters", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Marath, Will of the Wild", CounterType.P1P1, 3);
// COPY WATCHER testing (e.g. rollback compatible)
runCode("test copy watcher", 1, PhaseStep.PRECOMBAT_MAIN, playerA, (info, player, game) -> {
ManaPaidSourceWatcher watcher = game.getState().getWatcher(ManaPaidSourceWatcher.class);
Permanent perm = game.getBattlefield().getAllPermanents()
.stream()
.filter(p -> p.getName().equals("Marath, Will of the Wild"))
.findFirst()
.orElse(null);
Assert.assertNotNull(perm);
// check correct copy
int before = watcher.testsReturnTotal(perm);
Assert.assertEquals("original must have 3x", 3, before);
ManaPaidSourceWatcher copiedWatcher = watcher.copy();
int after = copiedWatcher.testsReturnTotal(perm);
Assert.assertEquals("copied must have 3x", before, after);
// check correct refs and changes
// simulate ai games (changes in copied watcher must not touch original watcher)
copiedWatcher.testsIncrementManaAmount(game, perm);
int afterChangeCopied = copiedWatcher.testsReturnTotal(perm);
int afterChangeOriginal = watcher.testsReturnTotal(perm);
Assert.assertEquals("after change, copied", 4, afterChangeCopied);
Assert.assertEquals("after change, original", 3, afterChangeOriginal);
});
// kill
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", "Marath, Will of the Wild");
setChoice(playerA, true); // move to command

View file

@ -5,6 +5,7 @@ import mage.constants.WatcherScope;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.players.PlayerList;
import mage.util.Copyable;
import org.apache.log4j.Logger;
import java.io.Serializable;
@ -142,6 +143,14 @@ public abstract class Watcher implements Serializable {
Cards list = e.getValue().copy();
target.put(e.getKey(), list);
}
} else if (Arrays.stream(((Class) valueType).getInterfaces()).anyMatch(c -> c.equals(Copyable.class))) {
Map<Object, Copyable> source = (Map<Object, Copyable>) field.get(this);
Map<Object, Copyable> target = (Map<Object, Copyable>) field.get(watcher);
target.clear();
for (Map.Entry<Object, Copyable> e : source.entrySet()) {
Copyable object = (Copyable) e.getValue().copy();
target.put(e.getKey(), object);
}
} else if (valueType.getTypeName().contains("List")) {
Map<Object, List<Object>> source = (Map<Object, List<Object>>) field.get(this);
Map<Object, List<Object>> target = (Map<Object, List<Object>>) field.get(watcher);
@ -161,6 +170,8 @@ public abstract class Watcher implements Serializable {
target.put(e.getKey(), map);
}
} else {
// TODO: add additional tests to find unsupported watcher data
((Map) field.get(watcher)).putAll((Map) field.get(this));
}
} else if (field.getType() == List.class) {

View file

@ -11,6 +11,7 @@ import mage.game.events.GameEvent;
import mage.game.events.ManaPaidEvent;
import mage.game.events.ZoneChangeEvent;
import mage.game.stack.Spell;
import mage.util.Copyable;
import mage.watchers.Watcher;
import java.io.Serializable;
@ -25,7 +26,8 @@ import java.util.UUID;
*/
public class ManaPaidSourceWatcher extends Watcher {
private static final class ManaPaidTracker implements Serializable {
private static final class ManaPaidTracker implements Serializable, Copyable<ManaPaidTracker> {
private int total = 0;
private int whiteSnow = 0;
private int blueSnow = 0;
@ -35,6 +37,26 @@ public class ManaPaidSourceWatcher extends Watcher {
private int colorlessSnow = 0;
private int treasure = 0;
private ManaPaidTracker() {
super();
}
private ManaPaidTracker(final ManaPaidTracker tracker) {
this.total = tracker.total;
this.whiteSnow = tracker.whiteSnow;
this.blueSnow = tracker.blueSnow;
this.blackSnow = tracker.blackSnow;
this.redSnow = tracker.redSnow;
this.greenSnow = tracker.greenSnow;
this.colorlessSnow = tracker.colorlessSnow;
this.treasure = tracker.treasure;
}
@Override
public ManaPaidTracker copy() {
return new ManaPaidTracker(this);
}
private void increment(MageObject sourceObject, ManaType manaType, Game game) {
total++;
if (sourceObject.hasSubtype(SubType.TREASURE, game)) {
@ -129,4 +151,14 @@ public class ManaPaidSourceWatcher extends Watcher {
ManaPaidSourceWatcher watcher = game.getState().getWatcher(ManaPaidSourceWatcher.class);
return watcher != null && watcher.manaMap.getOrDefault(spell.getSpellAbility().getId(), emptyTracker).checkSnowColor(spell, game);
}
public void testsIncrementManaAmount(Game game, MageObject mageObject) {
// for tests only (logic here: change data in tracker like real event do)
this.manaMap.getOrDefault(mageObject.getId(), null).increment(mageObject, ManaType.RED, game);
}
public int testsReturnTotal(MageObject mageObject) {
// for tests only
return this.manaMap.getOrDefault(mageObject.getId(), null).total;
}
}