Add Ertai's Meddling

This commit is contained in:
Alumi
2021-03-19 16:11:46 +00:00
committed by Michael Kamensky
parent ef3e91e8a8
commit 903b0130c7
9 changed files with 67 additions and 9 deletions

View File

@@ -1010,7 +1010,11 @@ public class PlayerControllerAi extends PlayerController {
} else {
if (sa.isCopied()) {
if (sa.isSpell()) {
player.getGame().getStackZone().add(sa.getHostCard());
if (!sa.getHostCard().isInZone(ZoneType.Stack)) {
sa.setHostCard(player.getGame().getAction().moveToStack(sa.getHostCard(), sa));
} else {
player.getGame().getStackZone().add(sa.getHostCard());
}
}
/* FIXME: the new implementation (below) requires implementing setupNewTargets in the AI controller, among other possible changes, otherwise breaks AI

View File

@@ -1452,6 +1452,8 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
Card movedCard = null;
if (srcSA.hasParam("Destination")) {
final boolean remember = srcSA.hasParam("RememberChanged");
final boolean rememberSpell = srcSA.hasParam("RememberSpell");
final boolean imprint = srcSA.hasParam("Imprint");
if (tgtSA.isAbility()) {
// Shouldn't be able to target Abilities but leaving this in for now
} else if (srcSA.getParam("Destination").equals("Graveyard")) {
@@ -1484,6 +1486,12 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
srcSA.getHostCard().addRemembered(tgtHost);
// TODO or remember moved?
}
if (rememberSpell) {
srcSA.getHostCard().addRemembered(tgtSA);
}
if (imprint) {
srcSA.getHostCard().addImprintedCard(tgtHost);
}
if (!tgtSA.isAbility()) {
System.out.println("Moving spell to " + srcSA.getParam("Destination"));

View File

@@ -466,6 +466,12 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
return states.get(state);
}
public void setOriginalStateAsFaceDown() {
// For Ertai's Meddling a morph spell
currentState = CardUtil.getFaceDownCharacteristic(this, CardStateName.Original);
states.put(CardStateName.Original, currentState);
}
public boolean setState(final CardStateName state, boolean updateView) {
return setState(state, updateView, false);
}

View File

@@ -181,7 +181,8 @@ public class CardFactory {
*/
public final static SpellAbility copySpellAbilityAndPossiblyHost(final SpellAbility sourceSA, final SpellAbility targetSA, final Player controller) {
//it is only necessary to copy the host card if the SpellAbility is a spell, not an ability
final Card c = targetSA.isSpell() ? copySpellHost(sourceSA, targetSA, controller) : targetSA.getHostCard();
final Card c = targetSA.isSpell() && !sourceSA.hasParam("UseOriginalHost") ?
copySpellHost(sourceSA, targetSA, controller) : targetSA.getHostCard();
final SpellAbility copySA;
if (targetSA.isTrigger() && targetSA.isWrapper()) {

View File

@@ -117,8 +117,10 @@ public class CardFactoryUtil {
@Override
public void resolve() {
if (!hostCard.isFaceDown()) {
hostCard.setOriginalStateAsFaceDown();
}
hostCard.getGame().getAction().moveToPlay(hostCard, this);
//c.setPreFaceDownState(CardStateName.Original);
}
@Override

View File

@@ -360,10 +360,14 @@ public final class CardUtil {
}
public static CardState getFaceDownCharacteristic(Card c) {
return getFaceDownCharacteristic(c, CardStateName.FaceDown);
}
public static CardState getFaceDownCharacteristic(Card c, CardStateName state) {
final CardType type = new CardType(false);
type.add("Creature");
final CardState ret = new CardState(c, CardStateName.FaceDown);
final CardState ret = new CardState(c, state);
ret.setBasePower(2);
ret.setBaseToughness(2);
@@ -371,10 +375,14 @@ public final class CardUtil {
ret.setType(type);
//show hidden if exiled facedown
if (c.isInZone(ZoneType.Exile))
ret.setImageKey(ImageKeys.getTokenKey(c.isForetold() ? ImageKeys.FORETELL_IMAGE : ImageKeys.HIDDEN_CARD));
else
ret.setImageKey(ImageKeys.getTokenKey(c.isManifested() ? ImageKeys.MANIFEST_IMAGE : ImageKeys.MORPH_IMAGE));
if (state == CardStateName.FaceDown) {
if (c.isInZone(ZoneType.Exile))
ret.setImageKey(ImageKeys.getTokenKey(c.isForetold() ? ImageKeys.FORETELL_IMAGE : ImageKeys.HIDDEN_CARD));
else
ret.setImageKey(ImageKeys.getTokenKey(c.isManifested() ? ImageKeys.MANIFEST_IMAGE : ImageKeys.MORPH_IMAGE));
} else {
ret.setImageKey(c.getImageKey());
}
return ret;
}

View File

@@ -984,6 +984,12 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
// always set this to false, it is only set in CopyEffect
clone.mayChooseNewTargets = false;
// Copied spell is not cast face down
if (clone instanceof Spell) {
Spell spell = (Spell) clone;
spell.setCastFaceDown(false);
}
clone.triggeringObjects = AbilityKey.newMap(this.triggeringObjects);
clone.setPayCosts(getPayCosts().copy());

View File

@@ -0,0 +1,19 @@
Name:Ertai's Meddling
ManaCost:X U
Types:Instant
Text:X can't be 0.\r\n
A:SP$ ChangeZone | Cost$ XCantBe0 X U | TgtZone$ Stack | TargetType$ Spell | ValidTgts$ Card | Origin$ Stack | Destination$ Exile | Imprint$ True | RememberSpell$ True | SubAbility$ DBPutCounter | SpellDescription$ Target spell's controller exiles it with X delay counters on it.
SVar:X:Count$xPaid
SVar:DBPutCounter:DB$ PutCounter | Defined$ Imprinted | CounterType$ DELAY | CounterNum$ X | SubAbility$ DBDelayEffect
SVar:DBDelayEffect:DB$ Effect | EffectOwner$ TargetedController | RememberObjects$ Remembered | ImprintCards$ Imprinted | Triggers$ TrigDelay,TrigExile | Duration$ Permanent | SubAbility$ DBForget
SVar:DBForget:DB$ Cleanup | ClearRemembered$ True | ClearImprinted$ True
# Add a fake trigger to display spell ability text ingame
T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | TriggerZones$ Command | Execute$ TrigLoseDelay | TriggerDescription$ At the beginning of each of that player's upkeeps, if that card is exiled, remove a delay counter from it. If the card has no delay counters on it, the player puts it onto the stack as a copy of the original spell.
SVar:TrigDelay:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | TriggerZones$ Command | Execute$ TrigLoseDelay | TriggerDescription$ At the beginning of each of that player's upkeeps, if that card is exiled, remove a delay counter from it. If the card has no delay counters on it, the player puts it onto the stack as a copy of the original spell.
SVar:TrigLoseDelay:DB$ RemoveCounter | Defined$ Imprinted | CounterType$ DELAY | CounterNum$ 1 | SubAbility$ DBPutOntoStack
SVar:DBPutOntoStack:DB$ CopySpellAbility | Defined$ Remembered | Controller$ You | UseOriginalHost$ True | ConditionDefined$ Imprinted | ConditionPresent$ Card.counters_EQ0_DELAY
SVar:TrigExile:Mode$ ChangesZone | Origin$ Exile | Destination$ Any | Static$ True | ValidCard$ Card.IsImprinted | TriggerZones$ Command | Execute$ TrigExileSelf
SVar:TrigExileSelf:DB$ ChangeZone | Defined$ Self | Origin$ Command | Destination$ Exile
AI:RemoveDeck:All
AI:RemoveDeck:Random
Oracle:X can't be 0.\nTarget spell's controller exiles it with X delay counters on it.\nAt the beginning of each of that player's upkeeps, if that card is exiled, remove a delay counter from it. If the card has no delay counters on it, the player puts it onto the stack as a copy of the original spell.

View File

@@ -1856,7 +1856,11 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
if (next.isCopied()) {
if (next.isSpell()) {
// copied spell always add to stack
player.getGame().getStackZone().add(next.getHostCard());
if (!next.getHostCard().isInZone(ZoneType.Stack)) {
next.setHostCard(player.getGame().getAction().moveToStack(next.getHostCard(), next));
} else {
player.getGame().getStackZone().add(next.getHostCard());
}
}
// TODO check if static abilities needs to be run for things affecting the copy?
if (next.isMayChooseNewTargets()) {