use StaticAbility for Topsy Turvy (#7143)

This commit is contained in:
Hans Mackowiak
2025-03-12 09:24:53 +01:00
committed by GitHub
parent fbff1fe10a
commit 137d87c3df
8 changed files with 68 additions and 18 deletions

View File

@@ -522,7 +522,7 @@ public class Game {
* The Direction in which the turn order of this Game currently proceeds. * The Direction in which the turn order of this Game currently proceeds.
*/ */
public final Direction getTurnOrder() { public final Direction getTurnOrder() {
if (phaseHandler.getPlayerTurn() != null && phaseHandler.getPlayerTurn().getAmountOfKeyword("The turn order is reversed.") % 2 == 1) { if (phaseHandler.getPlayerTurn() != null && phaseHandler.getPlayerTurn().isTurnOrderReversed()) {
return turnOrder.getOtherDirection(); return turnOrder.getOtherDirection();
} }
return turnOrder; return turnOrder;

View File

@@ -25,7 +25,7 @@ public class AddPhaseEffect extends SpellAbilityEffect {
public void resolve(SpellAbility sa) { public void resolve(SpellAbility sa) {
final Card host = sa.getHostCard(); final Card host = sa.getHostCard();
final Player activator = sa.getActivatingPlayer(); final Player activator = sa.getActivatingPlayer();
boolean isTopsy = activator.getAmountOfKeyword("The phases of your turn are reversed.") % 2 == 1; boolean isTopsy = activator.isPhasesReversed();
PhaseHandler phaseHandler = activator.getGame().getPhaseHandler(); PhaseHandler phaseHandler = activator.getGame().getPhaseHandler();
PhaseType currentPhase = phaseHandler.getPhase(); PhaseType currentPhase = phaseHandler.getPhase();

View File

@@ -303,6 +303,6 @@ public class FlipCoinEffect extends SpellAbilityEffect {
public static int getFlipMultiplier(final Player flipper) { public static int getFlipMultiplier(final Player flipper) {
String str = "If you would flip a coin, instead flip two coins and ignore one."; String str = "If you would flip a coin, instead flip two coins and ignore one.";
return 1 << flipper.getKeywords().getAmount(str); return 1 << flipper.getAmountOfKeyword(str);
} }
} }

View File

@@ -142,7 +142,7 @@ public class PhaseHandler implements java.io.Serializable {
private void advanceToNextPhase() { private void advanceToNextPhase() {
PhaseType oldPhase = phase; PhaseType oldPhase = phase;
boolean isTopsy = playerTurn.getAmountOfKeyword("The phases of your turn are reversed.") % 2 == 1; boolean isTopsy = playerTurn.isPhasesReversed();
boolean turnEnded = false; boolean turnEnded = false;
game.getStack().clearUndoStack(); //can't undo action from previous phase game.getStack().clearUndoStack(); //can't undo action from previous phase
@@ -1165,7 +1165,7 @@ public class PhaseHandler implements java.io.Serializable {
return devAdvanceToPhase(targetPhase, null); return devAdvanceToPhase(targetPhase, null);
} }
public final boolean devAdvanceToPhase(PhaseType targetPhase, Runnable resolver) { public final boolean devAdvanceToPhase(PhaseType targetPhase, Runnable resolver) {
boolean isTopsy = playerTurn.getAmountOfKeyword("The phases of your turn are reversed.") % 2 == 1; boolean isTopsy = playerTurn.isPhasesReversed();
while (phase.isBefore(targetPhase, isTopsy)) { while (phase.isBefore(targetPhase, isTopsy)) {
if (checkStateBasedEffects()) { if (checkStateBasedEffects()) {
return false; return false;

View File

@@ -2232,7 +2232,7 @@ public class Player extends GameEntity implements Comparable<Player> {
numManaConversion = l; numManaConversion = l;
} }
public final boolean hasManaConversion() { public final boolean hasManaConversion() {
return numManaConversion < keywords.getAmount("You may spend mana as though" return numManaConversion < getAmountOfKeyword("You may spend mana as though"
+ " it were mana of any type to cast a spell this turn."); + " it were mana of any type to cast a spell this turn.");
} }
public final void incNumManaConversion() { public final void incNumManaConversion() {
@@ -2547,6 +2547,13 @@ public class Player extends GameEntity implements Comparable<Player> {
return keywords.getAmount(k); return keywords.getAmount(k);
} }
public boolean isTurnOrderReversed() {
return StaticAbilityTurnPhaseReversed.isTurnReversed(this);
}
public boolean isPhasesReversed() {
return StaticAbilityTurnPhaseReversed.isPhaseReversed(this);
}
public void onCleanupPhase() { public void onCleanupPhase() {
for (Card c : getCardsIn(ZoneType.Hand)) { for (Card c : getCardsIn(ZoneType.Hand)) {
c.setDrawnThisTurn(false); c.setDrawnThisTurn(false);

View File

@@ -0,0 +1,43 @@
package forge.game.staticability;
import forge.game.Game;
import forge.game.card.Card;
import forge.game.player.Player;
import forge.game.zone.ZoneType;
public class StaticAbilityTurnPhaseReversed {
static String TURN_MODE = "TurnReversed";
static String PHASE_MODE = "PhaseReversed";
public static boolean isTurnReversed(Player player) {
return anyTurnPhaseReversed(player, TURN_MODE);
}
public static boolean isPhaseReversed(Player player) {
return anyTurnPhaseReversed(player, PHASE_MODE);
}
protected static boolean anyTurnPhaseReversed(Player player, final String mode)
{
boolean result = false;
final Game game = player.getGame();
for (final Card ca : game.getCardsIn(ZoneType.STATIC_ABILITIES_SOURCE_ZONES)) {
for (final StaticAbility stAb : ca.getStaticAbilities()) {
if (!stAb.checkConditions(mode)) {
continue;
}
if (applyTurnPhaseReversed(stAb, player)) {
result = !result;
}
}
}
return result;
}
protected static boolean applyTurnPhaseReversed(StaticAbility stAb, Player player) {
if (!stAb.matchesValidParam("ValidPlayer", player)) {
return false;
}
return true;
}
}

View File

@@ -75,7 +75,7 @@ public class GameSimulationTest extends SimulationTest {
game.getAction().checkStateEffects(true); game.getAction().checkStateEffects(true);
game.getAction().checkStateEffects(true); game.getAction().checkStateEffects(true);
AssertJUnit.assertEquals(1, sliver.getAmountOfKeyword("Flanking")); AssertJUnit.assertEquals(1, sliver.getAmountOfKeyword(Keyword.FLANKING));
AssertJUnit.assertEquals(2, sliver.getNetPower()); AssertJUnit.assertEquals(2, sliver.getNetPower());
AssertJUnit.assertEquals(2, sliver.getNetToughness()); AssertJUnit.assertEquals(2, sliver.getNetToughness());
@@ -87,7 +87,7 @@ public class GameSimulationTest extends SimulationTest {
AssertJUnit.assertTrue(score > 0); AssertJUnit.assertTrue(score > 0);
Game simGame = sim.getSimulatedGameState(); Game simGame = sim.getSimulatedGameState();
Card sliverCopy = findCardWithName(simGame, sliverCardName); Card sliverCopy = findCardWithName(simGame, sliverCardName);
AssertJUnit.assertEquals(1, sliverCopy.getAmountOfKeyword("Flanking")); AssertJUnit.assertEquals(1, sliverCopy.getAmountOfKeyword(Keyword.FLANKING));
AssertJUnit.assertEquals(2, sliver.getNetPower()); AssertJUnit.assertEquals(2, sliver.getNetPower());
AssertJUnit.assertEquals(2, sliver.getNetToughness()); AssertJUnit.assertEquals(2, sliver.getNetToughness());
} }
@@ -103,15 +103,15 @@ public class GameSimulationTest extends SimulationTest {
game.getPhaseHandler().devModeSet(PhaseType.MAIN1, p); game.getPhaseHandler().devModeSet(PhaseType.MAIN1, p);
game.getAction().checkStateEffects(true); game.getAction().checkStateEffects(true);
AssertJUnit.assertTrue(lion.isMonstrous()); AssertJUnit.assertTrue(lion.isMonstrous());
AssertJUnit.assertEquals(1, lion.getAmountOfKeyword("Hexproof")); AssertJUnit.assertEquals(1, lion.getAmountOfKeyword(Keyword.HEXPROOF));
AssertJUnit.assertEquals(1, lion.getAmountOfKeyword("Indestructible")); AssertJUnit.assertEquals(1, lion.getAmountOfKeyword(Keyword.INDESTRUCTIBLE));
GameSimulator sim = createSimulator(game, p); GameSimulator sim = createSimulator(game, p);
Game simGame = sim.getSimulatedGameState(); Game simGame = sim.getSimulatedGameState();
Card lionCopy = findCardWithName(simGame, lionCardName); Card lionCopy = findCardWithName(simGame, lionCardName);
AssertJUnit.assertTrue(lionCopy.isMonstrous()); AssertJUnit.assertTrue(lionCopy.isMonstrous());
AssertJUnit.assertEquals(1, lionCopy.getAmountOfKeyword("Hexproof")); AssertJUnit.assertEquals(1, lionCopy.getAmountOfKeyword(Keyword.HEXPROOF));
AssertJUnit.assertEquals(1, lionCopy.getAmountOfKeyword("Indestructible")); AssertJUnit.assertEquals(1, lionCopy.getAmountOfKeyword(Keyword.INDESTRUCTIBLE));
} }
@Test @Test
@@ -125,12 +125,12 @@ public class GameSimulationTest extends SimulationTest {
cloak.attachToEntity(bear, null); cloak.attachToEntity(bear, null);
game.getPhaseHandler().devModeSet(PhaseType.MAIN1, p); game.getPhaseHandler().devModeSet(PhaseType.MAIN1, p);
game.getAction().checkStateEffects(true); game.getAction().checkStateEffects(true);
AssertJUnit.assertEquals(1, bear.getAmountOfKeyword("Shroud")); AssertJUnit.assertEquals(1, bear.getAmountOfKeyword(Keyword.SHROUD));
GameSimulator sim = createSimulator(game, p); GameSimulator sim = createSimulator(game, p);
Game simGame = sim.getSimulatedGameState(); Game simGame = sim.getSimulatedGameState();
Card bearCopy = findCardWithName(simGame, bearCardName); Card bearCopy = findCardWithName(simGame, bearCardName);
AssertJUnit.assertEquals(1, bearCopy.getAmountOfKeyword("Shroud")); AssertJUnit.assertEquals(1, bearCopy.getAmountOfKeyword(Keyword.SHROUD));
} }
@Test @Test
@@ -144,12 +144,12 @@ public class GameSimulationTest extends SimulationTest {
lifelink.attachToEntity(bear, null); lifelink.attachToEntity(bear, null);
game.getPhaseHandler().devModeSet(PhaseType.MAIN1, p); game.getPhaseHandler().devModeSet(PhaseType.MAIN1, p);
game.getAction().checkStateEffects(true); game.getAction().checkStateEffects(true);
AssertJUnit.assertEquals(1, bear.getAmountOfKeyword("Lifelink")); AssertJUnit.assertEquals(1, bear.getAmountOfKeyword(Keyword.LIFELINK));
GameSimulator sim = createSimulator(game, p); GameSimulator sim = createSimulator(game, p);
Game simGame = sim.getSimulatedGameState(); Game simGame = sim.getSimulatedGameState();
Card bearCopy = findCardWithName(simGame, bearCardName); Card bearCopy = findCardWithName(simGame, bearCardName);
AssertJUnit.assertEquals(1, bearCopy.getAmountOfKeyword("Lifelink")); AssertJUnit.assertEquals(1, bearCopy.getAmountOfKeyword(Keyword.LIFELINK));
} }
@Test @Test

View File

@@ -1,7 +1,7 @@
Name:Topsy Turvy Name:Topsy Turvy
ManaCost:2 U ManaCost:2 U
Types:Enchantment Types:Enchantment
S:Mode$ Continuous | Affected$ Player | AddKeyword$ The phases of your turn are reversed. | Description$ The phases of each player's turn are reversed. (The phases are, in reverse order, ending, postcombat main, combat, precombat main, and beginning.) S:Mode$ PhaseReversed | ValidPlayer$ Player | Description$ The phases of each player's turn are reversed. (The phases are, in reverse order, ending, postcombat main, combat, precombat main, and beginning.)
S:Mode$ Continuous | Affected$ Player | AddKeyword$ The turn order is reversed. | CheckSVar$ X | SVarCompare$ GT2 | Description$ As long as there are more than two players in the game, the turn order is reversed. S:Mode$ TurnReversed | ValidPlayer$ Player | CheckSVar$ X | SVarCompare$ GT2 | Description$ As long as there are more than two players in the game, the turn order is reversed.
SVar:X:PlayerCountPlayers$Amount SVar:X:PlayerCountPlayers$Amount
Oracle:The phases of each player's turn are reversed. (The phases are, in reverse order, ending, postcombat main, combat, precombat main, and beginning.)\nAs long as there are more than two players in the game, the turn order is reversed. Oracle:The phases of each player's turn are reversed. (The phases are, in reverse order, ending, postcombat main, combat, precombat main, and beginning.)\nAs long as there are more than two players in the game, the turn order is reversed.