- Temporarily reverted 30117:30118 (related to Echo update) because the current new implementation misbehaves (please see the related forum post) and I could not fix the rule interaction bug in a timely manner.

- Feel free to revert this commit and continue working on the new Echo implementation.
This commit is contained in:
Agetian
2015-09-27 06:00:21 +00:00
parent 5f4b9480e7
commit 273e71cc0a
7 changed files with 83 additions and 25 deletions

View File

@@ -165,7 +165,7 @@ public class CreatureEvaluator implements Function<Card, Integer> {
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") && c.cameUnderControlSinceLastUpkeep()) {
} else if (c.hasStartOfKeyword("(Echo unpaid)")) {
value -= subValue(10, "echo-unpaid");
}

View File

@@ -471,6 +471,9 @@ public class GameAction {
oldBattlefield.remove(c);
newBattlefield.add(c);
c.setSickness(true);
if (c.hasStartOfKeyword("Echo")) {
c.addExtrinsicKeyword("(Echo unpaid)");
}
if (game.getPhaseHandler().inCombat()) {
game.getCombat().removeFromCombat(c);
}

View File

@@ -138,7 +138,6 @@ public class Card extends GameEntity implements Comparable<Card> {
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;
@@ -207,6 +206,7 @@ public class Card extends GameEntity implements Comparable<Card> {
private NavigableMap<Long, Player> tempControllers = new TreeMap<>();
private String originalText = "", text = "";
private String echoCost = "";
private Cost miracleCost = null;
private String chosenType = "";
private List<String> chosenColors;
@@ -1101,6 +1101,14 @@ public class Card extends GameEntity implements Comparable<Card> {
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);
}
@@ -2150,14 +2158,6 @@ public class Card extends GameEntity implements Comparable<Card> {
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;
@@ -4616,10 +4616,6 @@ public class Card extends GameEntity implements Comparable<Card> {
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)) {

View File

@@ -2306,18 +2306,19 @@ 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";
String ref = "X".equals(manacost) ? " | References$ X" : "";
card.setSVar("TrigUpkeepEcho", "AB$ Sacrifice | Cost$ 0 | SacValid$ Self | "
+ "Echo$ " + manacost + ref);
card.setEchoCost(manacost);
final Trigger parsedUpkeepTrig = TriggerHandler.parseTrigger(upkeepTrig, card, true);
card.addTrigger(parsedUpkeepTrig);
final GameCommand intoPlay = new GameCommand() {
private static final long serialVersionUID = -7913835645603984242L;
@Override
public void run() {
card.addExtrinsicKeyword("(Echo unpaid)");
}
};
card.addComesIntoPlayCommand(intoPlay);
}
else if (keyword.startsWith("Suspend")) {
card.removeIntrinsicKeyword(keyword);

View File

@@ -419,7 +419,6 @@ 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);

View File

@@ -17,12 +17,15 @@
*/
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;
@@ -69,10 +72,42 @@ 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<Card>() {
@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);

View File

@@ -242,6 +242,30 @@ 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);