mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-15 10:18:01 +00:00
ReplacementEffect: rewrite for Riot and Spark Double
This commit is contained in:
committed by
Michael Kamensky
parent
ca87a5d857
commit
1b47a81b8c
@@ -466,7 +466,7 @@ public class Game {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Zone getZoneOf(final Card card) {
|
public Zone getZoneOf(final Card card) {
|
||||||
return card.getZone();
|
return card.getLastKnownZone();
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized CardCollectionView getCardsIn(final ZoneType zone) {
|
public synchronized CardCollectionView getCardsIn(final ZoneType zone) {
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ import forge.game.ability.effects.AttachEffect;
|
|||||||
import forge.game.card.*;
|
import forge.game.card.*;
|
||||||
import forge.game.event.*;
|
import forge.game.event.*;
|
||||||
import forge.game.keyword.KeywordInterface;
|
import forge.game.keyword.KeywordInterface;
|
||||||
import forge.game.keyword.KeywordsChange;
|
|
||||||
import forge.game.player.GameLossReason;
|
import forge.game.player.GameLossReason;
|
||||||
import forge.game.player.Player;
|
import forge.game.player.Player;
|
||||||
import forge.game.replacement.ReplacementEffect;
|
import forge.game.replacement.ReplacementEffect;
|
||||||
@@ -289,33 +288,6 @@ public class GameAction {
|
|||||||
copied.getOwner().addInboundToken(copied);
|
copied.getOwner().addInboundToken(copied);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (toBattlefield) {
|
|
||||||
// HACK for making the RIOT enchantment look into the Future
|
|
||||||
// need to check the Keywords what it would have on the Battlefield
|
|
||||||
Card riotLKI = CardUtil.getLKICopy(copied);
|
|
||||||
riotLKI.setLastKnownZone(zoneTo);
|
|
||||||
CardCollection preList = new CardCollection(riotLKI);
|
|
||||||
checkStaticAbilities(false, Sets.newHashSet(riotLKI), preList);
|
|
||||||
|
|
||||||
List<Long> changedTimeStamps = Lists.newArrayList();
|
|
||||||
for(Map.Entry<Long, KeywordsChange> e : riotLKI.getChangedCardKeywords().entrySet()) {
|
|
||||||
if (!copied.hasChangedCardKeywords(e.getKey())) {
|
|
||||||
KeywordsChange o = e.getValue();
|
|
||||||
o.setHostCard(copied);
|
|
||||||
for (KeywordInterface k : o.getKeywords()) {
|
|
||||||
for (ReplacementEffect re : k.getReplacements()) {
|
|
||||||
// this param need to be set, otherwise in ReplaceMoved it fails
|
|
||||||
re.getMapParams().put("BypassEtbCheck", "True");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
copied.addChangedCardKeywordsInternal(o, e.getKey());
|
|
||||||
changedTimeStamps.add(e.getKey());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
checkStaticAbilities(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, Object> repParams = Maps.newHashMap();
|
Map<String, Object> repParams = Maps.newHashMap();
|
||||||
repParams.put("Event", "Moved");
|
repParams.put("Event", "Moved");
|
||||||
repParams.put("Affected", copied);
|
repParams.put("Affected", copied);
|
||||||
|
|||||||
@@ -10,8 +10,11 @@ import forge.game.player.Player;
|
|||||||
import forge.game.spellability.SpellAbility;
|
import forge.game.spellability.SpellAbility;
|
||||||
import forge.game.zone.ZoneType;
|
import forge.game.zone.ZoneType;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
public class CloneEffect extends SpellAbilityEffect {
|
public class CloneEffect extends SpellAbilityEffect {
|
||||||
// TODO update this method
|
// TODO update this method
|
||||||
|
|
||||||
@@ -48,6 +51,11 @@ public class CloneEffect extends SpellAbilityEffect {
|
|||||||
final Player activator = sa.getActivatingPlayer();
|
final Player activator = sa.getActivatingPlayer();
|
||||||
Card tgtCard = host;
|
Card tgtCard = host;
|
||||||
final Game game = activator.getGame();
|
final Game game = activator.getGame();
|
||||||
|
final List<String> pumpKeywords = Lists.newArrayList();
|
||||||
|
|
||||||
|
if (sa.hasParam("PumpKeywords")) {
|
||||||
|
pumpKeywords.addAll(Arrays.asList(sa.getParam("PumpKeywords").split(" & ")));
|
||||||
|
}
|
||||||
|
|
||||||
// find cloning source i.e. thing to be copied
|
// find cloning source i.e. thing to be copied
|
||||||
Card cardToCopy = null;
|
Card cardToCopy = null;
|
||||||
@@ -115,6 +123,10 @@ public class CloneEffect extends SpellAbilityEffect {
|
|||||||
tgtCard.setTapped(true);
|
tgtCard.setTapped(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!pumpKeywords.isEmpty()) {
|
||||||
|
tgtCard.addChangedCardKeywords(pumpKeywords, Lists.<String>newArrayList(), false, false, ts);
|
||||||
|
}
|
||||||
|
|
||||||
tgtCard.updateStateForView();
|
tgtCard.updateStateForView();
|
||||||
|
|
||||||
//Clear Remembered and Imprint lists
|
//Clear Remembered and Imprint lists
|
||||||
|
|||||||
@@ -1,16 +1,13 @@
|
|||||||
package forge.game.replacement;
|
package forge.game.replacement;
|
||||||
|
|
||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
import forge.game.card.CardCollection;
|
|
||||||
import forge.game.card.CardUtil;
|
|
||||||
import forge.game.player.Player;
|
import forge.game.player.Player;
|
||||||
import forge.game.spellability.SpellAbility;
|
import forge.game.spellability.SpellAbility;
|
||||||
import forge.game.zone.ZoneType;
|
import forge.game.zone.ZoneType;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import com.google.common.collect.Sets;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO: Write javadoc for this type.
|
* TODO: Write javadoc for this type.
|
||||||
*
|
*
|
||||||
@@ -50,56 +47,23 @@ public class ReplaceMoved extends ReplacementEffect {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean matchedZone = false;
|
|
||||||
if (hasParam("Origin")) {
|
if (hasParam("Origin")) {
|
||||||
for(ZoneType z : ZoneType.listValueOf(getParam("Origin"))) {
|
ZoneType zt = (ZoneType) runParams.get("Origin");
|
||||||
if(z == (ZoneType) runParams.get("Origin"))
|
if (!ZoneType.listValueOf(getParam("Origin")).contains(zt)) {
|
||||||
matchedZone = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!matchedZone)
|
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasParam("Destination")) {
|
if (hasParam("Destination")) {
|
||||||
matchedZone = false;
|
|
||||||
ZoneType zt = (ZoneType) runParams.get("Destination");
|
ZoneType zt = (ZoneType) runParams.get("Destination");
|
||||||
for(ZoneType z : ZoneType.listValueOf(getParam("Destination"))) {
|
if (!ZoneType.listValueOf(getParam("Destination")).contains(zt)) {
|
||||||
if(z == zt)
|
|
||||||
matchedZone = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!matchedZone)
|
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (zt.equals(ZoneType.Battlefield) && getHostCard().equals(affected) && !hasParam("BypassEtbCheck")) {
|
|
||||||
// would be an etb replacement effect that enters the battlefield
|
|
||||||
Card lki = CardUtil.getLKICopy(affected);
|
|
||||||
lki.setLastKnownZone(lki.getController().getZone(zt));
|
|
||||||
|
|
||||||
CardCollection preList = new CardCollection(lki);
|
|
||||||
getHostCard().getGame().getAction().checkStaticAbilities(false, Sets.newHashSet(lki), preList);
|
|
||||||
|
|
||||||
// check if when entering the battlefield would still has this RE or is suppressed
|
|
||||||
if (!lki.hasReplacementEffect(this) || lki.getReplacementEffect(getId()).isSuppressed()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasParam("ExcludeDestination")) {
|
if (hasParam("ExcludeDestination")) {
|
||||||
matchedZone = false;
|
ZoneType zt = (ZoneType) runParams.get("Destination");
|
||||||
for(ZoneType z : ZoneType.listValueOf(getParam("ExcludeDestination"))) {
|
if (ZoneType.listValueOf(getParam("ExcludeDestination")).contains(zt)) {
|
||||||
if(z == (ZoneType) runParams.get("Destination"))
|
|
||||||
matchedZone = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(matchedZone)
|
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,6 +44,8 @@ public abstract class ReplacementEffect extends TriggerReplacementBase {
|
|||||||
/** The has run. */
|
/** The has run. */
|
||||||
private boolean hasRun = false;
|
private boolean hasRun = false;
|
||||||
|
|
||||||
|
private List<ReplacementEffect> otherChoices = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the id.
|
* Gets the id.
|
||||||
*
|
*
|
||||||
@@ -102,6 +104,13 @@ public abstract class ReplacementEffect extends TriggerReplacementBase {
|
|||||||
this.hasRun = hasRun;
|
this.hasRun = hasRun;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<ReplacementEffect> getOtherChoices() {
|
||||||
|
return otherChoices;
|
||||||
|
}
|
||||||
|
public void setOtherChoices(List<ReplacementEffect> choices) {
|
||||||
|
this.otherChoices = choices;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Can replace.
|
* Can replace.
|
||||||
*
|
*
|
||||||
@@ -174,6 +183,7 @@ public abstract class ReplacementEffect extends TriggerReplacementBase {
|
|||||||
if (!lki) {
|
if (!lki) {
|
||||||
res.setId(nextId());
|
res.setId(nextId());
|
||||||
res.setHasRun(false);
|
res.setHasRun(false);
|
||||||
|
res.setOtherChoices(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
res.setHostCard(host);
|
res.setHostCard(host);
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ import forge.game.GameLogEntryType;
|
|||||||
import forge.game.ability.AbilityFactory;
|
import forge.game.ability.AbilityFactory;
|
||||||
import forge.game.ability.AbilityUtils;
|
import forge.game.ability.AbilityUtils;
|
||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
|
import forge.game.card.CardCollection;
|
||||||
|
import forge.game.card.CardUtil;
|
||||||
import forge.game.player.Player;
|
import forge.game.player.Player;
|
||||||
import forge.game.spellability.SpellAbility;
|
import forge.game.spellability.SpellAbility;
|
||||||
import forge.game.zone.Zone;
|
import forge.game.zone.Zone;
|
||||||
@@ -34,6 +36,7 @@ import forge.util.Visitor;
|
|||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
@@ -74,6 +77,34 @@ public class ReplacementHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public List<ReplacementEffect> getReplacementList(final Map<String, Object> runParams, final ReplacementLayer layer) {
|
public List<ReplacementEffect> getReplacementList(final Map<String, Object> runParams, final ReplacementLayer layer) {
|
||||||
|
|
||||||
|
final CardCollection preList = new CardCollection();
|
||||||
|
boolean checkAgain = false;
|
||||||
|
Card affectedLKI = null;
|
||||||
|
Card affectedCard = null;
|
||||||
|
|
||||||
|
if ("Moved".equals(runParams.get("Event")) && ZoneType.Battlefield.equals(runParams.get("Destination"))) {
|
||||||
|
// if it was caused by an replacement effect, use the already calculated RE list
|
||||||
|
// otherwise the RIOT card would cause a StackError
|
||||||
|
SpellAbility cause = (SpellAbility) runParams.get("Cause");
|
||||||
|
if (cause != null && cause.isReplacementAbility()) {
|
||||||
|
final ReplacementEffect re = cause.getReplacementEffect();
|
||||||
|
// only return for same layer
|
||||||
|
if (layer.equals(re.getLayer())) {
|
||||||
|
return re.getOtherChoices();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rule 614.12 Enter the Battlefield Replacement Effects look at what the card would be on the battlefield
|
||||||
|
affectedCard = (Card) runParams.get("Affected");
|
||||||
|
affectedLKI = CardUtil.getLKICopy(affectedCard);
|
||||||
|
affectedLKI.setLastKnownZone(affectedCard.getController().getZone(ZoneType.Battlefield));
|
||||||
|
preList.add(affectedLKI);
|
||||||
|
game.getAction().checkStaticAbilities(false, Sets.newHashSet(affectedLKI), preList);
|
||||||
|
checkAgain = true;
|
||||||
|
runParams.put("Affected", affectedLKI);
|
||||||
|
}
|
||||||
|
|
||||||
final List<ReplacementEffect> possibleReplacers = Lists.newArrayList();
|
final List<ReplacementEffect> possibleReplacers = Lists.newArrayList();
|
||||||
// Round up Non-static replacement effects ("Until EOT," or
|
// Round up Non-static replacement effects ("Until EOT," or
|
||||||
// "The next time you would..." etc)
|
// "The next time you would..." etc)
|
||||||
@@ -87,17 +118,19 @@ public class ReplacementHandler {
|
|||||||
game.forEachCardInGame(new Visitor<Card>() {
|
game.forEachCardInGame(new Visitor<Card>() {
|
||||||
@Override
|
@Override
|
||||||
public boolean visit(Card crd) {
|
public boolean visit(Card crd) {
|
||||||
for (final ReplacementEffect replacementEffect : crd.getReplacementEffects()) {
|
final Card c = preList.get(crd);
|
||||||
|
|
||||||
|
for (final ReplacementEffect replacementEffect : c.getReplacementEffects()) {
|
||||||
|
|
||||||
// Use "CheckLKIZone" parameter to test for effects that care abut where the card was last (e.g. Kalitas, Traitor of Ghet
|
// Use "CheckLKIZone" parameter to test for effects that care abut where the card was last (e.g. Kalitas, Traitor of Ghet
|
||||||
// getting hit by mass removal should still produce tokens).
|
// getting hit by mass removal should still produce tokens).
|
||||||
Zone cardZone = "True".equals(replacementEffect.getMapParams().get("CheckSelfLKIZone")) ? game.getChangeZoneLKIInfo(crd).getLastKnownZone() : game.getZoneOf(crd);
|
Zone cardZone = "True".equals(replacementEffect.getParam("CheckSelfLKIZone")) ? game.getChangeZoneLKIInfo(c).getLastKnownZone() : game.getZoneOf(c);
|
||||||
|
|
||||||
// Replacement effects that are tied to keywords (e.g. damage prevention effects - if the keyword is removed, the replacement
|
// Replacement effects that are tied to keywords (e.g. damage prevention effects - if the keyword is removed, the replacement
|
||||||
// effect should be inactive)
|
// effect should be inactive)
|
||||||
if (replacementEffect.hasParam("TiedToKeyword")) {
|
if (replacementEffect.hasParam("TiedToKeyword")) {
|
||||||
String kw = replacementEffect.getParam("TiedToKeyword");
|
String kw = replacementEffect.getParam("TiedToKeyword");
|
||||||
if (!crd.hasKeyword(kw)) {
|
if (!c.hasKeyword(kw)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -115,6 +148,19 @@ public class ReplacementHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (checkAgain) {
|
||||||
|
if (affectedLKI != null && affectedCard != null) {
|
||||||
|
// need to set the Host Card there so it is not connected to LKI anymore?
|
||||||
|
// need to be done after canReplace check
|
||||||
|
for (final ReplacementEffect re : affectedLKI.getReplacementEffects()) {
|
||||||
|
re.setHostCard(affectedCard);
|
||||||
|
}
|
||||||
|
runParams.put("Affected", affectedCard);
|
||||||
|
}
|
||||||
|
game.getAction().checkStaticAbilities(false);
|
||||||
|
}
|
||||||
|
|
||||||
return possibleReplacers;
|
return possibleReplacers;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,15 +184,18 @@ public class ReplacementHandler {
|
|||||||
possibleReplacers.remove(chosenRE);
|
possibleReplacers.remove(chosenRE);
|
||||||
|
|
||||||
chosenRE.setHasRun(true);
|
chosenRE.setHasRun(true);
|
||||||
ReplacementResult res = this.executeReplacement(runParams, chosenRE, decider, game);
|
chosenRE.setOtherChoices(possibleReplacers);
|
||||||
|
ReplacementResult res = executeReplacement(runParams, chosenRE, decider, game);
|
||||||
if (res == ReplacementResult.NotReplaced) {
|
if (res == ReplacementResult.NotReplaced) {
|
||||||
if (!possibleReplacers.isEmpty()) {
|
if (!possibleReplacers.isEmpty()) {
|
||||||
res = run(runParams);
|
res = run(runParams);
|
||||||
}
|
}
|
||||||
chosenRE.setHasRun(false);
|
chosenRE.setHasRun(false);
|
||||||
|
chosenRE.setOtherChoices(null);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
chosenRE.setHasRun(false);
|
chosenRE.setHasRun(false);
|
||||||
|
chosenRE.setOtherChoices(null);
|
||||||
String message = chosenRE.toString();
|
String message = chosenRE.toString();
|
||||||
if ( !StringUtils.isEmpty(message))
|
if ( !StringUtils.isEmpty(message))
|
||||||
if (chosenRE.getHostCard() != null) {
|
if (chosenRE.getHostCard() != null) {
|
||||||
@@ -210,7 +259,6 @@ public class ReplacementHandler {
|
|||||||
effectSA.setIntrinsic(true);
|
effectSA.setIntrinsic(true);
|
||||||
effectSA.changeText();
|
effectSA.changeText();
|
||||||
}
|
}
|
||||||
effectSA.setReplacementAbility(true);
|
|
||||||
effectSA.setReplacementEffect(replacementEffect);
|
effectSA.setReplacementEffect(replacementEffect);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -278,9 +326,11 @@ public class ReplacementHandler {
|
|||||||
* @return A finished instance
|
* @return A finished instance
|
||||||
*/
|
*/
|
||||||
public static ReplacementEffect parseReplacement(final String repParse, final Card host, final boolean intrinsic) {
|
public static ReplacementEffect parseReplacement(final String repParse, final Card host, final boolean intrinsic) {
|
||||||
|
return ReplacementHandler.parseReplacement(parseParams(repParse), host, intrinsic);
|
||||||
|
}
|
||||||
|
|
||||||
final Map<String, String> mapParams = FileSection.parseToMap(repParse, "$", "|");
|
public static Map<String, String> parseParams(final String repParse) {
|
||||||
return ReplacementHandler.parseReplacement(mapParams, host, intrinsic);
|
return FileSection.parseToMap(repParse, "$", "|");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -91,7 +91,6 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
|||||||
private boolean trigger = false;
|
private boolean trigger = false;
|
||||||
private Trigger triggerObj = null;
|
private Trigger triggerObj = null;
|
||||||
private boolean optionalTrigger = false;
|
private boolean optionalTrigger = false;
|
||||||
private boolean replacementAbility = false;
|
|
||||||
private ReplacementEffect replacementEffect = null;
|
private ReplacementEffect replacementEffect = null;
|
||||||
private int sourceTrigger = -1;
|
private int sourceTrigger = -1;
|
||||||
private List<Object> triggerRemembered = Lists.newArrayList();
|
private List<Object> triggerRemembered = Lists.newArrayList();
|
||||||
@@ -952,13 +951,13 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean isReplacementAbility() {
|
public boolean isReplacementAbility() {
|
||||||
return replacementAbility;
|
return getParent() != null ? getParent().isReplacementAbility() : replacementEffect != null;
|
||||||
}
|
|
||||||
public void setReplacementAbility(boolean replacement) {
|
|
||||||
replacementAbility = replacement;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReplacementEffect getReplacementEffect() {
|
public ReplacementEffect getReplacementEffect() {
|
||||||
|
if (getParent() != null) {
|
||||||
|
return getParent().getReplacementEffect();
|
||||||
|
}
|
||||||
return replacementEffect;
|
return replacementEffect;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -540,7 +540,7 @@ public class StaticAbility extends CardTraitBase implements Comparable<StaticAbi
|
|||||||
|
|
||||||
if (hasParam("EffectZone")) {
|
if (hasParam("EffectZone")) {
|
||||||
if (!getParam("EffectZone").equals("All")) {
|
if (!getParam("EffectZone").equals("All")) {
|
||||||
Zone zone = getHostCard().getZone();
|
Zone zone = game.getZoneOf(getHostCard());
|
||||||
if (zone == null || !ZoneType.listValueOf(getParam("EffectZone")).contains(zone.getZoneType())) {
|
if (zone == null || !ZoneType.listValueOf(getParam("EffectZone")).contains(zone.getZoneType())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1830,6 +1830,37 @@ public class GameSimulatorTest extends SimulationTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void testSparkDoubleAndGideon() {
|
||||||
|
Game game = initAndCreateGame();
|
||||||
|
Player p = game.getPlayers().get(0);
|
||||||
|
game.getPhaseHandler().devModeSet(PhaseType.MAIN1, p);
|
||||||
|
|
||||||
|
for (int i=0; i<7; i++) { addCardToZone("Plains", p, ZoneType.Battlefield); }
|
||||||
|
for (int i=0; i<7; i++) { addCardToZone("Island", p, ZoneType.Battlefield); }
|
||||||
|
|
||||||
|
Card gideon = addCardToZone("Gideon Blackblade", p, ZoneType.Hand);
|
||||||
|
Card sparkDouble = addCardToZone("Spark Double", p, ZoneType.Hand);
|
||||||
|
|
||||||
|
SpellAbility gideonSA = gideon.getFirstSpellAbility();
|
||||||
|
SpellAbility sparkDoubleSA = sparkDouble.getFirstSpellAbility();
|
||||||
|
|
||||||
|
game.getPhaseHandler().devModeSet(PhaseType.MAIN1, p);
|
||||||
|
game.getAction().checkStateEffects(true);
|
||||||
|
|
||||||
|
GameSimulator sim = createSimulator(game, p);
|
||||||
|
sim.simulateSpellAbility(gideonSA);
|
||||||
|
sim.simulateSpellAbility(sparkDoubleSA);
|
||||||
|
|
||||||
|
Game simGame = sim.getSimulatedGameState();
|
||||||
|
Card simSpark = (Card)sim.getGameCopier().find(sparkDouble);
|
||||||
|
|
||||||
|
assert(simSpark != null);
|
||||||
|
assert(simSpark.getZone().is(ZoneType.Battlefield));
|
||||||
|
assert(simSpark.getCounters(CounterType.P1P1) == 1);
|
||||||
|
assert(simSpark.getCounters(CounterType.LOYALTY) == 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public void broken_testCloneDimir() {
|
public void broken_testCloneDimir() {
|
||||||
Game game = initAndCreateGame();
|
Game game = initAndCreateGame();
|
||||||
|
|||||||
7
forge-gui/res/cardsfolder/upcoming/spark_double.txt
Normal file
7
forge-gui/res/cardsfolder/upcoming/spark_double.txt
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
Name:Spark Double
|
||||||
|
ManaCost:3 U
|
||||||
|
Types:Creature Shapeshifter
|
||||||
|
PT:0/0
|
||||||
|
K:ETBReplacement:Copy:DBCopy:Optional
|
||||||
|
SVar:DBCopy:DB$ Clone | Choices$ Creature.Other+YouCtrl,Planeswalker.Other+YouCtrl | NonLegendary$ True | PumpKeywords$ etbCounter:P1P1:1:ValidCard$ Creature.Self:CARDNAME enters with an additional +1/+1 counter on it if it’s a creature & etbCounter:LOYALTY:1:ValidCard$ Planeswalker.Self:CARDNAME enters with an additional loyalty counter on it if it’s a planeswalker | SpellDescription$ You may have CARDNAME enter the battlefield as a copy of a creature or planeswalker you control, except it enters with an additional +1/+1 counter on it if it’s a creature, it enters with an additional loyalty counter on it if it’s a planeswalker, and it isn’t legendary if that permanent is legendary.
|
||||||
|
Oracle:You may have Spark Double enter the battlefield as a copy of a creature or planeswalker you control, except it enters with an additional +1/+1 counter on it if it’s a creature, it enters with an additional loyalty counter on it if it’s a planeswalker, and it isn’t legendary if that permanent is legendary.
|
||||||
Reference in New Issue
Block a user