mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-17 03:08:02 +00:00
- 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:
@@ -165,7 +165,7 @@ public class CreatureEvaluator implements Function<Card, Integer> {
|
|||||||
value -= subValue(30, "cupkeep");
|
value -= subValue(30, "cupkeep");
|
||||||
} else if (c.hasStartOfKeyword("At the beginning of your upkeep, sacrifice CARDNAME unless you pay")) {
|
} else if (c.hasStartOfKeyword("At the beginning of your upkeep, sacrifice CARDNAME unless you pay")) {
|
||||||
value -= subValue(20, "sac-unless");
|
value -= subValue(20, "sac-unless");
|
||||||
} else if (c.hasStartOfKeyword("Echo") && c.cameUnderControlSinceLastUpkeep()) {
|
} else if (c.hasStartOfKeyword("(Echo unpaid)")) {
|
||||||
value -= subValue(10, "echo-unpaid");
|
value -= subValue(10, "echo-unpaid");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -471,6 +471,9 @@ public class GameAction {
|
|||||||
oldBattlefield.remove(c);
|
oldBattlefield.remove(c);
|
||||||
newBattlefield.add(c);
|
newBattlefield.add(c);
|
||||||
c.setSickness(true);
|
c.setSickness(true);
|
||||||
|
if (c.hasStartOfKeyword("Echo")) {
|
||||||
|
c.addExtrinsicKeyword("(Echo unpaid)");
|
||||||
|
}
|
||||||
if (game.getPhaseHandler().inCombat()) {
|
if (game.getPhaseHandler().inCombat()) {
|
||||||
game.getCombat().removeFromCombat(c);
|
game.getCombat().removeFromCombat(c);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -138,7 +138,6 @@ public class Card extends GameEntity implements Comparable<Card> {
|
|||||||
private boolean drawnThisTurn = false;
|
private boolean drawnThisTurn = false;
|
||||||
private boolean becameTargetThisTurn = false;
|
private boolean becameTargetThisTurn = false;
|
||||||
private boolean startedTheTurnUntapped = false;
|
private boolean startedTheTurnUntapped = false;
|
||||||
private boolean underControlSinceLastUpkeep = true; // for Echo
|
|
||||||
private boolean tapped = false;
|
private boolean tapped = false;
|
||||||
private boolean sickness = true; // summoning sickness
|
private boolean sickness = true; // summoning sickness
|
||||||
private boolean token = false;
|
private boolean token = false;
|
||||||
@@ -207,6 +206,7 @@ public class Card extends GameEntity implements Comparable<Card> {
|
|||||||
private NavigableMap<Long, Player> tempControllers = new TreeMap<>();
|
private NavigableMap<Long, Player> tempControllers = new TreeMap<>();
|
||||||
|
|
||||||
private String originalText = "", text = "";
|
private String originalText = "", text = "";
|
||||||
|
private String echoCost = "";
|
||||||
private Cost miracleCost = null;
|
private Cost miracleCost = null;
|
||||||
private String chosenType = "";
|
private String chosenType = "";
|
||||||
private List<String> chosenColors;
|
private List<String> chosenColors;
|
||||||
@@ -1101,6 +1101,14 @@ public class Card extends GameEntity implements Comparable<Card> {
|
|||||||
turnInZone = turn;
|
turnInZone = turn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final void setEchoCost(final String s) {
|
||||||
|
echoCost = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final String getEchoCost() {
|
||||||
|
return echoCost;
|
||||||
|
}
|
||||||
|
|
||||||
public final void setManaCost(final ManaCost s) {
|
public final void setManaCost(final ManaCost s) {
|
||||||
currentState.setManaCost(s);
|
currentState.setManaCost(s);
|
||||||
}
|
}
|
||||||
@@ -2150,14 +2158,6 @@ public class Card extends GameEntity implements Comparable<Card> {
|
|||||||
public void setStartedTheTurnUntapped(boolean untapped) {
|
public void setStartedTheTurnUntapped(boolean untapped) {
|
||||||
startedTheTurnUntapped = untapped;
|
startedTheTurnUntapped = untapped;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean cameUnderControlSinceLastUpkeep() {
|
|
||||||
return underControlSinceLastUpkeep;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUnderControlSinceLastUpkeep(boolean underControlSinceLastUpkeep) {
|
|
||||||
this.underControlSinceLastUpkeep = underControlSinceLastUpkeep;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final Player getOwner() {
|
public final Player getOwner() {
|
||||||
return owner;
|
return owner;
|
||||||
@@ -4616,10 +4616,6 @@ public class Card extends GameEntity implements Comparable<Card> {
|
|||||||
if (!hasStartedTheTurnUntapped()) {
|
if (!hasStartedTheTurnUntapped()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (property.startsWith("cameUnderControlSinceLastUpkeep")) {
|
|
||||||
if (!cameUnderControlSinceLastUpkeep()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else if (property.equals("attackedOrBlockedSinceYourLastUpkeep")) {
|
} else if (property.equals("attackedOrBlockedSinceYourLastUpkeep")) {
|
||||||
if (!getDamageHistory().hasAttackedSinceLastUpkeepOf(sourceController)
|
if (!getDamageHistory().hasAttackedSinceLastUpkeepOf(sourceController)
|
||||||
&& !getDamageHistory().hasBlockedSinceLastUpkeepOf(sourceController)) {
|
&& !getDamageHistory().hasBlockedSinceLastUpkeepOf(sourceController)) {
|
||||||
|
|||||||
@@ -2306,18 +2306,19 @@ public class CardFactoryUtil {
|
|||||||
else if (keyword.startsWith("Echo")) {
|
else if (keyword.startsWith("Echo")) {
|
||||||
final String[] k = keyword.split(":");
|
final String[] k = keyword.split(":");
|
||||||
final String manacost = k[1];
|
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.setEchoCost(manacost);
|
||||||
card.setSVar("TrigUpkeepEcho", "AB$ Sacrifice | Cost$ 0 | SacValid$ Self | "
|
|
||||||
+ "Echo$ " + manacost + ref);
|
|
||||||
|
|
||||||
final Trigger parsedUpkeepTrig = TriggerHandler.parseTrigger(upkeepTrig, card, true);
|
final GameCommand intoPlay = new GameCommand() {
|
||||||
card.addTrigger(parsedUpkeepTrig);
|
|
||||||
|
private static final long serialVersionUID = -7913835645603984242L;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
card.addExtrinsicKeyword("(Echo unpaid)");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
card.addComesIntoPlayCommand(intoPlay);
|
||||||
}
|
}
|
||||||
else if (keyword.startsWith("Suspend")) {
|
else if (keyword.startsWith("Suspend")) {
|
||||||
card.removeIntrinsicKeyword(keyword);
|
card.removeIntrinsicKeyword(keyword);
|
||||||
|
|||||||
@@ -419,7 +419,6 @@ public class PhaseHandler implements java.io.Serializable {
|
|||||||
c.getDamageHistory().setNotAttackedSinceLastUpkeepOf(playerTurn);
|
c.getDamageHistory().setNotAttackedSinceLastUpkeepOf(playerTurn);
|
||||||
c.getDamageHistory().setNotBlockedSinceLastUpkeepOf(playerTurn);
|
c.getDamageHistory().setNotBlockedSinceLastUpkeepOf(playerTurn);
|
||||||
c.getDamageHistory().setNotBeenBlockedSinceLastUpkeepOf(playerTurn);
|
c.getDamageHistory().setNotBeenBlockedSinceLastUpkeepOf(playerTurn);
|
||||||
c.setUnderControlSinceLastUpkeep(true);
|
|
||||||
}
|
}
|
||||||
game.getUpkeep().executeUntilEndOfPhase(playerTurn);
|
game.getUpkeep().executeUntilEndOfPhase(playerTurn);
|
||||||
game.getUpkeep().registerUntilEndCommand(playerTurn);
|
game.getUpkeep().registerUntilEndCommand(playerTurn);
|
||||||
|
|||||||
@@ -17,12 +17,15 @@
|
|||||||
*/
|
*/
|
||||||
package forge.game.phase;
|
package forge.game.phase;
|
||||||
|
|
||||||
|
import com.google.common.base.Predicate;
|
||||||
|
|
||||||
import forge.card.mana.ManaCost;
|
import forge.card.mana.ManaCost;
|
||||||
import forge.game.Game;
|
import forge.game.Game;
|
||||||
import forge.game.ability.AbilityFactory;
|
import forge.game.ability.AbilityFactory;
|
||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
import forge.game.card.CardCollectionView;
|
import forge.game.card.CardCollectionView;
|
||||||
import forge.game.card.CardFactoryUtil;
|
import forge.game.card.CardFactoryUtil;
|
||||||
|
import forge.game.card.CardLists;
|
||||||
import forge.game.card.CounterType;
|
import forge.game.card.CounterType;
|
||||||
import forge.game.cost.Cost;
|
import forge.game.cost.Cost;
|
||||||
import forge.game.player.Player;
|
import forge.game.player.Player;
|
||||||
@@ -69,10 +72,42 @@ public class Upkeep extends Phase {
|
|||||||
game.getStack().freezeStack();
|
game.getStack().freezeStack();
|
||||||
|
|
||||||
Upkeep.upkeepUpkeepCost(game); // sacrifice unless upkeep cost is paid
|
Upkeep.upkeepUpkeepCost(game); // sacrifice unless upkeep cost is paid
|
||||||
|
Upkeep.upkeepEcho(game);
|
||||||
|
|
||||||
game.getStack().unfreezeStack();
|
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) {
|
private static void upkeepUpkeepCost(final Game game) {
|
||||||
final CardCollectionView list = game.getPhaseHandler().getPlayerTurn().getCardsIn(ZoneType.Battlefield);
|
final CardCollectionView list = game.getPhaseHandler().getPlayerTurn().getCardsIn(ZoneType.Battlefield);
|
||||||
|
|
||||||
|
|||||||
@@ -242,6 +242,30 @@ public class GameSimulatorTest extends TestCase {
|
|||||||
assertEquals(16, simGame.getPlayers().get(0).getLife());
|
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() {
|
public void testSimulateUnmorph() {
|
||||||
Game game = initAndCreateGame();
|
Game game = initAndCreateGame();
|
||||||
Player p = game.getPlayers().get(1);
|
Player p = game.getPlayers().get(1);
|
||||||
|
|||||||
Reference in New Issue
Block a user