Merge branch 'spellAbilityAdditionalAbilities' into 'master'

SpellAbility: use SpellAbility for additionalAbilities so Trigger can have cost

See merge request core-developers/forge!4303
This commit is contained in:
Michael Kamensky
2021-03-30 04:47:45 +00:00
26 changed files with 79 additions and 72 deletions

View File

@@ -44,7 +44,6 @@ import forge.game.mana.ManaPool;
import forge.game.phase.PhaseType;
import forge.game.player.Player;
import forge.game.spellability.AbilityManaPart;
import forge.game.spellability.AbilitySub;
import forge.game.spellability.SpellAbility;
import forge.game.trigger.TriggerType;
import forge.game.zone.PlayerZone;
@@ -1346,7 +1345,7 @@ public abstract class GameState {
}
else if (info.startsWith("OnAdventure")) {
String abAdventure = "DB$ Effect | RememberObjects$ Self | StaticAbilities$ Play | ExileOnMoved$ Exile | Duration$ Permanent | ConditionDefined$ Self | ConditionPresent$ Card.nonCopiedSpell";
AbilitySub saAdventure = (AbilitySub)AbilityFactory.getAbility(abAdventure, c);
SpellAbility saAdventure = AbilityFactory.getAbility(abAdventure, c);
StringBuilder sbPlay = new StringBuilder();
sbPlay.append("Mode$ Continuous | MayPlay$ True | EffectZone$ Command | Affected$ Card.IsRemembered+nonAdventure");
sbPlay.append(" | AffectedZone$ Exile | Description$ You may cast the card.");

View File

@@ -159,8 +159,7 @@ public class SpecialCardAi {
final PhaseHandler ph = ai.getGame().getPhaseHandler();
final Combat combat = ai.getGame().getCombat();
Card animated = AnimateAi.becomeAnimated(sa.getHostCard(), sa);
animated.addType("Creature");
Card animated = AnimateAi.becomeAnimated(sa.getHostCard(), sa.getSubAbility());
if (sa.getHostCard().canReceiveCounters(CounterEnumType.P1P1)) {
animated.addCounter(CounterEnumType.P1P1, 2, ai, false, null);
}
@@ -170,10 +169,6 @@ public class SpecialCardAi {
return isOppEOT || isValuableAttacker || isValuableBlocker;
}
public static SpellAbility considerAnimating(final Player ai, final SpellAbility sa, final List<SpellAbility> options) {
return ai.getGame().getPhaseHandler().getPhase().isBefore(PhaseType.MAIN2) ? options.get(0) : options.get(1);
}
}
// Cursed Scroll

View File

@@ -299,7 +299,7 @@ public abstract class SpellAbilityAi {
final AbilitySub subAb = ab.getSubAbility();
return SpellApiToAi.Converter.get(ab.getApi()).chkAIDrawback(ab, aiPlayer) && (subAb == null || chkDrawbackWithSubs(aiPlayer, subAb));
}
public boolean confirmAction(Player player, SpellAbility sa, PlayerActionConfirmMode mode, String message) {
System.err.println("Warning: default (ie. inherited from base class) implementation of confirmAction is used by " + sa.getHostCard().getName() + " for " + this.getClass().getName() + ". Consider declaring an overloaded method");
return true;

View File

@@ -30,6 +30,7 @@ import forge.game.cost.CostPutCounter;
import forge.game.phase.PhaseHandler;
import forge.game.phase.PhaseType;
import forge.game.player.Player;
import forge.game.player.PlayerActionConfirmMode;
import forge.game.spellability.SpellAbility;
import forge.game.staticability.StaticAbility;
import forge.game.staticability.StaticAbilityContinuous;
@@ -243,6 +244,11 @@ public class AnimateAi extends SpellAbilityAi {
return true;
}
@Override
public boolean confirmAction(Player player, SpellAbility sa, PlayerActionConfirmMode mode, String message) {
return player.getGame().getPhaseHandler().getPhase().isBefore(PhaseType.MAIN2);
}
private boolean animateTgtAI(final SpellAbility sa) {
final Player ai = sa.getActivatingPlayer();
final PhaseHandler ph = ai.getGame().getPhaseHandler();

View File

@@ -363,8 +363,6 @@ public class ChooseGenericEffectAi extends SpellAbilityAi {
} else if ("Riot".equals(logic)) {
SpellAbility counterSA = spells.get(0), hasteSA = spells.get(1);
return preferHasteForRiot(sa, player) ? hasteSA : counterSA;
} else if ("CrawlingBarrens".equals(logic)) {
return SpecialCardAi.CrawlingBarrens.considerAnimating(player, sa, spells);
}
return spells.get(0); // return first choice if no logic found
}

View File

@@ -313,7 +313,12 @@ public class CountersPutAi extends SpellAbilityAi {
} else if (logic.startsWith("MoveCounter")) {
return doMoveCounterLogic(ai, sa, ph);
} else if (logic.equals("CrawlingBarrens")) {
return SpecialCardAi.CrawlingBarrens.consider(ai, sa);
boolean willActivate = SpecialCardAi.CrawlingBarrens.consider(ai, sa);
if (willActivate && ph.getPhase().isBefore(PhaseType.MAIN2)) {
// don't use this for mana until after combat
AiCardMemory.rememberCard(ai, source, AiCardMemory.MemorySet.HELD_MANA_SOURCES_FOR_MAIN2);
}
return willActivate;
}
if (!sa.metConditions() && sa.getSubAbility() == null) {

View File

@@ -16,7 +16,6 @@ import forge.game.card.CardPredicates.Presets;
import forge.game.card.CardUtil;
import forge.game.phase.PhaseType;
import forge.game.player.Player;
import forge.game.spellability.AbilitySub;
import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType;
import forge.util.TextUtil;
@@ -67,7 +66,7 @@ public class RepeatEachAi extends SpellAbilityAi {
return false;
} else if ("AllPlayerLoseLife".equals(logic)) {
final Card source = sa.getHostCard();
AbilitySub repeat = sa.getAdditionalAbility("RepeatSubAbility");
SpellAbility repeat = sa.getAdditionalAbility("RepeatSubAbility");
String svar = repeat.getSVar(repeat.getParam("LifeAmount"));
// replace RememberedPlayerCtrl with YouCtrl

View File

@@ -53,6 +53,7 @@ public final class AbilityFactory {
static final List<String> additionalAbilityKeys = Lists.newArrayList(
"WinSubAbility", "OtherwiseSubAbility", // Clash
"BidSubAbility", // BidLifeEffect
"ChooseNumberSubAbility", "Lowest", "Highest", "NotLowest", // ChooseNumber
"HeadsSubAbility", "TailsSubAbility", "LoseSubAbility", // FlipCoin
"TrueSubAbility", "FalseSubAbility", // Branch
@@ -272,7 +273,7 @@ public final class AbilityFactory {
for (final String key : additionalAbilityKeys) {
if (mapParams.containsKey(key) && spellAbility.getAdditionalAbility(key) == null) {
spellAbility.setAdditionalAbility(key, getSubAbility(state, mapParams.get(key), sVarHolder));
spellAbility.setAdditionalAbility(key, getAbility(state, mapParams.get(key), sVarHolder));
}
}

View File

@@ -12,6 +12,8 @@ import forge.game.card.Card;
import forge.game.card.CardUtil;
import forge.game.event.GameEventCardStatsChanged;
import forge.game.spellability.SpellAbility;
import forge.util.Lang;
import forge.util.TextUtil;
public class AnimateEffect extends AnimateEffectBase {
@@ -139,6 +141,17 @@ public class AnimateEffect extends AnimateEffectBase {
List<Card> tgts = getCardsfromTargets(sa);
if (sa.hasParam("Optional")) {
final String targets = Lang.joinHomogenous(tgts);
final String message = sa.hasParam("OptionQuestion")
? TextUtil.fastReplace(sa.getParam("OptionQuestion"), "TARGETS", targets)
: getStackDescription(sa);
if (!sa.getActivatingPlayer().getController().confirmAction(sa, null, message)) {
return;
}
}
for (final Card c : tgts) {
doAnimate(c, sa, power, toughness, types, removeTypes, finalDesc,
keywords, removeKeywords, hiddenKeywords,
@@ -229,9 +242,7 @@ public class AnimateEffect extends AnimateEffectBase {
final List<Card> tgts = getCardsfromTargets(sa);
for (final Card c : tgts) {
sb.append(c).append(" ");
}
sb.append(Lang.joinHomogenous(tgts)).append(" ");
// if power is -1, we'll assume it's not just setting toughness
if (power != null && toughness != null) {

View File

@@ -2,13 +2,11 @@ package forge.game.ability.effects;
import com.google.common.collect.Iterables;
import forge.game.ability.AbilityFactory;
import forge.game.ability.AbilityUtils;
import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card;
import forge.game.player.Player;
import forge.game.player.PlayerActionConfirmMode;
import forge.game.spellability.AbilitySub;
import forge.game.spellability.SpellAbility;
import forge.util.Localizer;
import forge.util.collect.FCollection;
@@ -67,10 +65,10 @@ public class BidLifeEffect extends SpellAbilityEffect {
host.setChosenNumber(bid);
host.addRemembered(winner);
final SpellAbility action = AbilityFactory.getAbility(host.getSVar(sa.getParam("BidSubAbility")), host);
action.setActivatingPlayer(sa.getActivatingPlayer());
((AbilitySub) action).setParent(sa);
AbilityUtils.resolve(action);
final SpellAbility action = sa.getAdditionalAbility("BidSubAbility");
if (action != null) {
AbilityUtils.resolve(action);
}
host.clearRemembered();
}
}

View File

@@ -3,7 +3,6 @@ package forge.game.ability.effects;
import forge.game.ability.AbilityUtils;
import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card;
import forge.game.spellability.AbilitySub;
import forge.game.spellability.SpellAbility;
import forge.util.Expressions;
@@ -24,7 +23,7 @@ public class BranchEffect extends SpellAbilityEffect {
final int svarValue = AbilityUtils.calculateAmount(host, branchSVar, sa);
final int operandValue = AbilityUtils.calculateAmount(host, operand, sa);
AbilitySub sub = null;
SpellAbility sub = null;
if (Expressions.compare(svarValue, operator, operandValue)) {
sub = sa.getAdditionalAbility("TrueSubAbility");
} else {

View File

@@ -11,7 +11,6 @@ import forge.game.ability.AbilityUtils;
import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card;
import forge.game.player.Player;
import forge.game.spellability.AbilitySub;
import forge.game.spellability.SpellAbility;
import forge.game.spellability.TargetRestrictions;
import forge.util.Localizer;
@@ -106,7 +105,7 @@ public class ChooseNumberEffect extends SpellAbilityEffect {
}
card.getGame().getAction().notifyOfValue(sa, card, sb.toString(), null);
if (sa.hasParam("ChooseNumberSubAbility")) {
AbilitySub sub = sa.getAdditionalAbility("ChooseNumberSubAbility");
SpellAbility sub = sa.getAdditionalAbility("ChooseNumberSubAbility");
for (Player p : chooseMap.keySet()) {
card.addRemembered(p);
@@ -117,7 +116,7 @@ public class ChooseNumberEffect extends SpellAbilityEffect {
}
if (sa.hasParam("Lowest")) {
AbilitySub sub = sa.getAdditionalAbility("Lowest");
SpellAbility sub = sa.getAdditionalAbility("Lowest");
for (Player p : lowestNum) {
card.addRemembered(p);
@@ -134,7 +133,7 @@ public class ChooseNumberEffect extends SpellAbilityEffect {
notLowestNum.add(p);
}
}
AbilitySub sub = sa.getAdditionalAbility("NotLowest");
SpellAbility sub = sa.getAdditionalAbility("NotLowest");
for (Player p : notLowestNum) {
card.addRemembered(p);
@@ -144,7 +143,7 @@ public class ChooseNumberEffect extends SpellAbilityEffect {
}
if (sa.hasParam("Highest")) {
AbilitySub sub = sa.getAdditionalAbility("Highest");
SpellAbility sub = sa.getAdditionalAbility("Highest");
for (Player p : highestNum) {
card.addRemembered(p);

View File

@@ -6,7 +6,6 @@ import forge.game.ability.AbilityUtils;
import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card;
import forge.game.player.Player;
import forge.game.spellability.AbilitySub;
import forge.game.spellability.SpellAbility;
import forge.game.spellability.TargetRestrictions;
import forge.util.Aggregates;
@@ -63,7 +62,7 @@ public class ChoosePlayerEffect extends SpellAbilityEffect {
}
// SubAbility that only fires if a player is chosen
AbilitySub chosenSA = sa.getAdditionalAbility("ChooseSubAbility");
SpellAbility chosenSA = sa.getAdditionalAbility("ChooseSubAbility");
if (chosenSA != null) {
if (!chosenSA.getHostCard().equals(sa.getHostCard())) {
System.out.println("Warning: ChooseSubAbility had the wrong host set (potentially after cloning the root SA), attempting to correct...");
@@ -73,7 +72,7 @@ public class ChoosePlayerEffect extends SpellAbilityEffect {
}
} else {
// SubAbility that only fires if a player is not chosen
AbilitySub notChosenSA = sa.getAdditionalAbility("CantChooseSubAbility");
SpellAbility notChosenSA = sa.getAdditionalAbility("CantChooseSubAbility");
if (notChosenSA != null) {
if (!notChosenSA.getHostCard().equals(sa.getHostCard())) {
System.out.println("Warning: CantChooseSubAbility had the wrong host set (potentially after cloning the root SA), attempting to correct...");

View File

@@ -9,7 +9,6 @@ import forge.game.ability.AbilityUtils;
import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card;
import forge.game.player.Player;
import forge.game.spellability.AbilitySub;
import forge.game.spellability.SpellAbility;
import forge.game.trigger.TriggerType;
import forge.game.zone.PlayerZone;
@@ -39,14 +38,14 @@ public class ClashEffect extends SpellAbilityEffect {
if (victory) {
AbilitySub sub = sa.getAdditionalAbility("WinSubAbility");
SpellAbility sub = sa.getAdditionalAbility("WinSubAbility");
if (sub != null) {
AbilityUtils.resolve(sub);
}
runParams.put(AbilityKey.Won, "True");
} else {
AbilitySub sub = sa.getAdditionalAbility("OtherwiseSubAbility");
SpellAbility sub = sa.getAdditionalAbility("OtherwiseSubAbility");
if (sub != null) {
AbilityUtils.resolve(sub);
}

View File

@@ -82,9 +82,11 @@ public class DelayedTriggerEffect extends SpellAbilityEffect {
}
if (sa.hasAdditionalAbility("Execute")) {
AbilitySub overridingSA = (AbilitySub)sa.getAdditionalAbility("Execute").copy(lki, sa.getActivatingPlayer(), false);
SpellAbility overridingSA = sa.getAdditionalAbility("Execute").copy(lki, sa.getActivatingPlayer(), false);
// need to reset the parent, additionalAbility does set it to this
overridingSA.setParent(null);
if (overridingSA instanceof AbilitySub) {
((AbilitySub)overridingSA).setParent(null);
}
// Set Transform timestamp when the delayed trigger is created
if (ApiType.SetState == overridingSA.getApi()) {
overridingSA.setSVar("StoredTransform", String.valueOf(sa.getHostCard().getTransformedTimestamp()));

View File

@@ -13,7 +13,6 @@ import forge.game.card.Card;
import forge.game.event.GameEventFlipCoin;
import forge.game.player.Player;
import forge.game.player.PlayerController;
import forge.game.spellability.AbilitySub;
import forge.game.spellability.SpellAbility;
import forge.game.trigger.TriggerType;
import forge.util.Localizer;
@@ -97,7 +96,7 @@ public class FlipCoinEffect extends SpellAbilityEffect {
}
}
if (countHeads > 0) {
AbilitySub sub = sa.getAdditionalAbility("HeadsSubAbility");
SpellAbility sub = sa.getAdditionalAbility("HeadsSubAbility");
if (sub != null) {
if (sa.hasParam("Amount")) {
sub.setSVar(varName, "Number$" + countHeads);
@@ -106,7 +105,7 @@ public class FlipCoinEffect extends SpellAbilityEffect {
}
}
if (countTails > 0) {
AbilitySub sub = sa.getAdditionalAbility("TailsSubAbility");
SpellAbility sub = sa.getAdditionalAbility("TailsSubAbility");
if (sub != null) {
if (sa.hasParam("Amount")) {
sub.setSVar(varName, "Number$" + countTails);

View File

@@ -75,9 +75,11 @@ public class ImmediateTriggerEffect extends SpellAbilityEffect {
}
if (sa.hasAdditionalAbility("Execute")) {
AbilitySub overridingSA = (AbilitySub)sa.getAdditionalAbility("Execute").copy(lki, sa.getActivatingPlayer(), false);
SpellAbility overridingSA = sa.getAdditionalAbility("Execute").copy(lki, sa.getActivatingPlayer(), false);
// need to set Parent to null, otherwise it might have wrong root ability
overridingSA.setParent(null);
if (overridingSA instanceof AbilitySub) {
((AbilitySub)overridingSA).setParent(null);
}
if (sa.hasParam("CopyTriggeringObjects")) {
overridingSA.setTriggeringObjects(sa.getTriggeringObjects());

View File

@@ -15,7 +15,6 @@ import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
import forge.game.card.CardLists;
import forge.game.player.Player;
import forge.game.spellability.AbilitySub;
import forge.game.spellability.SpellAbility;
import forge.game.spellability.TargetRestrictions;
import forge.game.zone.ZoneType;
@@ -105,7 +104,7 @@ public class MultiplePilesEffect extends SpellAbilityEffect {
}
}
AbilitySub sub = sa.getAdditionalAbility("ChosenPile");
SpellAbility sub = sa.getAdditionalAbility("ChosenPile");
if (sub != null) {
AbilityUtils.resolve(sub);
}

View File

@@ -16,7 +16,6 @@ import forge.game.card.CardDamageMap;
import forge.game.card.CardLists;
import forge.game.card.CardZoneTable;
import forge.game.player.Player;
import forge.game.spellability.AbilitySub;
import forge.game.spellability.SpellAbility;
import forge.game.spellability.SpellAbilityStackInstance;
import forge.game.zone.ZoneType;
@@ -33,7 +32,7 @@ public class RepeatEachEffect extends SpellAbilityEffect {
// Things to loop over: Cards, Players, or SAs
final Card source = sa.getHostCard();
final AbilitySub repeat = sa.getAdditionalAbility("RepeatSubAbility");
final SpellAbility repeat = sa.getAdditionalAbility("RepeatSubAbility");
if (repeat != null && !repeat.getHostCard().equalsWithTimestamp(source)) {
// TODO: for some reason, the host card of the original additional SA is set to the cloned card when

View File

@@ -7,7 +7,6 @@ import forge.game.card.Card;
import forge.game.card.CardCollectionView;
import forge.game.card.CardLists;
import forge.game.player.Player;
import forge.game.spellability.AbilitySub;
import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType;
import forge.util.Expressions;
@@ -25,7 +24,7 @@ public class RepeatEffect extends SpellAbilityEffect {
Card source = sa.getHostCard();
// setup subability to repeat
AbilitySub repeat = sa.getAdditionalAbility("RepeatSubAbility");
SpellAbility repeat = sa.getAdditionalAbility("RepeatSubAbility");
if (repeat != null && !repeat.getHostCard().equals(source)) {
// TODO: for some reason, the host card of the original additional SA is set to the cloned card when

View File

@@ -9,7 +9,6 @@ import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
import forge.game.card.CardLists;
import forge.game.player.Player;
import forge.game.spellability.AbilitySub;
import forge.game.spellability.SpellAbility;
import forge.game.spellability.TargetRestrictions;
import forge.game.zone.ZoneType;
@@ -161,7 +160,7 @@ public class TwoPilesEffect extends SpellAbilityEffect {
card.addRemembered(z);
}
AbilitySub sub = sa.getAdditionalAbility("ChosenPile");
SpellAbility sub = sa.getAdditionalAbility("ChosenPile");
if (sub != null) {
AbilityUtils.resolve(sub);
}
@@ -174,7 +173,7 @@ public class TwoPilesEffect extends SpellAbilityEffect {
card.addRemembered(z);
}
AbilitySub sub = sa.getAdditionalAbility("UnchosenPile");
SpellAbility sub = sa.getAdditionalAbility("UnchosenPile");
if (sub != null) {
AbilityUtils.resolve(sub);
}

View File

@@ -538,8 +538,8 @@ public class CardFactory {
if (from.getSubAbility() != null) {
to.setSubAbility((AbilitySub) from.getSubAbility().copy(host, p, lki));
}
for (Map.Entry<String, AbilitySub> e : from.getAdditionalAbilities().entrySet()) {
to.setAdditionalAbility(e.getKey(), (AbilitySub) e.getValue().copy(host, p, lki));
for (Map.Entry<String, SpellAbility> e : from.getAdditionalAbilities().entrySet()) {
to.setAdditionalAbility(e.getKey(), e.getValue().copy(host, p, lki));
}
for (Map.Entry<String, List<AbilitySub>> e : from.getAdditionalAbilityLists().entrySet()) {
to.setAdditionalAbilityList(e.getKey(), Lists.transform(e.getValue(), new Function<AbilitySub, AbilitySub>() {

View File

@@ -139,7 +139,7 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
private SpellAbilityCondition conditions = new SpellAbilityCondition();
private AbilitySub subAbility = null;
private Map<String, AbilitySub> additionalAbilities = Maps.newHashMap();
private Map<String, SpellAbility> additionalAbilities = Maps.newHashMap();
private Map<String, List<AbilitySub>> additionalAbilityLists = Maps.newHashMap();
protected ApiType api = null;
@@ -238,7 +238,7 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
if (subAbility != null) {
subAbility.setHostCard(c);
}
for (AbilitySub sa : additionalAbilities.values()) {
for (SpellAbility sa : additionalAbilities.values()) {
if (sa.getHostCard() != c) {
sa.setHostCard(c);
}
@@ -437,7 +437,7 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
if (subAbility != null) {
updated |= subAbility.setActivatingPlayer(player, lki);
}
for (AbilitySub sa : additionalAbilities.values()) {
for (SpellAbility sa : additionalAbilities.values()) {
updated |= sa.setActivatingPlayer(player, lki);
}
for (List<AbilitySub> list : additionalAbilityLists.values()) {
@@ -875,10 +875,10 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
view.updateDescription(this); //description changes when sub-abilities change
}
public Map<String, AbilitySub> getAdditionalAbilities() {
public Map<String, SpellAbility> getAdditionalAbilities() {
return additionalAbilities;
}
public AbilitySub getAdditionalAbility(final String name) {
public SpellAbility getAdditionalAbility(final String name) {
if (hasAdditionalAbility(name)) {
return additionalAbilities.get(name);
}
@@ -889,11 +889,13 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
return additionalAbilities.containsKey(name);
}
public void setAdditionalAbility(final String name, final AbilitySub sa) {
public void setAdditionalAbility(final String name, final SpellAbility sa) {
if (sa == null) {
additionalAbilities.remove(name);
} else {
sa.setParent(this);
if (sa instanceof AbilitySub) {
((AbilitySub)sa).setParent(this);
}
additionalAbilities.put(name, sa);
}
view.updateDescription(this); //description changes when sub-abilities change
@@ -2080,7 +2082,7 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
subAbility.changeText();
}
}
for (AbilitySub sa : additionalAbilities.values()) {
for (SpellAbility sa : additionalAbilities.values()) {
sa.changeText();
}
@@ -2105,7 +2107,7 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
subAbility.changeTextIntrinsic(colorMap, typeMap);
}
}
for (AbilitySub sa : additionalAbilities.values()) {
for (SpellAbility sa : additionalAbilities.values()) {
sa.changeTextIntrinsic(colorMap, typeMap);
}
@@ -2122,7 +2124,7 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
if (subAbility != null) {
subAbility.setIntrinsic(i);
}
for (AbilitySub sa : additionalAbilities.values()) {
for (SpellAbility sa : additionalAbilities.values()) {
if (sa.isIntrinsic() != i) {
sa.setIntrinsic(i);
}

View File

@@ -421,7 +421,7 @@ public class WrappedAbility extends Ability {
}
@Override
public AbilitySub getAdditionalAbility(String ability) {
public SpellAbility getAdditionalAbility(String ability) {
return sa.getAdditionalAbility(ability);
}

View File

@@ -2,9 +2,7 @@ Name:Crawling Barrens
ManaCost:no cost
Types:Land
A:AB$ Mana | Cost$ T | Produced$ C | SpellDescription$ Add {C}.
A:AB$ PutCounter | Cost$ 4 | CounterType$ P1P1 | CounterNum$ 2 | SubAbility$ DBChoice | AILogic$ CrawlingBarrens | SpellDescription$ Put two +1/+1 counters on CARDNAME. Then you may have it become a 0/0 Elemental creature until end of turn. It's still a land.
SVar:DBChoice:DB$ GenericChoice | Defined$ You | Choices$ Animate,NoAnimate | AILogic$ CrawlingBarrens | StackDescription$ Then you may have it become a 0/0 Elemental creature until end of turn. It's still a land.
SVar:Animate:DB$ Animate | Defined$ Self | Power$ 0 | Toughness$ 0 | Types$ Creature,Elemental | SpellDescription$ CARDNAME becomes a 0/0 Elemental creature until end of turn.
SVar:NoAnimate:DB$ Pump | SpellDescription$ CARDNAME does not become a 0/0 Elemental creature until end of turn.
A:AB$ PutCounter | Cost$ 4 | CounterType$ P1P1 | CounterNum$ 2 | SubAbility$ DBAnimate | AILogic$ CrawlingBarrens | SpellDescription$ Put two +1/+1 counters on CARDNAME. Then you may have it become a 0/0 Elemental creature until end of turn. It's still a land.
SVar:DBAnimate:DB$ Animate | Defined$ Self | Power$ 0 | Toughness$ 0 | Types$ Creature,Elemental | Optional$ True
DeckHas:Ability$Counters
Oracle:{T}: Add {C}.\n{4}: Put two +1/+1 counters on Crawling Barrens. Then you may have it become a 0/0 Elemental creature until end of turn. It's still a land.

View File

@@ -5,8 +5,8 @@ PT:1/1
K:Menace
K:Lifelink
R:Event$ Moved | ActiveZones$ Battlefield | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Creature+nonToken+OppOwn | ReplaceWith$ Exile | Description$ If a nontoken creature an opponent controls would die, exile it instead. When you do, you may pay {2}. If you do, create a 1/1 black and green Pest creature token with "When this creature dies, you gain 1 life."
SVar:Exile:DB$ ChangeZone | Hidden$ True | Origin$ All | Destination$ Exile | Defined$ ReplacedCard
T:Mode$ ChangesZone | TriggerZones$ Battlefield | Origin$ Any | Destination$ Exile | ValidCard$ Card.ExiledWithSource | Execute$ TrigToken | Secondary$ True | TriggerDescription$ If a nontoken creature an opponent controls would die, exile it instead. When you do, you may pay {2}. If you do, create a 1/1 black and green Pest creature token with "When this creature dies, you gain 1 life."
SVar:Exile:DB$ ChangeZone | Hidden$ True | Origin$ All | Destination$ Exile | Defined$ ReplacedCard | SubAbility$ DBImmediateTrigger
SVar:DBImmediateTrigger:DB$ ImmediateTrigger | Execute$ TrigToken | TriggerDescription$ If a nontoken creature an opponent controls would die, exile it instead. When you do, you may pay {2}. If you do, create a 1/1 black and green Pest creature token with "When this creature dies, you gain 1 life."
SVar:TrigToken:AB$ Token | Cost$ 2 | TokenAmount$ 1 | TokenScript$ bg_1_1_pest_lifegain | TokenOwner$ You
AlternateMode:Modal
DeckHas:Ability$Token & Ability$LifeGain