diff --git a/forge-game/src/main/java/forge/game/GameAction.java b/forge-game/src/main/java/forge/game/GameAction.java index 0edf0997bbd..ca1df7c8527 100644 --- a/forge-game/src/main/java/forge/game/GameAction.java +++ b/forge-game/src/main/java/forge/game/GameAction.java @@ -1560,6 +1560,12 @@ public class GameAction { } } + // 704.5z If a player controls a permanent with start your engines! and that player has no speed, that player’s speed becomes 1. See rule 702.179, “Start Your Engines!” + if (p.getSpeed() == 0 && p.getCardsIn(ZoneType.Battlefield).anyMatch(c -> c.hasKeyword(Keyword.START_YOUR_ENGINES))) { + p.increaseSpeed(); + checkAgain = true; + } + if (handlePlaneswalkerRule(p, noRegCreats)) { checkAgain = true; } 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 36e48ae2016..f3df038976d 100644 --- a/forge-game/src/main/java/forge/game/card/Card.java +++ b/forge-game/src/main/java/forge/game/card/Card.java @@ -2550,7 +2550,8 @@ public class Card extends GameEntity implements Comparable, IHasSVars, ITr || keyword.equals("Battle cry") || keyword.equals("Devoid") || keyword.equals("Riot") || keyword.equals("Daybound") || keyword.equals("Nightbound") || keyword.equals("Friends forever") || keyword.equals("Choose a Background") - || keyword.equals("Space sculptor") || keyword.equals("Doctor's companion")) { + || keyword.equals("Space sculptor") || keyword.equals("Doctor's companion") + || keyword.equals("Start your engines")) { sbLong.append(keyword).append(" (").append(inst.getReminderText()).append(")"); } else if (keyword.startsWith("Partner:")) { final String[] k = keyword.split(":"); @@ -2706,8 +2707,7 @@ public class Card extends GameEntity implements Comparable, IHasSVars, ITr || keyword.startsWith("Class") || keyword.startsWith("Blitz") || keyword.startsWith("Specialize") || keyword.equals("Ravenous") || keyword.equals("For Mirrodin") || keyword.startsWith("Craft") - || keyword.startsWith("Landwalk") || keyword.startsWith("Visit") - || keyword.equals("Start your engines")) { + || keyword.startsWith("Landwalk") || keyword.startsWith("Visit")) { // keyword parsing takes care of adding a proper description } else if (keyword.equals("Read ahead")) { sb.append(Localizer.getInstance().getMessage("lblReadAhead")).append(" (").append(Localizer.getInstance().getMessage("lblReadAheadDesc")); 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 3f2930304b5..1a22f7114d1 100644 --- a/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java +++ b/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java @@ -1835,15 +1835,6 @@ public class CardFactoryUtil { squadTrigger.setOverridingAbility(squadAbility); squadTrigger.setSVar("SquadAmount", "Count$OptionalKeywordAmount"); inst.addTrigger(squadTrigger); - } else if (keyword.equals("Start your engines")) { - final String trig = "Mode$ Always | TriggerZones$ Battlefield | Static$ True | CheckDefinedPlayer$ " + - "You.NoSpeed | TriggerDescription$ Start your engines! (" + inst.getReminderText() + ")"; - final String effect = "DB$ ChangeSpeed"; - - final Trigger trigger = TriggerHandler.parseTrigger(trig, card, intrinsic); - trigger.setOverridingAbility(AbilityFactory.getAbility(effect, card)); - - inst.addTrigger(trigger); } else if (keyword.equals("Storm")) { final String actualTrigger = "Mode$ SpellCast | ValidCard$ Card.Self | TriggerZones$ Stack | Secondary$ True" + "| TriggerDescription$ Storm (" + inst.getReminderText() + ")"; diff --git a/forge-game/src/main/java/forge/game/event/GameEventSpeedChanged.java b/forge-game/src/main/java/forge/game/event/GameEventSpeedChanged.java new file mode 100644 index 00000000000..5320fef0626 --- /dev/null +++ b/forge-game/src/main/java/forge/game/event/GameEventSpeedChanged.java @@ -0,0 +1,21 @@ +package forge.game.event; + +import forge.game.player.Player; + +public class GameEventSpeedChanged extends GameEvent { + + public final Player player; + public final int oldValue; + public final int newValue; + + public GameEventSpeedChanged(Player affected, int oldValue, int newValue) { + player = affected; + this.oldValue = oldValue; + this.newValue = newValue; + } + + @Override + public T visit(IGameEventVisitor visitor) { + return visitor.visit(this); + } +} diff --git a/forge-game/src/main/java/forge/game/event/GameEventSpeedUp.java b/forge-game/src/main/java/forge/game/event/GameEventSpeedUp.java deleted file mode 100644 index e7d7022bafa..00000000000 --- a/forge-game/src/main/java/forge/game/event/GameEventSpeedUp.java +++ /dev/null @@ -1,17 +0,0 @@ -package forge.game.event; - -import forge.game.player.Player; - -public class GameEventSpeedUp extends GameEvent { - - public final Player player; - - public GameEventSpeedUp(Player affected) { - player = affected; - } - - @Override - public T visit(IGameEventVisitor visitor) { - return visitor.visit(this); - } -} diff --git a/forge-game/src/main/java/forge/game/event/IGameEventVisitor.java b/forge-game/src/main/java/forge/game/event/IGameEventVisitor.java index ea84575eee8..159eb2836da 100644 --- a/forge-game/src/main/java/forge/game/event/IGameEventVisitor.java +++ b/forge-game/src/main/java/forge/game/event/IGameEventVisitor.java @@ -44,7 +44,7 @@ public interface IGameEventVisitor { T visit(GameEventRollDie event); T visit(GameEventScry event); T visit(GameEventShuffle event); - T visit(GameEventSpeedUp event); + T visit(GameEventSpeedChanged event); T visit(GameEventSpellAbilityCast event); T visit(GameEventSpellResolved event); T visit(GameEventSpellRemovedFromStack event); @@ -101,7 +101,7 @@ public interface IGameEventVisitor { public T visit(GameEventRollDie event) { return null; } public T visit(GameEventScry event) { return null; } public T visit(GameEventShuffle event) { return null; } - public T visit(GameEventSpeedUp event) { return null; } + public T visit(GameEventSpeedChanged event) { return null; } public T visit(GameEventSpellResolved event) { return null; } public T visit(GameEventSpellAbilityCast event) { return null; } public T visit(GameEventSpellRemovedFromStack event) { return null; } diff --git a/forge-game/src/main/java/forge/game/player/Player.java b/forge-game/src/main/java/forge/game/player/Player.java index 9a8b5dccc47..2db3db2e60f 100644 --- a/forge-game/src/main/java/forge/game/player/Player.java +++ b/forge-game/src/main/java/forge/game/player/Player.java @@ -1973,16 +1973,18 @@ public class Player extends GameEntity implements Comparable { public final void increaseSpeed() { if (speedEffect == null) createSpeedEffect(); if (!maxSpeed()) { // can't increase past 4 + int old = speed; speed++; view.updateSpeed(this); - game.fireEvent(new GameEventSpeedUp(this)); //play sound effect + getGame().fireEvent(new GameEventSpeedChanged(this, old, speed)); //play sound effect } } public final void decreaseSpeed() { if (speed > 1) { // can't decrease speed below 1 + int old = speed; speed--; view.updateSpeed(this); - getGame().fireEvent(new GameEventPlayerStatsChanged(this, false)); + game.fireEvent(new GameEventSpeedChanged(this, old, speed)); } } public final boolean noSpeed() { @@ -1998,9 +2000,11 @@ public class Player extends GameEntity implements Comparable { public final void createSpeedEffect() { final PlayerZone com = getZone(ZoneType.Command); DetachedCardEffect eff = new DetachedCardEffect(this, "Speed Effect"); - String trigger = "Mode$ LifeLost | ValidPlayer$ Opponent | TriggerZones$ Command | ActivationLimit$ 1 | " + + // 702.179d There is an inherent triggered ability associated with a player having 1 or more speed. This ability has no source and is controlled by that player. + // That ability is “Whenever one or more opponents lose life during your turn, if your speed is less than 4, your speed increases by 1. This ability triggers only once each turn.” + String trigger = "Mode$ LifeLostAll | ValidPlayer$ Opponent | TriggerZones$ Command | ActivationLimit$ 1 | " + "PlayerTurn$ True | CheckSVar$ Count$YourSpeed | SVarCompare$ LT4 | " - + "TriggerDescription$ Your speed increases once on each of your turns when an opponent loses life."; + + "TriggerDescription$ Whenever one or more opponents lose life during your turn, if your speed is less than 4, your speed increases by 1. This ability triggers only once each turn."; String speedUp = "DB$ ChangeSpeed"; Trigger lifeLostTrigger = TriggerHandler.parseTrigger(trigger, eff, true); lifeLostTrigger.setOverridingAbility(AbilityFactory.getAbility(speedUp, eff)); diff --git a/forge-gui/src/main/java/forge/gui/control/FControlGameEventHandler.java b/forge-gui/src/main/java/forge/gui/control/FControlGameEventHandler.java index a3635bf9293..a17250b56d3 100644 --- a/forge-gui/src/main/java/forge/gui/control/FControlGameEventHandler.java +++ b/forge-gui/src/main/java/forge/gui/control/FControlGameEventHandler.java @@ -451,7 +451,7 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base { return processCards(cards, cardsRefreshDetails); } - public Void visit(final GameEventSpeedUp event) { + public Void visit(final GameEventSpeedChanged event) { Player p = event.player; processPlayer(p, livesUpdate); return processEvent(); diff --git a/forge-gui/src/main/java/forge/sound/EventVisualizer.java b/forge-gui/src/main/java/forge/sound/EventVisualizer.java index 09f8848d9df..3cc118fcce4 100644 --- a/forge-gui/src/main/java/forge/sound/EventVisualizer.java +++ b/forge-gui/src/main/java/forge/sound/EventVisualizer.java @@ -80,7 +80,7 @@ public class EventVisualizer extends IGameEventVisitor.Base imp @Override public SoundEffectType visit(final GameEventShuffle event) { return SoundEffectType.Shuffle; } @Override - public SoundEffectType visit(final GameEventSpeedUp event) { return SoundEffectType.SpeedUp; } + public SoundEffectType visit(final GameEventSpeedChanged event) { return event.newValue > event.oldValue ? SoundEffectType.SpeedUp : null; } @Override public SoundEffectType visit(final GameEventTokenCreated event) { return SoundEffectType.Token; } @Override