From 01a47aaa222cb6b8c8139c3faa3df7adff868ba2 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Fri, 24 Jan 2025 18:52:52 -0500 Subject: [PATCH 1/2] add initial speed handling --- Mage.Sets/src/mage/sets/Aetherdrift.java | 2 - .../java/org/mage/test/player/TestPlayer.java | 15 +++++++ .../common/ControllerSpeedCount.java | 9 +++- .../continuous/MaxSpeedGainAbilityEffect.java | 1 + .../keyword/StartYourEnginesAbility.java | 44 ++++++++++++++++--- Mage/src/main/java/mage/players/Player.java | 6 +++ .../main/java/mage/players/PlayerImpl.java | 25 +++++++++++ 7 files changed, 93 insertions(+), 9 deletions(-) diff --git a/Mage.Sets/src/mage/sets/Aetherdrift.java b/Mage.Sets/src/mage/sets/Aetherdrift.java index f22b78c6017c..239675d60868 100644 --- a/Mage.Sets/src/mage/sets/Aetherdrift.java +++ b/Mage.Sets/src/mage/sets/Aetherdrift.java @@ -94,7 +94,5 @@ private Aetherdrift() { cards.add(new SetCardInfo("Wild Roads", 269, Rarity.UNCOMMON, mage.cards.w.WildRoads.class)); cards.add(new SetCardInfo("Willowrush Verge", 270, Rarity.RARE, mage.cards.w.WillowrushVerge.class)); cards.add(new SetCardInfo("Wind-Scarred Crag", 271, Rarity.COMMON, mage.cards.w.WindScarredCrag.class)); - - cards.removeIf(setCardInfo -> unfinished.contains(setCardInfo.getName())); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java index cef50ca4a8e9..3dd85558f475 100644 --- a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java +++ b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java @@ -3977,6 +3977,21 @@ public boolean isDrawsOnOpponentsTurn() { return computerPlayer.isDrawsOnOpponentsTurn(); } + @Override + public int getSpeed() { + return computerPlayer.getSpeed(); + } + + @Override + public boolean initSpeed() { + return computerPlayer.initSpeed(); + } + + @Override + public void increaseSpeed() { + computerPlayer.increaseSpeed(); + } + @Override public void setPayManaMode(boolean payManaMode) { computerPlayer.setPayManaMode(payManaMode); diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/ControllerSpeedCount.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/ControllerSpeedCount.java index b06aa28ecfec..12ca32d02a9e 100644 --- a/Mage/src/main/java/mage/abilities/dynamicvalue/common/ControllerSpeedCount.java +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/ControllerSpeedCount.java @@ -4,6 +4,9 @@ import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.effects.Effect; import mage.game.Game; +import mage.players.Player; + +import java.util.Optional; /** * @author TheElk801 @@ -13,8 +16,10 @@ public enum ControllerSpeedCount implements DynamicValue { @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { - // TODO: Implement this - return 0; + return Optional + .ofNullable(game.getPlayer(sourceAbility.getControllerId())) + .map(Player::getSpeed) + .orElse(0); } @Override diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/MaxSpeedGainAbilityEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/MaxSpeedGainAbilityEffect.java index a0136fad8c3b..962e366df85d 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/MaxSpeedGainAbilityEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/MaxSpeedGainAbilityEffect.java @@ -26,6 +26,7 @@ public MaxSpeedGainAbilityEffect(Effect effect) { public MaxSpeedGainAbilityEffect(Ability ability) { super(Duration.WhileOnBattlefield, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility); + ability.setRuleVisible(false); this.ability = ability; } diff --git a/Mage/src/main/java/mage/abilities/keyword/StartYourEnginesAbility.java b/Mage/src/main/java/mage/abilities/keyword/StartYourEnginesAbility.java index 1c8d8c5516cb..6b3505a26441 100644 --- a/Mage/src/main/java/mage/abilities/keyword/StartYourEnginesAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/StartYourEnginesAbility.java @@ -1,17 +1,25 @@ package mage.abilities.keyword; +import mage.abilities.Ability; import mage.abilities.StaticAbility; -import mage.constants.Zone; +import mage.abilities.dynamicvalue.common.ControllerSpeedCount; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.hint.Hint; +import mage.abilities.hint.ValueHint; +import mage.constants.*; +import mage.game.Game; +import mage.players.Player; /** - * TODO: Implement this - * * @author TheElk801 */ public class StartYourEnginesAbility extends StaticAbility { + private static final Hint hint = new ValueHint("Your current speed", ControllerSpeedCount.instance); + public StartYourEnginesAbility() { - super(Zone.BATTLEFIELD, null); + super(Zone.BATTLEFIELD, new StartYourEnginesEffect()); + this.addHint(hint); } private StartYourEnginesAbility(final StartYourEnginesAbility ability) { @@ -25,6 +33,32 @@ public StartYourEnginesAbility copy() { @Override public String getRule() { - return "Start your engines!"; + return "start your engines!"; + } +} + +class StartYourEnginesEffect extends ContinuousEffectImpl { + + StartYourEnginesEffect() { + super(Duration.WhileOnBattlefield, Layer.PlayerEffects, SubLayer.NA, Outcome.Benefit); + } + + private StartYourEnginesEffect(final StartYourEnginesEffect effect) { + super(effect); + } + + @Override + public StartYourEnginesEffect copy() { + return new StartYourEnginesEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null || !player.initSpeed()) { + return false; + } + game.informPlayers(player.getLogName() + "'s speed is now 1."); + return true; } } diff --git a/Mage/src/main/java/mage/players/Player.java b/Mage/src/main/java/mage/players/Player.java index 9566348bc7cd..fc8e945ec62d 100644 --- a/Mage/src/main/java/mage/players/Player.java +++ b/Mage/src/main/java/mage/players/Player.java @@ -216,6 +216,12 @@ default boolean isComputer() { boolean isDrawsOnOpponentsTurn(); + int getSpeed(); + + boolean initSpeed(); + + void increaseSpeed(); + /** * Returns alternative casting costs a player can cast spells for * diff --git a/Mage/src/main/java/mage/players/PlayerImpl.java b/Mage/src/main/java/mage/players/PlayerImpl.java index 4afac4032342..1b925115d87e 100644 --- a/Mage/src/main/java/mage/players/PlayerImpl.java +++ b/Mage/src/main/java/mage/players/PlayerImpl.java @@ -153,6 +153,7 @@ public abstract class PlayerImpl implements Player, Serializable { protected boolean canPlotFromTopOfLibrary = false; protected boolean drawsFromBottom = false; protected boolean drawsOnOpponentsTurn = false; + protected int speed = 0; protected FilterPermanent sacrificeCostFilter; protected List alternativeSourceCosts = new ArrayList<>(); @@ -252,6 +253,7 @@ protected PlayerImpl(final PlayerImpl player) { this.canPlotFromTopOfLibrary = player.canPlotFromTopOfLibrary; this.drawsFromBottom = player.drawsFromBottom; this.drawsOnOpponentsTurn = player.drawsOnOpponentsTurn; + this.speed = player.speed; this.attachments.addAll(player.attachments); @@ -367,6 +369,7 @@ public void restore(Player player) { this.drawsFromBottom = player.isDrawsFromBottom(); this.drawsOnOpponentsTurn = player.isDrawsOnOpponentsTurn(); this.alternativeSourceCosts = CardUtil.deepCopyObject(((PlayerImpl) player).alternativeSourceCosts); + this.speed = player.getSpeed(); this.topCardRevealed = player.isTopCardRevealed(); @@ -480,6 +483,7 @@ public void init(Game game) { this.canPlotFromTopOfLibrary = false; this.drawsFromBottom = false; this.drawsOnOpponentsTurn = false; + this.speed = 0; this.sacrificeCostFilter = null; this.alternativeSourceCosts.clear(); @@ -4674,6 +4678,27 @@ public boolean isDrawsOnOpponentsTurn() { return drawsOnOpponentsTurn; } + @Override + public int getSpeed() { + return speed; + } + + @Override + public boolean initSpeed() { + if (speed < 1) { + speed = 1; + return true; + } + return false; + } + + @Override + public void increaseSpeed() { + if (speed < 4) { + speed++; + } + } + @Override public boolean autoLoseGame() { return false; From b269b1121d3d5c2ef062d71dd981484c48a6e15d Mon Sep 17 00:00:00 2001 From: theelk801 Date: Fri, 24 Jan 2025 22:11:35 -0500 Subject: [PATCH 2/2] finish speed implementation --- .../java/org/mage/test/player/TestPlayer.java | 8 +- .../keyword/StartYourEnginesAbility.java | 11 +- .../mage/designations/DesignationType.java | 5 +- .../main/java/mage/designations/Speed.java | 108 ++++++++++++++++++ Mage/src/main/java/mage/players/Player.java | 4 +- .../main/java/mage/players/PlayerImpl.java | 15 ++- 6 files changed, 130 insertions(+), 21 deletions(-) create mode 100644 Mage/src/main/java/mage/designations/Speed.java diff --git a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java index 3dd85558f475..8d9394141efd 100644 --- a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java +++ b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java @@ -3983,13 +3983,13 @@ public int getSpeed() { } @Override - public boolean initSpeed() { - return computerPlayer.initSpeed(); + public void initSpeed(Game game) { + computerPlayer.initSpeed(game); } @Override - public void increaseSpeed() { - computerPlayer.increaseSpeed(); + public void increaseSpeed(Game game) { + computerPlayer.increaseSpeed(game); } @Override diff --git a/Mage/src/main/java/mage/abilities/keyword/StartYourEnginesAbility.java b/Mage/src/main/java/mage/abilities/keyword/StartYourEnginesAbility.java index 6b3505a26441..be19e3269ab6 100644 --- a/Mage/src/main/java/mage/abilities/keyword/StartYourEnginesAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/StartYourEnginesAbility.java @@ -8,7 +8,8 @@ import mage.abilities.hint.ValueHint; import mage.constants.*; import mage.game.Game; -import mage.players.Player; + +import java.util.Optional; /** * @author TheElk801 @@ -54,11 +55,9 @@ public StartYourEnginesEffect copy() { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player == null || !player.initSpeed()) { - return false; - } - game.informPlayers(player.getLogName() + "'s speed is now 1."); + Optional.ofNullable(source.getControllerId()) + .map(game::getPlayer) + .ifPresent(player -> player.initSpeed(game)); return true; } } diff --git a/Mage/src/main/java/mage/designations/DesignationType.java b/Mage/src/main/java/mage/designations/DesignationType.java index 62b77b28c61c..dd95ff9808f1 100644 --- a/Mage/src/main/java/mage/designations/DesignationType.java +++ b/Mage/src/main/java/mage/designations/DesignationType.java @@ -6,8 +6,8 @@ public enum DesignationType { THE_MONARCH("The Monarch"), // global CITYS_BLESSING("City's Blessing"), // per player - THE_INITIATIVE("The Initiative"); // global - + THE_INITIATIVE("The Initiative"), // global + SPEED("Speed"); // per player private final String text; DesignationType(String text) { @@ -18,5 +18,4 @@ public enum DesignationType { public String toString() { return text; } - } diff --git a/Mage/src/main/java/mage/designations/Speed.java b/Mage/src/main/java/mage/designations/Speed.java new file mode 100644 index 000000000000..b3529f50fb24 --- /dev/null +++ b/Mage/src/main/java/mage/designations/Speed.java @@ -0,0 +1,108 @@ +package mage.designations; + +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.OneShotEffect; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.players.Player; + +import java.util.Optional; + +/** + * @author TheElk801 + */ +public class Speed extends Designation { + + public Speed() { + super(DesignationType.SPEED); + addAbility(new SpeedTriggeredAbility()); + } + + private Speed(final Speed card) { + super(card); + } + + @Override + public Speed copy() { + return new Speed(this); + } +} + +class SpeedTriggeredAbility extends TriggeredAbilityImpl { + + SpeedTriggeredAbility() { + super(Zone.ALL, new SpeedEffect()); + setTriggersLimitEachTurn(1); + } + + private SpeedTriggeredAbility(final SpeedTriggeredAbility ability) { + super(ability); + } + + @Override + public SpeedTriggeredAbility copy() { + return new SpeedTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.LOST_LIFE_BATCH_FOR_ONE_PLAYER; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + return game.isActivePlayer(getControllerId()) + && game + .getOpponents(getControllerId()) + .contains(event.getTargetId()); + } + + @Override + public boolean checkInterveningIfClause(Game game) { + return Optional + .ofNullable(getControllerId()) + .map(game::getPlayer) + .map(Player::getSpeed) + .map(x -> x < 4) + .orElse(false); + } + + @Override + public boolean isInUseableZone(Game game, MageObject sourceObject, GameEvent event) { + return true; + } + + @Override + public String getRule() { + return "Whenever one or more opponents lose life during your turn, if your speed is less than 4, " + + "increase your speed by 1. This ability triggers only once each turn."; + } +} + +class SpeedEffect extends OneShotEffect { + + SpeedEffect() { + super(Outcome.Benefit); + } + + private SpeedEffect(final SpeedEffect effect) { + super(effect); + } + + @Override + public SpeedEffect copy() { + return new SpeedEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Optional.ofNullable(source.getControllerId()) + .map(game::getPlayer) + .ifPresent(player -> player.increaseSpeed(game)); + return true; + } +} diff --git a/Mage/src/main/java/mage/players/Player.java b/Mage/src/main/java/mage/players/Player.java index fc8e945ec62d..cdf5a8bed3c1 100644 --- a/Mage/src/main/java/mage/players/Player.java +++ b/Mage/src/main/java/mage/players/Player.java @@ -218,9 +218,9 @@ default boolean isComputer() { int getSpeed(); - boolean initSpeed(); + void initSpeed(Game game); - void increaseSpeed(); + void increaseSpeed(Game game); /** * Returns alternative casting costs a player can cast spells for diff --git a/Mage/src/main/java/mage/players/PlayerImpl.java b/Mage/src/main/java/mage/players/PlayerImpl.java index 1b925115d87e..e1f5245fad1d 100644 --- a/Mage/src/main/java/mage/players/PlayerImpl.java +++ b/Mage/src/main/java/mage/players/PlayerImpl.java @@ -27,6 +27,7 @@ import mage.counters.Counters; import mage.designations.Designation; import mage.designations.DesignationType; +import mage.designations.Speed; import mage.filter.FilterCard; import mage.filter.FilterMana; import mage.filter.FilterPermanent; @@ -4684,18 +4685,20 @@ public int getSpeed() { } @Override - public boolean initSpeed() { - if (speed < 1) { - speed = 1; - return true; + public void initSpeed(Game game) { + if (speed > 0) { + return; } - return false; + speed = 1; + game.getState().addDesignation(new Speed(), game, getId()); + game.informPlayers(this.getLogName() + "'s speed is now 1."); } @Override - public void increaseSpeed() { + public void increaseSpeed(Game game) { if (speed < 4) { speed++; + game.informPlayers(this.getLogName() + "'s speed has increased to " + speed); } }