diff --git a/forge-ai/src/main/java/forge/ai/CreatureEvaluator.java b/forge-ai/src/main/java/forge/ai/CreatureEvaluator.java index 437ca66ac1e..a6b04973743 100644 --- a/forge-ai/src/main/java/forge/ai/CreatureEvaluator.java +++ b/forge-ai/src/main/java/forge/ai/CreatureEvaluator.java @@ -165,7 +165,7 @@ public class CreatureEvaluator implements Function { value -= subValue(30, "cupkeep"); } else if (c.hasStartOfKeyword("At the beginning of your upkeep, sacrifice CARDNAME unless you pay")) { value -= subValue(20, "sac-unless"); - } else if (c.hasStartOfKeyword("(Echo unpaid)")) { + } else if (c.hasStartOfKeyword("Echo") && c.cameUnderControlSinceLastUpkeep()) { value -= subValue(10, "echo-unpaid"); } diff --git a/forge-game/src/main/java/forge/game/card/Card.java b/forge-game/src/main/java/forge/game/card/Card.java index 8810508aa38..c2f3b7727ef 100644 --- a/forge-game/src/main/java/forge/game/card/Card.java +++ b/forge-game/src/main/java/forge/game/card/Card.java @@ -138,6 +138,7 @@ public class Card extends GameEntity implements Comparable { private boolean drawnThisTurn = false; private boolean becameTargetThisTurn = false; private boolean startedTheTurnUntapped = false; + private boolean underControlSinceLastUpkeep = true; // for Echo private boolean tapped = false; private boolean sickness = true; // summoning sickness private boolean token = false; @@ -206,7 +207,6 @@ public class Card extends GameEntity implements Comparable { private NavigableMap tempControllers = new TreeMap<>(); private String originalText = "", text = ""; - private String echoCost = ""; private Cost miracleCost = null; private String chosenType = ""; private List chosenColors; @@ -1100,14 +1100,6 @@ public class Card extends GameEntity implements Comparable { turnInZone = turn; } - public final void setEchoCost(final String s) { - echoCost = s; - } - - public final String getEchoCost() { - return echoCost; - } - public final void setManaCost(final ManaCost s) { currentState.setManaCost(s); } @@ -2157,6 +2149,14 @@ public class Card extends GameEntity implements Comparable { public void setStartedTheTurnUntapped(boolean untapped) { startedTheTurnUntapped = untapped; } + + public boolean cameUnderControlSinceLastUpkeep() { + return underControlSinceLastUpkeep; + } + + public void setUnderControlSinceLastUpkeep(boolean underControlSinceLastUpkeep) { + this.underControlSinceLastUpkeep = underControlSinceLastUpkeep; + } public final Player getOwner() { return owner; @@ -4615,6 +4615,10 @@ public class Card extends GameEntity implements Comparable { if (!hasStartedTheTurnUntapped()) { return false; } + } else if (property.startsWith("cameUnderControlSinceLastUpkeep")) { + if (!cameUnderControlSinceLastUpkeep()) { + return false; + } } else if (property.equals("attackedOrBlockedSinceYourLastUpkeep")) { if (!getDamageHistory().hasAttackedSinceLastUpkeepOf(sourceController) && !getDamageHistory().hasBlockedSinceLastUpkeepOf(sourceController)) { diff --git a/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java b/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java index 6ba7b130cb1..c496e4d7d33 100644 --- a/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java +++ b/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java @@ -2306,19 +2306,18 @@ public class CardFactoryUtil { else if (keyword.startsWith("Echo")) { final String[] k = keyword.split(":"); final String manacost = k[1]; + + String upkeepTrig = "Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | TriggerZones$ Battlefield " + + " | Execute$ TrigUpkeepEcho | IsPresent$ Card.Self+cameUnderControlSinceLastUpkeep | Secondary$ True | " + + "TriggerDescription$ Echo: At the beginning of your upkeep, if CARDNAME came under your control since the " + + "beginning of your last upkeep, sacrifice it unless you pay the Echo cost"; - card.setEchoCost(manacost); + String ref = "X".equals(manacost) ? " | References$ X" : ""; + card.setSVar("TrigUpkeepEcho", "AB$ Sacrifice | Cost$ 0 | SacValid$ Self | " + + "Echo$ " + manacost + ref); - final GameCommand intoPlay = new GameCommand() { - - private static final long serialVersionUID = -7913835645603984242L; - - @Override - public void run() { - card.addExtrinsicKeyword("(Echo unpaid)"); - } - }; - card.addComesIntoPlayCommand(intoPlay); + final Trigger parsedUpkeepTrig = TriggerHandler.parseTrigger(upkeepTrig, card, true); + card.addTrigger(parsedUpkeepTrig); } else if (keyword.startsWith("Suspend")) { card.removeIntrinsicKeyword(keyword); diff --git a/forge-game/src/main/java/forge/game/phase/PhaseHandler.java b/forge-game/src/main/java/forge/game/phase/PhaseHandler.java index 1c9fc903851..a2d142229c3 100644 --- a/forge-game/src/main/java/forge/game/phase/PhaseHandler.java +++ b/forge-game/src/main/java/forge/game/phase/PhaseHandler.java @@ -419,6 +419,7 @@ public class PhaseHandler implements java.io.Serializable { c.getDamageHistory().setNotAttackedSinceLastUpkeepOf(playerTurn); c.getDamageHistory().setNotBlockedSinceLastUpkeepOf(playerTurn); c.getDamageHistory().setNotBeenBlockedSinceLastUpkeepOf(playerTurn); + c.setUnderControlSinceLastUpkeep(true); } game.getUpkeep().executeUntilEndOfPhase(playerTurn); game.getUpkeep().registerUntilEndCommand(playerTurn); diff --git a/forge-game/src/main/java/forge/game/phase/Upkeep.java b/forge-game/src/main/java/forge/game/phase/Upkeep.java index 306e03c0ea5..96e571e6977 100644 --- a/forge-game/src/main/java/forge/game/phase/Upkeep.java +++ b/forge-game/src/main/java/forge/game/phase/Upkeep.java @@ -17,15 +17,12 @@ */ package forge.game.phase; -import com.google.common.base.Predicate; - import forge.card.mana.ManaCost; import forge.game.Game; import forge.game.ability.AbilityFactory; import forge.game.card.Card; import forge.game.card.CardCollectionView; import forge.game.card.CardFactoryUtil; -import forge.game.card.CardLists; import forge.game.card.CounterType; import forge.game.cost.Cost; import forge.game.player.Player; @@ -72,42 +69,10 @@ public class Upkeep extends Phase { game.getStack().freezeStack(); Upkeep.upkeepUpkeepCost(game); // sacrifice unless upkeep cost is paid - Upkeep.upkeepEcho(game); game.getStack().unfreezeStack(); } - private static void upkeepEcho(final Game game) { - CardCollectionView list = game.getPhaseHandler().getPlayerTurn().getCardsIn(ZoneType.Battlefield); - list = CardLists.filter(list, new Predicate() { - @Override - public boolean apply(final Card c) { - return c.hasStartOfKeyword("(Echo unpaid)"); - } - }); - - for (int i = 0; i < list.size(); i++) { - final Card c = list.get(i); - if (c.hasStartOfKeyword("(Echo unpaid)")) { - final StringBuilder sb = new StringBuilder(); - sb.append("Echo for ").append(c).append("\n"); - String ref = "X".equals(c.getEchoCost()) ? " | References$ X" : ""; - String effect = "AB$ Sacrifice | Cost$ 0 | SacValid$ Self | " - + "Echo$ " + c.getEchoCost() + ref; - - SpellAbility sacAbility = AbilityFactory.getAbility(effect, c); - sacAbility.setTrigger(true); - sacAbility.setActivatingPlayer(c.getController()); - sacAbility.setStackDescription(sb.toString()); - sacAbility.setDescription(sb.toString()); - - game.getStack().addSimultaneousStackEntry(sacAbility); - - c.removeAllExtrinsicKeyword("(Echo unpaid)"); - } - } - } - private static void upkeepUpkeepCost(final Game game) { final CardCollectionView list = game.getPhaseHandler().getPlayerTurn().getCardsIn(ZoneType.Battlefield); diff --git a/forge-gui-desktop/src/test/java/forge/ai/simulation/GameSimulatorTest.java b/forge-gui-desktop/src/test/java/forge/ai/simulation/GameSimulatorTest.java index 93198b3b547..64b08c73306 100644 --- a/forge-gui-desktop/src/test/java/forge/ai/simulation/GameSimulatorTest.java +++ b/forge-gui-desktop/src/test/java/forge/ai/simulation/GameSimulatorTest.java @@ -242,30 +242,6 @@ public class GameSimulatorTest extends TestCase { assertEquals(16, simGame.getPlayers().get(0).getLife()); } - public void testEchoCostState() { - Game game = initAndCreateGame(); - Player p = game.getPlayers().get(1); - - String c1Name = "Acridian"; - String c2Name = "Goblin Patrol"; - Card c1 = addCard(c1Name, p); - Card c2 = addCard(c2Name, p); - - game.getPhaseHandler().devModeSet(PhaseType.MAIN2, p); - game.getAction().checkStateEffects(true); - - assertTrue(c1.hasStartOfKeyword("(Echo unpaid)")); - assertTrue(c2.hasStartOfKeyword("(Echo unpaid)")); - c2.removeAllExtrinsicKeyword("(Echo unpaid)"); - - GameSimulator sim = createSimulator(game, p); - Game simGame = sim.getSimulatedGameState(); - Card c1Copy = findCardWithName(simGame, c1Name); - assertTrue(c1Copy.hasStartOfKeyword("(Echo unpaid)")); - Card c2Copy = findCardWithName(simGame, c2Name); - assertFalse(c2Copy.hasStartOfKeyword("(Echo unpaid)")); - } - public void testSimulateUnmorph() { Game game = initAndCreateGame(); Player p = game.getPlayers().get(1);