mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-12 08:48:39 +00:00
Some cleanup (#6712)
This commit is contained in:
@@ -18,7 +18,6 @@
|
||||
package forge.ai;
|
||||
|
||||
import com.esotericsoftware.minlog.Log;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import forge.ai.AiCardMemory.MemorySet;
|
||||
@@ -64,6 +63,7 @@ import io.sentry.Breadcrumb;
|
||||
import io.sentry.Sentry;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
@@ -2208,8 +2208,6 @@ public class AiController {
|
||||
return activePlayerSAs;
|
||||
}
|
||||
|
||||
List<SpellAbility> result = Lists.newArrayList();
|
||||
|
||||
// filter list by ApiTypes
|
||||
List<SpellAbility> discard = filterListByApi(activePlayerSAs, ApiType.Discard);
|
||||
List<SpellAbility> mandatoryDiscard = filterList(discard, SpellAbilityPredicates.isMandatory());
|
||||
@@ -2225,37 +2223,33 @@ public class AiController {
|
||||
List<SpellAbility> pump = filterListByApi(activePlayerSAs, ApiType.Pump);
|
||||
List<SpellAbility> pumpAll = filterListByApi(activePlayerSAs, ApiType.PumpAll);
|
||||
|
||||
List<SpellAbility> result = Lists.newArrayList(activePlayerSAs);
|
||||
|
||||
// do mandatory discard early if hand is empty or has DiscardMe card
|
||||
boolean discardEarly = false;
|
||||
CardCollectionView playerHand = player.getCardsIn(ZoneType.Hand);
|
||||
if (playerHand.isEmpty() || playerHand.anyMatch(CardPredicates.hasSVar("DiscardMe"))) {
|
||||
discardEarly = true;
|
||||
if (!playerHand.isEmpty() && !playerHand.anyMatch(CardPredicates.hasSVar("DiscardMe"))) {
|
||||
result.addAll(mandatoryDiscard);
|
||||
mandatoryDiscard.clear();
|
||||
}
|
||||
|
||||
// token should be added first so they might get the pump bonus
|
||||
result.addAll(token);
|
||||
result.addAll(pump);
|
||||
result.addAll(pumpAll);
|
||||
|
||||
// do Evolve Trigger before other PutCounter SpellAbilities
|
||||
// do putCounter before Draw/Discard because it can cause a Draw Trigger
|
||||
result.addAll(evolve);
|
||||
result.addAll(putCounter);
|
||||
result.addAll(putCounterAll);
|
||||
|
||||
// optional Discard, probably combined with Draw
|
||||
result.addAll(discard);
|
||||
// do Draw before Discard
|
||||
result.addAll(draw);
|
||||
result.addAll(discard); // optional Discard, probably combined with Draw
|
||||
|
||||
if (!discardEarly) {
|
||||
result.addAll(putCounterAll);
|
||||
// do putCounter before Draw/Discard because it can cause a Draw Trigger
|
||||
result.addAll(putCounter);
|
||||
// do Evolve Trigger before other PutCounter SpellAbilities
|
||||
result.addAll(evolve);
|
||||
|
||||
// token should be added first so they might get the pump bonus
|
||||
result.addAll(pumpAll);
|
||||
result.addAll(pump);
|
||||
result.addAll(token);
|
||||
|
||||
result.addAll(mandatoryDiscard);
|
||||
}
|
||||
|
||||
result.addAll(activePlayerSAs);
|
||||
|
||||
//need to reverse because of magic stack
|
||||
Collections.reverse(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -2267,6 +2261,10 @@ public class AiController {
|
||||
}
|
||||
|
||||
// TODO move to more common place
|
||||
public static <T extends TriggerReplacementBase> List<T> filterList(List<T> input, Function<SpellAbility, Object> pred, Object value) {
|
||||
return filterList(input, trb -> pred.apply(trb.ensureAbility()) == value);
|
||||
}
|
||||
|
||||
public static List<SpellAbility> filterListByApi(List<SpellAbility> input, ApiType type) {
|
||||
return filterList(input, SpellAbilityPredicates.isApi(type));
|
||||
}
|
||||
@@ -2303,12 +2301,11 @@ public class AiController {
|
||||
public ReplacementEffect chooseSingleReplacementEffect(List<ReplacementEffect> list) {
|
||||
// no need to choose anything
|
||||
if (list.size() <= 1) {
|
||||
return Iterables.getFirst(list, null);
|
||||
return list.get(0);
|
||||
}
|
||||
|
||||
ReplacementType mode = Iterables.getFirst(list, null).getMode();
|
||||
ReplacementType mode = list.get(0).getMode();
|
||||
|
||||
// replace lifegain effects
|
||||
if (mode.equals(ReplacementType.GainLife)) {
|
||||
List<ReplacementEffect> noGain = filterListByAiLogic(list, "NoLife");
|
||||
List<ReplacementEffect> loseLife = filterListByAiLogic(list, "LoseLife");
|
||||
@@ -2317,16 +2314,16 @@ public class AiController {
|
||||
|
||||
if (!noGain.isEmpty()) {
|
||||
// no lifegain is better than lose life
|
||||
return Iterables.getFirst(noGain, null);
|
||||
return noGain.get(0);
|
||||
} else if (!loseLife.isEmpty()) {
|
||||
// lose life before double life to prevent lose double
|
||||
return Iterables.getFirst(loseLife, null);
|
||||
return loseLife.get(0);
|
||||
} else if (!lichDraw.isEmpty()) {
|
||||
// lich draw before double life to prevent to draw to much
|
||||
return Iterables.getFirst(lichDraw, null);
|
||||
return lichDraw.get(0);
|
||||
} else if (!doubleLife.isEmpty()) {
|
||||
// other than that, do double life
|
||||
return Iterables.getFirst(doubleLife, null);
|
||||
return doubleLife.get(0);
|
||||
}
|
||||
} else if (mode.equals(ReplacementType.DamageDone)) {
|
||||
List<ReplacementEffect> prevention = filterList(list, CardTraitPredicates.hasParam("Prevent"));
|
||||
@@ -2334,7 +2331,7 @@ public class AiController {
|
||||
// TODO when Protection is done as ReplacementEffect do them
|
||||
// before normal prevention
|
||||
if (!prevention.isEmpty()) {
|
||||
return Iterables.getFirst(prevention, null);
|
||||
return prevention.get(0);
|
||||
}
|
||||
} else if (mode.equals(ReplacementType.Destroy)) {
|
||||
List<ReplacementEffect> shield = filterList(list, CardTraitPredicates.hasParam("ShieldCounter"));
|
||||
@@ -2344,30 +2341,35 @@ public class AiController {
|
||||
|
||||
// Indestructible umbra armor is the best
|
||||
if (!umbraArmorIndestructible.isEmpty()) {
|
||||
return Iterables.getFirst(umbraArmorIndestructible, null);
|
||||
return umbraArmorIndestructible.get(0);
|
||||
}
|
||||
|
||||
// then it might be better to remove shield counter if able?
|
||||
if (!shield.isEmpty()) {
|
||||
return Iterables.getFirst(shield, null);
|
||||
return shield.get(0);
|
||||
}
|
||||
|
||||
// TODO get the RunParams for Affected to check if the creature already dealt combat damage for Regeneration effects
|
||||
// is using a Regeneration Effect better than using a Umbra Armor?
|
||||
if (!regeneration.isEmpty()) {
|
||||
return Iterables.getFirst(regeneration, null);
|
||||
return regeneration.get(0);
|
||||
}
|
||||
|
||||
if (!umbraArmor.isEmpty()) {
|
||||
// sort them by cmc
|
||||
umbraArmor.sort(Comparator.comparing(CardTraitBase::getHostCard, Comparator.comparing(Card::getCMC)));
|
||||
return Iterables.getFirst(umbraArmor, null);
|
||||
return umbraArmor.get(0);
|
||||
}
|
||||
} else if (mode.equals(ReplacementType.Draw)) {
|
||||
List<ReplacementEffect> winGame = filterList(list, SpellAbility::getApi, ApiType.WinsGame);
|
||||
if (!winGame.isEmpty()) {
|
||||
return winGame.get(0);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO always lower counters with Vorinclex first, might turn it from 1 to 0 as final
|
||||
|
||||
return Iterables.getFirst(list, null);
|
||||
return list.get(0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -248,10 +248,10 @@ public class CreatureEvaluator implements Function<Card, Integer> {
|
||||
value -= subValue(10, "echo-unpaid");
|
||||
}
|
||||
if (t.isKeyword(Keyword.FADING)) {
|
||||
value -= subValue(20 / (Math.max(1, c.getCounters(CounterEnumType.FADE))), "fading");
|
||||
value -= subValue(20 / (Math.max(1, c.isInPlay() ? c.getCounters(CounterEnumType.FADE) : c.getKeywordMagnitude(Keyword.FADING))), "fading");
|
||||
}
|
||||
if (t.isKeyword(Keyword.VANISHING)) {
|
||||
value -= subValue(20 / (Math.max(1, c.getCounters(CounterEnumType.TIME))), "vanishing");
|
||||
value -= subValue(20 / (Math.max(1, c.isInPlay() ? c.getCounters(CounterEnumType.TIME) : c.getKeywordMagnitude(Keyword.VANISHING))), "vanishing");
|
||||
}
|
||||
|
||||
SpellAbility ab = t.ensureAbility();
|
||||
|
||||
@@ -253,7 +253,7 @@ public final class CardRulesPredicates {
|
||||
}
|
||||
|
||||
public static Predicate<CardRules> canBePartnerCommanderWith(final CardRules commander) {
|
||||
return (rules) -> rules.canBePartnerCommanders(commander);
|
||||
return rules -> rules.canBePartnerCommanders(commander);
|
||||
}
|
||||
|
||||
private static class LeafString extends PredicateString<CardRules> {
|
||||
|
||||
@@ -5,7 +5,6 @@ import java.util.List;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import forge.game.ability.SpellAbilityEffect;
|
||||
import forge.game.card.Card;
|
||||
@@ -45,7 +44,7 @@ public class ActivateAbilityEffect extends SpellAbilityEffect {
|
||||
|
||||
List<Card> list = CardLists.getType(p.getCardsIn(ZoneType.Battlefield), sa.getParamOrDefault("Type", "Card"));
|
||||
for (Card c : list) {
|
||||
List<SpellAbility> possibleAb = Lists.newArrayList(c.getAllPossibleAbilities(p, true));
|
||||
List<SpellAbility> possibleAb = c.getAllPossibleAbilities(p, true);
|
||||
if (isManaAb) {
|
||||
possibleAb.retainAll((FCollection<SpellAbility>)c.getManaAbilities());
|
||||
}
|
||||
|
||||
@@ -880,13 +880,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
||||
* a {@link forge.game.spellability.SpellAbility} object.
|
||||
*/
|
||||
private void changeHiddenOriginResolve(final SpellAbility sa) {
|
||||
List<Player> fetchers;
|
||||
|
||||
if (sa.hasParam("DefinedPlayer")) {
|
||||
fetchers = AbilityUtils.getDefinedPlayers(sa.getHostCard(), sa.getParam("DefinedPlayer"), sa);
|
||||
} else {
|
||||
fetchers = Lists.newArrayList(sa.getActivatingPlayer());
|
||||
}
|
||||
List<Player> fetchers = AbilityUtils.getDefinedPlayers(sa.getHostCard(), sa.getParam("DefinedPlayer"), sa);
|
||||
|
||||
Player chooser = null;
|
||||
if (sa.hasParam("Chooser")) {
|
||||
@@ -1059,7 +1053,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
||||
handleCastWhileSearching(fetchList, decider);
|
||||
}
|
||||
final Map<AbilityKey, Object> runParams = AbilityKey.mapFromPlayer(decider);
|
||||
runParams.put(AbilityKey.Target, Lists.newArrayList(player));
|
||||
runParams.put(AbilityKey.Target, player);
|
||||
game.getTriggerHandler().runTrigger(TriggerType.SearchedLibrary, runParams, false);
|
||||
}
|
||||
if (searchedLibrary && sa.hasParam("Searched")) {
|
||||
|
||||
@@ -22,7 +22,6 @@ public class ChooseCardNameEffect extends SpellAbilityEffect {
|
||||
|
||||
@Override
|
||||
protected String getStackDescription(SpellAbility sa) {
|
||||
|
||||
return Lang.joinHomogenous(getTargetPlayers(sa)) + " names a card.";
|
||||
}
|
||||
|
||||
@@ -58,21 +57,6 @@ public class ChooseCardNameEffect extends SpellAbilityEffect {
|
||||
continue;
|
||||
}
|
||||
String chosen;
|
||||
//This section was used for Momir Avatar, which no longer uses it - commented out 7/28/2021
|
||||
//if (randomChoice) {
|
||||
//String numericAmount = "X";
|
||||
//final int validAmount = StringUtils.isNumeric(numericAmount) ? Integer.parseInt(numericAmount) :
|
||||
// AbilityUtils.calculateAmount(host, numericAmount, sa);
|
||||
// Momir needs PaperCard
|
||||
//Collection<PaperCard> cards = StaticData.instance().getCommonCards().getUniqueCards();
|
||||
//Predicate<PaperCard> cpp = Predicates.and(
|
||||
// Predicates.compose(CardRulesPredicates.IS_CREATURE, PaperCard.FN_GET_RULES),
|
||||
// Predicates.compose(CardRulesPredicates.cmc(ComparableOp.EQUALS, validAmount), PaperCard.FN_GET_RULES));
|
||||
//cards = Lists.newArrayList(Iterables.filter(cards, cpp));
|
||||
//if (!cards.isEmpty()) { chosen = Aggregates.random(cards).getName();
|
||||
//} else {
|
||||
// chosen = "";
|
||||
//}
|
||||
if (chooseFromDefined) {
|
||||
CardCollection choices = AbilityUtils.getDefinedCards(host, sa.getParam("ChooseFromDefinedCards"), sa);
|
||||
choices = CardLists.getValidCards(choices, valid, host.getController(), host, sa);
|
||||
|
||||
@@ -2,12 +2,11 @@ package forge.game.ability.effects;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import forge.game.Game;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
import forge.game.ability.SpellAbilityEffect;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.CardCollectionView;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.util.CardTranslation;
|
||||
@@ -23,9 +22,9 @@ public class ControlExchangeEffect extends SpellAbilityEffect {
|
||||
protected String getStackDescription(SpellAbility sa) {
|
||||
Card object1 = null;
|
||||
Card object2 = null;
|
||||
List<Card> tgts = null;
|
||||
CardCollectionView tgts = null;
|
||||
if (sa.usesTargeting()) {
|
||||
tgts = Lists.newArrayList(sa.getTargets().getTargetCards());
|
||||
tgts = sa.getTargets().getTargetCards();
|
||||
if (tgts.size() > 0) {
|
||||
object1 = tgts.get(0);
|
||||
}
|
||||
@@ -57,9 +56,9 @@ public class ControlExchangeEffect extends SpellAbilityEffect {
|
||||
Card object1 = null;
|
||||
Card object2 = null;
|
||||
|
||||
List<Card> tgts = null;
|
||||
CardCollectionView tgts = null;
|
||||
if (sa.usesTargeting()) {
|
||||
tgts = Lists.newArrayList(sa.getTargets().getTargetCards());
|
||||
tgts = sa.getTargets().getTargetCards();
|
||||
if (tgts.size() > 0) {
|
||||
object1 = tgts.get(0);
|
||||
}
|
||||
|
||||
@@ -72,10 +72,7 @@ public class CopySpellAbilityEffect extends SpellAbilityEffect {
|
||||
return;
|
||||
}
|
||||
|
||||
List<Player> controllers = Lists.newArrayList(sa.getActivatingPlayer());
|
||||
if (sa.hasParam("Controller")) {
|
||||
controllers = AbilityUtils.getDefinedPlayers(card, sa.getParam("Controller"), sa);
|
||||
}
|
||||
List<Player> controllers = AbilityUtils.getDefinedPlayers(card, sa.getParam("Controller"), sa);
|
||||
|
||||
boolean isOptional = sa.hasParam("Optional");
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ public class DrawEffect extends SpellAbilityEffect {
|
||||
|
||||
final List<Player> tgts = getTargetPlayersWithDuplicates(true, "Defined", sa);
|
||||
|
||||
for (final Player p : Sets.newHashSet(tgts)) {
|
||||
for (final Player p : Sets.newLinkedHashSet(tgts)) {
|
||||
if (!p.isInGame()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -98,7 +98,7 @@ public class FlipOntoBattlefieldEffect extends SpellAbilityEffect {
|
||||
// as well as the current card attachments that are visually located next to the requested card or are assumed to be near it.
|
||||
Player controller = c.getController();
|
||||
ArrayList<Card> attachments = Lists.newArrayList();
|
||||
ArrayList<Card> cardsOTB = Lists.newArrayList(CardLists.filter(
|
||||
CardCollection cardsOTB = CardLists.filter(
|
||||
controller.getCardsIn(ZoneType.Battlefield), card -> {
|
||||
if (card.isAttachedToEntity(c)) {
|
||||
attachments.add(card);
|
||||
@@ -114,7 +114,7 @@ public class FlipOntoBattlefieldEffect extends SpellAbilityEffect {
|
||||
}
|
||||
return card.sharesCardTypeWith(c);
|
||||
}
|
||||
));
|
||||
);
|
||||
|
||||
// Chance to hit an attachment
|
||||
float hitAttachment = 0.50f;
|
||||
|
||||
@@ -26,7 +26,7 @@ public class LifeGainEffect extends SpellAbilityEffect {
|
||||
|
||||
sb.append(Lang.joinHomogenous(getDefinedPlayersOrTargeted(sa)));
|
||||
if (sb.length() == 0 && spellDesc != null) {
|
||||
return (spellDesc);
|
||||
return spellDesc;
|
||||
} else {
|
||||
sb.append(getDefinedPlayersOrTargeted(sa).size() > 1 ? " gain " : " gains ");
|
||||
if (!StringUtils.isNumeric(amountStr) && spellDesc != null && spellDesc.contains("life equal to")) {
|
||||
|
||||
@@ -29,7 +29,7 @@ public class RestartGameEffect extends SpellAbilityEffect {
|
||||
List<ZoneType> restartZones = new ArrayList<>(Arrays.asList(ZoneType.Battlefield,
|
||||
ZoneType.Library, ZoneType.Graveyard, ZoneType.Hand, ZoneType.Exile));
|
||||
|
||||
ZoneType leaveZone = ZoneType.smartValueOf(sa.hasParam("RestrictFromZone") ? sa.getParam("RestrictFromZone") : null);
|
||||
ZoneType leaveZone = ZoneType.smartValueOf(sa.getParam("RestrictFromZone"));
|
||||
restartZones.remove(leaveZone);
|
||||
String leaveRestriction = sa.getParamOrDefault("RestrictFromValid", "Card");
|
||||
|
||||
|
||||
@@ -252,7 +252,7 @@ public class AbilityManaPart implements java.io.Serializable {
|
||||
eff.setColor(MagicColor.COLORLESS);
|
||||
eff.setGamePieceType(GamePieceType.EFFECT);
|
||||
|
||||
String cantcounterstr = "Event$ Counter | ValidCard$ Card.IsRemembered | Description$ That spell can't be countered.";
|
||||
String cantcounterstr = "Event$ Counter | ValidSA$ Spell.IsRemembered | Description$ That spell can't be countered.";
|
||||
ReplacementEffect re = ReplacementHandler.parseReplacement(cantcounterstr, eff, true);
|
||||
re.setLayer(ReplacementLayer.CantHappen);
|
||||
eff.addReplacementEffect(re);
|
||||
|
||||
@@ -453,11 +453,9 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
||||
}
|
||||
public void setActivatingPlayer(final Player player) {
|
||||
// trickle down activating player
|
||||
boolean updated = false;
|
||||
// don't use equals because player might be from simulation
|
||||
if (player == null || player != activatingPlayer) {
|
||||
activatingPlayer = player;
|
||||
updated = true;
|
||||
}
|
||||
if (subAbility != null) {
|
||||
subAbility.setActivatingPlayer(player);
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
*/
|
||||
package forge.game.trigger;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import forge.game.ability.AbilityKey;
|
||||
@@ -60,9 +59,8 @@ public class TriggerSearchedLibrary extends Trigger {
|
||||
return false;
|
||||
}
|
||||
if (hasParam("SearchOwnLibrary")) {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Player> targets = (List<Player>) runParams.get(AbilityKey.Target);
|
||||
if (!targets.contains(runParams.get(AbilityKey.Player))) {
|
||||
Player target = (Player) runParams.get(AbilityKey.Target);
|
||||
if (!target.equals(runParams.get(AbilityKey.Player))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ Types:Legendary Creature Human Knight
|
||||
PT:4/4
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigToken | TriggerDescription$ Whenever CARDNAME enters or attacks, create a Virtuous Role token attached to another target creature you control. (If you control another Role on it, put that one into the graveyard. Enchanted creature gets +1/+1 for each enchantment you control.)
|
||||
T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigToken | Secondary$ True | TriggerDescription$ Whenever CARDNAME enters or attacks, create a Virtuous Role token attached to another target creature you control. (If you control another Role on it, put that one into the graveyard. Enchanted creature gets +1/+1 for each enchantment you control.)
|
||||
SVar:TrigToken:DB$ Token | TokenScript$ role_virtuous | AttachedTo$ Targeted | ValidTgts$ Creature.YouCtrl+Other
|
||||
SVar:TrigToken:DB$ Token | TokenScript$ role_virtuous | AttachedTo$ Targeted | ValidTgts$ Creature.YouCtrl+Other | TokenOwner$ You
|
||||
T:Mode$ DamageDone | ValidSource$ Creature.YouCtrl+enchanted | ValidTarget$ Player | CombatDamage$ True | TriggerZones$ Battlefield | Execute$ TrigDraw | TriggerDescription$ Whenever an enchanted creature you control deals combat damage to a player, draw a card.
|
||||
SVar:TrigDraw:DB$ Draw
|
||||
SVar:HasAttackEffect:TRUE
|
||||
|
||||
@@ -4,7 +4,7 @@ Types:Legendary Creature Goblin Rogue
|
||||
PT:2/2
|
||||
K:etbCounter:P1P1:X
|
||||
SVar:X:Count$xPaid
|
||||
A:AB$ ChangeZone | Cost$ 2 | Defined$ BottomOfLibrary | Origin$ Library | Destination$ Graveyard | RememberChanged$ True | SubAbility$ DBChangeZone | StackDescription$ SpellDescription | SpellDescription$ Put the bottom card of your library into your graveyard. If it's a creature card with power less than or equal to CARDNAME's power, put it onto the battlefield.
|
||||
A:AB$ ChangeZone | Cost$ 2 | Defined$ BottomOfLibrary | Origin$ Library | Destination$ Graveyard | RememberChanged$ True | SubAbility$ DBChangeZone | StackDescription$ SpellDescription | SpellDescription$ Put the bottom card of your library into your graveyard. If it's a creature card with power less than or equal to NICKNAME's power, put it onto the battlefield.
|
||||
SVar:DBChangeZone:DB$ ChangeZone | Defined$ Remembered | Origin$ All | Destination$ Battlefield | Hidden$ True | ConditionDefined$ Remembered | ConditionPresent$ Card.Creature+powerLEY | ConditionCompare$ GE1 | SubAbility$ DBCleanup
|
||||
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||
SVar:Y:Count$CardPower
|
||||
|
||||
@@ -2,5 +2,7 @@ Name:Veiled Apparition
|
||||
ManaCost:1 U
|
||||
Types:Enchantment
|
||||
T:Mode$ SpellCast | ValidCard$ Card | ValidActivatingPlayer$ Opponent | TriggerZones$ Battlefield | IsPresent$ Card.Self+Enchantment | Execute$ TrigAnimate | TriggerDescription$ When an opponent casts a spell, if CARDNAME is an enchantment, CARDNAME becomes a 3/3 Illusion creature with flying and "At the beginning of your upkeep, sacrifice CARDNAME unless you pay {1}{U}."
|
||||
SVar:TrigAnimate:DB$ Animate | Defined$ Self | Power$ 3 | Toughness$ 3 | Keywords$ Flying & UpkeepCost:1 U | Types$ Creature,Illusion | RemoveCardTypes$ True | RemoveCreatureTypes$ True | Duration$ Permanent
|
||||
SVar:TrigAnimate:DB$ Animate | Defined$ Self | Power$ 3 | Toughness$ 3 | Keywords$ Flying | Triggers$ UpkeepCostTrigger | Types$ Creature,Illusion | RemoveCardTypes$ True | RemoveCreatureTypes$ True | Duration$ Permanent
|
||||
SVar:UpkeepCostTrigger:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigUpkeep | TriggerDescription$ At the beginning of your upkeep, sacrifice CARDNAME unless you pay {1}{U}.
|
||||
SVar:TrigUpkeep:DB$ Sacrifice | UnlessPayer$ You | UnlessCost$ 1 U
|
||||
Oracle:When an opponent casts a spell, if Veiled Apparition is an enchantment, Veiled Apparition becomes a 3/3 Illusion creature with flying and "At the beginning of your upkeep, sacrifice Veiled Apparition unless you pay {1}{U}."
|
||||
|
||||
Reference in New Issue
Block a user