mirror of
https://github.com/magefree/mage.git
synced 2026-01-22 19:29:59 -08:00
[Ready for review] Implementing Warp mechanic (#13847)
* add initial warp mechanic implementation * a few small changes * add hand restriction * add void support * add test * [EOE] Implement Timeline Culler * add void test * [EOE] Implement Close Encounter * [EOE] Implement Tannuk, Steadfast Second * a few requested changes * add comment * [EOE] Implement Full Bore * small rewrite * merge fix * remove reminder text * small code rewrite
This commit is contained in:
parent
ae0e4e1483
commit
df70ab7c8a
9 changed files with 752 additions and 15 deletions
|
|
@ -1,10 +1,21 @@
|
|||
package mage.abilities.keyword;
|
||||
|
||||
import mage.MageIdentifier;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.SpellAbility;
|
||||
import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility;
|
||||
import mage.abilities.condition.Condition;
|
||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.cards.Card;
|
||||
import mage.constants.SpellAbilityType;
|
||||
import mage.constants.TimingRule;
|
||||
import mage.constants.*;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.players.Player;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
|
|
@ -12,16 +23,60 @@ import mage.constants.TimingRule;
|
|||
public class WarpAbility extends SpellAbility {
|
||||
|
||||
public static final String WARP_ACTIVATION_VALUE_KEY = "warpActivation";
|
||||
private final boolean allowGraveyard;
|
||||
|
||||
public WarpAbility(Card card, String manaString) {
|
||||
super(new ManaCostsImpl<>(manaString), card.getName() + " with Warp");
|
||||
this(card, manaString, false);
|
||||
}
|
||||
|
||||
public WarpAbility(Card card, String manaString, boolean allowGraveyard) {
|
||||
super(card.getSpellAbility());
|
||||
this.newId();
|
||||
this.setCardName(card.getName() + " with Warp");
|
||||
this.zone = Zone.HAND;
|
||||
this.spellAbilityType = SpellAbilityType.BASE_ALTERNATE;
|
||||
this.setAdditionalCostsRuleVisible(false);
|
||||
this.timing = TimingRule.SORCERY;
|
||||
this.clearManaCosts();
|
||||
this.clearManaCostsToPay();
|
||||
this.addCost(new ManaCostsImpl<>(manaString));
|
||||
this.setAdditionalCostsRuleVisible(false);
|
||||
this.allowGraveyard = allowGraveyard;
|
||||
}
|
||||
|
||||
private WarpAbility(final WarpAbility ability) {
|
||||
super(ability);
|
||||
this.allowGraveyard = ability.allowGraveyard;
|
||||
}
|
||||
|
||||
// The ability sets up a delayed trigger which can't be set up using the cost tag system
|
||||
public static void addDelayedTrigger(SpellAbility spellAbility, Game game) {
|
||||
if (spellAbility instanceof WarpAbility) {
|
||||
game.addDelayedTriggeredAbility(
|
||||
new AtTheBeginOfNextEndStepDelayedTriggeredAbility(new WarpExileEffect()), spellAbility
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActivationStatus canActivate(UUID playerId, Game game) {
|
||||
switch (game.getState().getZone(getSourceId())) {
|
||||
case GRAVEYARD:
|
||||
if (!allowGraveyard) {
|
||||
break;
|
||||
}
|
||||
case HAND:
|
||||
return super.canActivate(playerId, game);
|
||||
}
|
||||
return ActivationStatus.getFalse();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean activate(Game game, Set<MageIdentifier> allowedIdentifiers, boolean noMana) {
|
||||
if (!super.activate(game, allowedIdentifiers, noMana)) {
|
||||
return false;
|
||||
}
|
||||
this.setCostsTag(WARP_ACTIVATION_VALUE_KEY, null);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -43,9 +98,60 @@ public class WarpAbility extends SpellAbility {
|
|||
sb.append(getCosts().getText());
|
||||
sb.append('.');
|
||||
}
|
||||
sb.append(" <i>(You may cast this card from your hand for its warp cost. ");
|
||||
sb.append("Exile this creature at the beginning of the next end step, ");
|
||||
sb.append("then you may cast it from exile on a later turn.)</i>");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static String makeWarpString(UUID playerId) {
|
||||
return playerId + "- Warped";
|
||||
}
|
||||
}
|
||||
|
||||
class WarpExileEffect extends OneShotEffect {
|
||||
|
||||
private static class WarpCondition implements Condition {
|
||||
|
||||
private final int turnNumber;
|
||||
|
||||
WarpCondition(Game game) {
|
||||
this.turnNumber = game.getTurnNum();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return game.getTurnNum() > turnNumber;
|
||||
}
|
||||
}
|
||||
|
||||
WarpExileEffect() {
|
||||
super(Outcome.Benefit);
|
||||
staticText = "exile this creature if it was cast for its warp cost";
|
||||
}
|
||||
|
||||
private WarpExileEffect(final WarpExileEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WarpExileEffect copy() {
|
||||
return new WarpExileEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player player = game.getPlayer(source.getControllerId());
|
||||
Permanent permanent = game.getPermanent(source.getSourceId());
|
||||
if (permanent == null || permanent.getZoneChangeCounter(game) != source.getSourceObjectZoneChangeCounter() + 1) {
|
||||
return false;
|
||||
}
|
||||
player.moveCardsToExile(
|
||||
permanent, source, game, true,
|
||||
CardUtil.getExileZoneId(WarpAbility.makeWarpString(player.getId()), game),
|
||||
"Warped by " + player.getLogName()
|
||||
);
|
||||
CardUtil.makeCardPlayable(
|
||||
game, source, permanent.getMainCard(), true,
|
||||
Duration.Custom, false, player.getId(), new WarpCondition(game)
|
||||
);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import mage.abilities.costs.mana.ManaCosts;
|
|||
import mage.abilities.keyword.BestowAbility;
|
||||
import mage.abilities.keyword.PrototypeAbility;
|
||||
import mage.abilities.keyword.TransformAbility;
|
||||
import mage.abilities.keyword.WarpAbility;
|
||||
import mage.cards.*;
|
||||
import mage.constants.*;
|
||||
import mage.counters.Counter;
|
||||
|
|
@ -421,6 +422,7 @@ public class Spell extends StackObjectImpl implements Card {
|
|||
} else {
|
||||
MageObjectReference mor = new MageObjectReference(getSpellAbility());
|
||||
game.storePermanentCostsTags(mor, getSpellAbility());
|
||||
WarpAbility.addDelayedTrigger(getSpellAbility(), game);
|
||||
return controller.moveCards(card, Zone.BATTLEFIELD, ability, game, false, faceDown, false, null);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
package mage.watchers.common;
|
||||
|
||||
import mage.abilities.keyword.WarpAbility;
|
||||
import mage.constants.WatcherScope;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.ZoneChangeEvent;
|
||||
import mage.game.stack.Spell;
|
||||
import mage.watchers.Watcher;
|
||||
|
||||
import java.util.HashSet;
|
||||
|
|
@ -12,8 +14,6 @@ import java.util.Set;
|
|||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* TODO: this doesn't handle warp yet
|
||||
*
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class VoidWatcher extends Watcher {
|
||||
|
|
@ -29,6 +29,10 @@ public class VoidWatcher extends Watcher {
|
|||
public void watch(GameEvent event, Game game) {
|
||||
switch (event.getType()) {
|
||||
case SPELL_CAST:
|
||||
Spell spell = game.getSpell(event.getTargetId());
|
||||
if (spell != null && spell.getSpellAbility() instanceof WarpAbility) {
|
||||
players.addAll(game.getState().getPlayersInRange(spell.getControllerId(), game));
|
||||
}
|
||||
return;
|
||||
case ZONE_CHANGE:
|
||||
ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue