mirror of
https://github.com/magefree/mage.git
synced 2025-12-28 22:42:03 -08:00
Implementing "Start your engines!" mechanic (#13259)
* add initial speed handling * finish speed implementation * remove skip list * add initial test * add some more tests * change speed initialization to state-based action * add opponent speed check * add control change test * add check for speed 5
This commit is contained in:
parent
655af10b2e
commit
ef213b1bef
11 changed files with 393 additions and 15 deletions
|
|
@ -38,9 +38,21 @@ class MaxSpeedAbilityEffect extends ContinuousEffectImpl {
|
|||
|
||||
private final Ability ability;
|
||||
|
||||
private static Duration getDuration(Ability ability) {
|
||||
switch (ability.getZone()) {
|
||||
case BATTLEFIELD:
|
||||
return Duration.WhileOnBattlefield;
|
||||
case GRAVEYARD:
|
||||
return Duration.WhileInGraveyard;
|
||||
default:
|
||||
return Duration.Custom;
|
||||
}
|
||||
}
|
||||
|
||||
MaxSpeedAbilityEffect(Ability ability) {
|
||||
super(Duration.Custom, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility);
|
||||
super(getDuration(ability), Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility);
|
||||
this.ability = ability;
|
||||
this.ability.setRuleVisible(false);
|
||||
}
|
||||
|
||||
private MaxSpeedAbilityEffect(final MaxSpeedAbilityEffect effect) {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,9 @@ import mage.abilities.Ability;
|
|||
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
|
||||
|
|
|
|||
|
|
@ -1,17 +1,21 @@
|
|||
package mage.abilities.keyword;
|
||||
|
||||
import mage.abilities.StaticAbility;
|
||||
import mage.abilities.dynamicvalue.common.ControllerSpeedCount;
|
||||
import mage.abilities.hint.Hint;
|
||||
import mage.abilities.hint.ValueHint;
|
||||
import mage.constants.Zone;
|
||||
|
||||
/**
|
||||
* 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);
|
||||
this.addHint(hint);
|
||||
}
|
||||
|
||||
private StartYourEnginesAbility(final StartYourEnginesAbility ability) {
|
||||
|
|
@ -25,6 +29,6 @@ public class StartYourEnginesAbility extends StaticAbility {
|
|||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "Start your engines!";
|
||||
return "start your engines!";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@ package mage.designations;
|
|||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
108
Mage/src/main/java/mage/designations/Speed.java
Normal file
108
Mage/src/main/java/mage/designations/Speed.java
Normal file
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -2862,6 +2862,11 @@ public abstract class GameImpl implements Game {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (perm.getAbilities(this).containsClass(StartYourEnginesAbility.class)) {
|
||||
Optional.ofNullable(perm.getControllerId())
|
||||
.map(this::getPlayer)
|
||||
.ifPresent(player -> player.initSpeed(this));
|
||||
}
|
||||
}
|
||||
//201300713 - 704.5k
|
||||
// If a player controls two or more legendary permanents with the same name, that player
|
||||
|
|
|
|||
|
|
@ -216,6 +216,12 @@ public interface Player extends MageItem, Copyable<Player> {
|
|||
|
||||
boolean isDrawsOnOpponentsTurn();
|
||||
|
||||
int getSpeed();
|
||||
|
||||
void initSpeed(Game game);
|
||||
|
||||
void increaseSpeed(Game game);
|
||||
|
||||
/**
|
||||
* Returns alternative casting costs a player can cast spells for
|
||||
*
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import mage.counters.CounterType;
|
|||
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;
|
||||
|
|
@ -153,6 +154,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> alternativeSourceCosts = new ArrayList<>();
|
||||
|
|
@ -252,6 +254,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
this.canPlotFromTopOfLibrary = player.canPlotFromTopOfLibrary;
|
||||
this.drawsFromBottom = player.drawsFromBottom;
|
||||
this.drawsOnOpponentsTurn = player.drawsOnOpponentsTurn;
|
||||
this.speed = player.speed;
|
||||
|
||||
this.attachments.addAll(player.attachments);
|
||||
|
||||
|
|
@ -367,6 +370,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
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 +484,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
this.canPlotFromTopOfLibrary = false;
|
||||
this.drawsFromBottom = false;
|
||||
this.drawsOnOpponentsTurn = false;
|
||||
this.speed = 0;
|
||||
|
||||
this.sacrificeCostFilter = null;
|
||||
this.alternativeSourceCosts.clear();
|
||||
|
|
@ -4674,6 +4679,29 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
return drawsOnOpponentsTurn;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSpeed() {
|
||||
return speed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initSpeed(Game game) {
|
||||
if (speed > 0) {
|
||||
return;
|
||||
}
|
||||
speed = 1;
|
||||
game.getState().addDesignation(new Speed(), game, getId());
|
||||
game.informPlayers(this.getLogName() + "'s speed is now 1.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void increaseSpeed(Game game) {
|
||||
if (speed < 4) {
|
||||
speed++;
|
||||
game.informPlayers(this.getLogName() + "'s speed has increased to " + speed);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean autoLoseGame() {
|
||||
return false;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue