Planechase inherent effects (#4408)

* Planechase effects draft

Draft to close #4262, by moving the planeswalking ability and the static chaos trigger to an effect carried with the player in a planechase game. Currently this effect is visible in the command zone much like the monarch or initiative (but with no image), which is something that needs fixing; I'd have it be a DetachedCardEffect but there's no linked card for it like there are for commander and companion effects (the active plane [or the face-up plane with the earliest timestamp, I suppose] would be a logical choice for the getCardForUi, but that would require updating it as the plane changes, and in any case because there's a separate effect for each player, the fact that the owner of a DetachedCardEffect is set as the owner of the linked card also adds some wrinkles. In any case, I've set the effects to be created in startGame after initPlane is run, rather than in initVariantZones as is the case for the commander and companion DetachedCardEffects, in anticipation of hopefully in the future making the effect be linked to an active plane).

* Update Player.java

* Move planar dice special action to effect

* Update ComputerUtilAbility.java

* Move die roll chaos to PlanarDice.java
This commit is contained in:
Klisz
2023-12-30 23:11:30 -07:00
committed by GitHub
parent d58f564a84
commit c02f7c698d
6 changed files with 66 additions and 37 deletions

View File

@@ -255,10 +255,25 @@ public class ComputerUtilAbility {
}
// deprioritize planar die roll marked with AIRollPlanarDieParams:LowPriority$ True
if (ApiType.RollPlanarDice == a.getApi() && a.getHostCard() != null && a.getHostCard().hasSVar("AIRollPlanarDieParams") && a.getHostCard().getSVar("AIRollPlanarDieParams").toLowerCase().matches(".*lowpriority\\$\\s*true.*")) {
return 1;
} else if (ApiType.RollPlanarDice == b.getApi() && b.getHostCard() != null && b.getHostCard().hasSVar("AIRollPlanarDieParams") && b.getHostCard().getSVar("AIRollPlanarDieParams").toLowerCase().matches(".*lowpriority\\$\\s*true.*")) {
return -1;
if (ApiType.RollPlanarDice == a.getApi() || ApiType.RollPlanarDice == b.getApi()) {
Card hostCardForGame = a.getHostCard();
if (hostCardForGame == null) {
if (b.getHostCard() != null) {
hostCardForGame = b.getHostCard();
} else {
return 0; // fallback if neither SA have a host card somehow
}
}
Game game = hostCardForGame.getGame();
for (Card c : game.getActivePlanes()) {
if (c.hasSVar("AIRollPlanarDieParams") && c.getSVar("AIRollPlanarDieParams").toLowerCase().matches(".*lowpriority\\$\\s*true.*")) {
if (ApiType.RollPlanarDice == a.getApi()) {
return 1;
} else {
return -1;
}
}
}
}
// deprioritize pump spells with pure energy cost (can be activated last,

View File

@@ -19,9 +19,16 @@ public class RollPlanarDiceAi extends SpellAbilityAi {
*/
@Override
protected boolean canPlayAI(Player ai, SpellAbility sa) {
AiController aic = ((PlayerControllerAi)ai.getController()).getAi();
Card plane = sa.getHostCard();
for (Card c : ai.getGame().getActivePlanes()) {
if (willRollOnPlane(ai, c)) {
return true;
}
}
return false;
}
private boolean willRollOnPlane(Player ai, Card plane) {
AiController aic = ((PlayerControllerAi)ai.getController()).getAi();
boolean decideToRoll = false;
boolean rollInMain1 = false;
String modeName = "never";

View File

@@ -2090,6 +2090,9 @@ public class GameAction {
//<THIS CODE WILL WORK WITH PHASE = NULL>
if (game.getRules().hasAppliedVariant(GameType.Planechase)) {
first.initPlane();
for (final Player p1 : game.getPlayers()) {
p1.createPlanechaseEffects(game);
}
}
first = runOpeningHandActions(first);

View File

@@ -87,6 +87,11 @@ public enum PlanarDice {
runParams.put(AbilityKey.Result, Arrays.asList(0));
roller.getGame().getTriggerHandler().runTrigger(TriggerType.RolledDieOnce, runParams, false);
if (res == Chaos) {
runParams = AbilityKey.mapFromPlayer(roller);
roller.getGame().getTriggerHandler().runTrigger(TriggerType.ChaosEnsues, runParams, false);
}
return res;
}

View File

@@ -318,42 +318,11 @@ public class CardFactory {
// ******************************************************************
// ************** Link to different CardFactories *******************
if (card.isPlane()) {
buildPlaneAbilities(card);
}
buildBattleAbilities(card);
CardFactoryUtil.setupKeywordedAbilities(card); // Should happen AFTER setting left/right split abilities to set Fuse ability to both sides
card.updateStateForView();
}
private static void buildPlaneAbilities(Card card) {
String trigger = "Mode$ PlanarDice | Result$ Planeswalk | TriggerZones$ Command | Secondary$ True | " +
"TriggerDescription$ Whenever you roll the Planeswalker symbol on the planar die, planeswalk.";
String rolledWalk = "DB$ Planeswalk | Cause$ PlanarDie";
Trigger planesWalkTrigger = TriggerHandler.parseTrigger(trigger, card, true);
planesWalkTrigger.setOverridingAbility(AbilityFactory.getAbility(rolledWalk, card));
card.addTrigger(planesWalkTrigger);
String chaosTrig = "Mode$ PlanarDice | Result$ Chaos | TriggerZones$ Command | Static$ True";
String rolledChaos = "DB$ ChaosEnsues";
Trigger chaosTrigger = TriggerHandler.parseTrigger(chaosTrig, card, true);
chaosTrigger.setOverridingAbility(AbilityFactory.getAbility(rolledChaos, card));
card.addTrigger(chaosTrigger);
String specialA = "ST$ RollPlanarDice | Cost$ X | SorcerySpeed$ True | Activator$ Player | SpecialAction$ True" +
" | ActivationZone$ Command | SpellDescription$ Roll the planar dice. X is equal to the number of " +
"times you have previously taken this action this turn. | CostDesc$ {X}: ";
SpellAbility planarRoll = AbilityFactory.getAbility(specialA, card);
planarRoll.setSVar("X", "Count$PlanarDiceSpecialActionThisTurn");
card.addSpellAbility(planarRoll);
}
private static void buildBattleAbilities(Card card) {
if (!card.isBattle()) {
return;

View File

@@ -3176,6 +3176,36 @@ public class Player extends GameEntity implements Comparable<Player> {
return eff;
}
public void createPlanechaseEffects(Game game) {
final PlayerZone com = getZone(ZoneType.Command);
final String name = "Planar Dice";
final Card eff = new Card(game.nextCardId(), game);
eff.setTimestamp(game.getNextTimestamp());
eff.setName(name);
eff.setOwner(this);
eff.setImmutable(true);
String image = ImageKeys.getTokenKey("planechase");
eff.setImageKey(image);
String trigger = "Mode$ PlanarDice | Result$ Planeswalk | TriggerZones$ Command | ValidPlayer$ You | Secondary$ True | " +
"TriggerDescription$ Whenever you roll the Planeswalker symbol on the planar die, planeswalk.";
String rolledWalk = "DB$ Planeswalk | Cause$ PlanarDie";
Trigger planesWalkTrigger = TriggerHandler.parseTrigger(trigger, eff, true);
planesWalkTrigger.setOverridingAbility(AbilityFactory.getAbility(rolledWalk, eff));
eff.addTrigger(planesWalkTrigger);
String specialA = "ST$ RollPlanarDice | Cost$ X | SorcerySpeed$ True | Activator$ Player | SpecialAction$ True" +
" | ActivationZone$ Command | SpellDescription$ Roll the planar dice. X is equal to the number of " +
"times you have previously taken this action this turn. | CostDesc$ {X}: ";
SpellAbility planarRoll = AbilityFactory.getAbility(specialA, eff);
planarRoll.setSVar("X", "Count$PlanarDiceSpecialActionThisTurn");
eff.addSpellAbility(planarRoll);
eff.updateStateForView();
com.add(eff);
this.updateZoneForView(com);
}
public void createTheRing(Card host) {
final PlayerZone com = getZone(ZoneType.Command);
if (theRing == null) {