diff --git a/forge-ai/src/main/java/forge/ai/ability/DamageDealAi.java b/forge-ai/src/main/java/forge/ai/ability/DamageDealAi.java index e452056b8f1..7622a9422be 100644 --- a/forge-ai/src/main/java/forge/ai/ability/DamageDealAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/DamageDealAi.java @@ -95,8 +95,8 @@ protected boolean canPlayAI(Player ai, SpellAbility sa) { final String damage = sa.getParam("NumDmg"); int dmg = AbilityUtils.calculateAmount(source, damage, sa); - if (damage.equals("X") || source.getSVar("X").equals("Count$xPaid") || sourceName.equals("Crater's Claws")) { - if (sa.getSVar("X").equals("Count$xPaid") || sa.getSVar(damage).equals("Count$xPaid") || sourceName.equals("Crater's Claws")) { + if (damage.equals("X") || source.getSVar("X").equals("Count$xPaid")) { + if (sa.getSVar("X").equals("Count$xPaid") || sa.getSVar(damage).equals("Count$xPaid")) { dmg = ComputerUtilCost.getMaxXValue(sa, ai, sa.isTrigger()); // Try not to waste spells like Blaze or Fireball on early targets, try to do more damage with them if possible @@ -106,7 +106,7 @@ protected boolean canPlayAI(Player ai, SpellAbility sa) { if (MyRandom.percentTrue(holdChance)) { int threshold = aic.getIntProperty(AiProps.HOLD_X_DAMAGE_SPELLS_THRESHOLD); boolean inDanger = ComputerUtil.aiLifeInDanger(ai, false, 0); - boolean isLethal = sa.getTargetRestrictions().canTgtPlayer() && dmg >= ai.getWeakestOpponent().getLife() && !ai.getWeakestOpponent().cantLoseForZeroOrLessLife(); + boolean isLethal = sa.usesTargeting() && sa.getTargetRestrictions().canTgtPlayer() && dmg >= ai.getWeakestOpponent().getLife() && !ai.getWeakestOpponent().cantLoseForZeroOrLessLife(); if (dmg < threshold && ai.getGame().getPhaseHandler().getTurn() / 2 < threshold && !inDanger && !isLethal) { return false; } @@ -116,7 +116,7 @@ protected boolean canPlayAI(Player ai, SpellAbility sa) { // Set PayX here to maximum value. It will be adjusted later depending on the target. sa.setXManaCostPaid(dmg); } else if (sa.getSVar(damage).contains("InYourHand") && source.isInZone(ZoneType.Hand)) { - dmg = AbilityUtils.calculateAmount(source, damage, sa) - 1; // the card will be spent casting the spell, so actual damage is 1 less + dmg -= - 1; // the card will be spent casting the spell, so actual damage is 1 less } else if (sa.getSVar(damage).equals("TargetedPlayer$CardsInHand")) { // cards that deal damage by the number of cards in target player's hand, e.g. Sudden Impact if (sa.getTargetRestrictions().canTgtPlayer()) { @@ -260,11 +260,9 @@ protected boolean canPlayAI(Player ai, SpellAbility sa) { AiController aic = ((PlayerControllerAi)ai.getController()).getAi(); aic.reserveManaSourcesForNextSpell(chainDmg.getKey(), sa); } - } else { + } else if (!damageTargetAI(ai, sa, dmg, false)) { // simple targeting when there is no spell chaining plan - if (!damageTargetAI(ai, sa, dmg, false)) { - return false; - } + return false; } if ((damage.equals("X") && sa.getSVar(damage).equals("Count$xPaid")) || diff --git a/forge-core/src/main/java/forge/card/DeckHints.java b/forge-core/src/main/java/forge/card/DeckHints.java index 6b7d2b0435a..6d4d3cc4910 100644 --- a/forge-core/src/main/java/forge/card/DeckHints.java +++ b/forge-core/src/main/java/forge/card/DeckHints.java @@ -196,7 +196,11 @@ private Iterable getCardsForFilter(Iterable cardList, Type Iterables.addAll(cards, getMatchingItems(cardList, CardRulesPredicates.name(StringOp.EQUALS, p), PaperCard::getRules)); break; case TYPE: - Iterables.addAll(cards, getMatchingItems(cardList, CardRulesPredicates.joinedType(StringOp.CONTAINS_IC, p), PaperCard::getRules)); + Predicate typePred = CardRulesPredicates.joinedType(StringOp.CONTAINS_IC, p); + if (CardType.isACreatureType(p)) { + typePred = Predicates.or(CardRulesPredicates.hasKeyword("Changeling"), typePred); + } + Iterables.addAll(cards, getMatchingItems(cardList, typePred, PaperCard::getRules)); break; case NONE: case ABILITY: // already done above diff --git a/forge-game/src/main/java/forge/game/GameAction.java b/forge-game/src/main/java/forge/game/GameAction.java index 6b75fb6b610..e7acdb002b9 100644 --- a/forge-game/src/main/java/forge/game/GameAction.java +++ b/forge-game/src/main/java/forge/game/GameAction.java @@ -249,13 +249,6 @@ private Card changeZone(final Zone zoneFrom, Zone zoneTo, final Card c, Integer copied = new CardCopyService(c).copyCard(false); - // CR 707.12 casting of a card copy - if (zoneTo.is(ZoneType.Stack) && c.isRealToken()) { - copied.setCopiedPermanent(c.getCopiedPermanent()); - //TODO: Feels like this should fit here and seems to work but it'll take a fair bit more testing to be sure. - //copied.setGamePieceType(GamePieceType.COPIED_SPELL); - } - copied.setGameTimestamp(c.getGameTimestamp()); if (zoneTo.is(ZoneType.Stack)) { @@ -267,6 +260,13 @@ private Card changeZone(final Zone zoneFrom, Zone zoneTo, final Card c, Integer copied.setExiledBy(c.getExiledBy()); copied.setDrawnThisTurn(c.getDrawnThisTurn()); + // CR 707.12 casting of a card copy + if (c.isRealToken()) { + copied.setCopiedPermanent(c.getCopiedPermanent()); + //TODO: Feels like this should fit here and seems to work but it'll take a fair bit more testing to be sure. + //copied.setGamePieceType(GamePieceType.COPIED_SPELL); + } + if (c.isTransformed()) { copied.incrementTransformedTimestamp(); } @@ -277,6 +277,7 @@ private Card changeZone(final Zone zoneFrom, Zone zoneTo, final Card c, Integer // CR 112.2 A spell’s controller is, by default, the player who put it on the stack. copied.setController(cause.getActivatingPlayer(), 0); + KeywordInterface kw = cause.getKeyword(); if (kw != null) { copied.addKeywordForStaticAbility(kw); @@ -290,25 +291,24 @@ private Card changeZone(final Zone zoneFrom, Zone zoneTo, final Card c, Integer copied.setBackSide(false); } - copied.setUnearthed(c.isUnearthed()); - // need to copy counters when card enters another zone than hand or library if (lastKnownInfo.hasKeyword("Counters remain on CARDNAME as it moves to any zone other than a player's hand or library.") && !(zoneTo.is(ZoneType.Hand) || zoneTo.is(ZoneType.Library))) { copied.setCounters(Maps.newHashMap(lastKnownInfo.getCounters())); } - } - // perpetual stuff - if (c.hasIntensity()) { - copied.setIntensity(c.getIntensity(false)); - } - if (c.isSpecialized()) { - copied.setState(c.getCurrentStateName(), false); - } - if (c.hasPerpetual()) { - copied.setPerpetual(c); + // perpetual stuff + if (c.hasIntensity()) { + copied.setIntensity(c.getIntensity(false)); + } + if (c.isSpecialized()) { + copied.setState(c.getCurrentStateName(), false); + } + if (c.hasPerpetual()) { + copied.setPerpetual(c); + } } + // ensure that any leftover keyword/type changes are cleared in the state view copied.updateStateForView(); @@ -780,8 +780,6 @@ private Card moveTo(final Zone zoneTo, Card c, Integer position, SpellAbility ca final Zone zoneFrom = game.getZoneOf(c); // String prevName = prev != null ? prev.getZoneName() : ""; - // Card lastKnownInfo = c; - // Handle the case that one component of a merged permanent got take to the subgame if (zoneTo.is(ZoneType.Subgame) && (c.hasMergedCard() || c.isMerged())) { c.moveMergedToSubgame(cause); @@ -913,7 +911,7 @@ public final Card moveToVariantDeck(Card c, ZoneType zone, int deckPosition, Spe } return changeZone(game.getZoneOf(c), deck, c, deckPosition, cause, params); } - + public final Card moveToJunkyard(Card c, SpellAbility cause, Map params) { final PlayerZone junkyard = c.getOwner().getZone(ZoneType.Junkyard); return moveTo(junkyard, c, cause, params); @@ -931,7 +929,6 @@ public final Card exile(final Card c, SpellAbility cause, Map runParams = AbilityKey.mapFromCard(c); runParams.put(AbilityKey.Cause, cause); if (origin != null) { // is generally null when adding via dev mode @@ -1264,10 +1261,9 @@ public boolean checkStateEffects(final boolean runEvents, final Set affect AbilityKey.addCardZoneTableParams(mapParams, table); for (final Player p : game.getPlayers()) { - for (final ZoneType zt : ZoneType.values()) { - if (zt == ZoneType.Command) - p.checkKeywordCard(); + p.checkKeywordCard(); + for (final ZoneType zt : ZoneType.values()) { if (zt == ZoneType.Battlefield) { continue; } @@ -1275,7 +1271,9 @@ public boolean checkStateEffects(final boolean runEvents, final Set affect checkAgain |= stateBasedAction704_5d(c); // Dungeon Card won't affect other cards, so don't need to set checkAgain stateBasedAction_Dungeon(c); - stateBasedAction_Scheme(c); + if (zt == ZoneType.Command) { + stateBasedAction_Scheme(c); + } } } } @@ -1557,7 +1555,7 @@ private void stateBasedAction_Scheme(Card c) { return; } if (!game.getStack().hasSourceOnStack(c, null)) { - moveTo(ZoneType.SchemeDeck, c, null, AbilityKey.newMap()); + moveTo(ZoneType.SchemeDeck, c, -1, null, AbilityKey.newMap()); } } @@ -1676,7 +1674,6 @@ public void checkGameOverCondition() { FCollectionView allPlayers = game.getPlayers(); for (Player p : allPlayers) { if (p.checkLoseCondition()) { // this will set appropriate outcomes - // Run triggers if (losers == null) { losers = Lists.newArrayListWithCapacity(3); } @@ -1898,7 +1895,6 @@ public final CardCollection sacrifice(final Iterable list, final SpellAbil } } for (Map.Entry> e : lki.asMap().entrySet()) { - // Run triggers final Map runParams = AbilityKey.mapFromPlayer(e.getKey()); runParams.put(AbilityKey.Cards, new CardCollection(e.getValue())); runParams.put(AbilityKey.Cause, source); diff --git a/forge-game/src/main/java/forge/game/ability/effects/DigEffect.java b/forge-game/src/main/java/forge/game/ability/effects/DigEffect.java index 40380e1e6ec..996a3fc998a 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/DigEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/DigEffect.java @@ -367,7 +367,6 @@ else if (!sa.hasParam("NoLooking")) { } } - for (Card c : movedCards) { Map moveParams = AbilityKey.newMap(); AbilityKey.addCardZoneTableParams(moveParams, zoneMovements); diff --git a/forge-game/src/main/java/forge/game/phase/Untap.java b/forge-game/src/main/java/forge/game/phase/Untap.java index 868a39d0566..52ba46f0260 100644 --- a/forge-game/src/main/java/forge/game/phase/Untap.java +++ b/forge-game/src/main/java/forge/game/phase/Untap.java @@ -259,8 +259,10 @@ private static boolean optionalUntap(final Card c) { } public static void doPhasing(final Player turn) { + Game game = turn.getGame(); + // Needs to include phased out cards - final List list = CardLists.filter(turn.getGame().getCardsIncludePhasingIn(ZoneType.Battlefield), + final List list = CardLists.filter(game.getCardsIncludePhasingIn(ZoneType.Battlefield), c -> (c.isPhasedOut(turn) && c.isDirectlyPhasedOut()) || (c.hasKeyword(Keyword.PHASING) && c.getController().equals(turn)) ); @@ -299,11 +301,13 @@ public static void doPhasing(final Player turn) { if (!phasedOut.isEmpty()) { final Map runParams = AbilityKey.newMap(); runParams.put(AbilityKey.Cards, phasedOut); - turn.getGame().getTriggerHandler().runTrigger(TriggerType.PhaseOutAll, runParams, false); + game.getTriggerHandler().runTrigger(TriggerType.PhaseOutAll, runParams, false); } if (!toPhase.isEmpty()) { + // refresh statics for phased in permanents (e.g. so King of the Oathbreakers sees Changeling) + game.getAction().checkStaticAbilities(); // collect now before some zone change during Untap resets triggers - turn.getGame().getTriggerHandler().collectTriggerForWaiting(); + game.getTriggerHandler().collectTriggerForWaiting(); } } diff --git a/forge-game/src/main/java/forge/game/replacement/ReplacementHandler.java b/forge-game/src/main/java/forge/game/replacement/ReplacementHandler.java index 33522f6be37..cd28fa4316a 100644 --- a/forge-game/src/main/java/forge/game/replacement/ReplacementHandler.java +++ b/forge-game/src/main/java/forge/game/replacement/ReplacementHandler.java @@ -694,8 +694,7 @@ public void runReplaceDamage(final boolean isCombat, final CardDamageMap damageM // Determine if need to divide shield among affected entity and // determine if the prevent next N damage shield is large enough to replace all damage - Map mapParams = chosenRE.getMapParams(); - if ((mapParams.containsKey("PreventionEffect") && mapParams.get("PreventionEffect").equals("NextN")) + if ((chosenRE.hasParam("PreventionEffect") && chosenRE.getParam("PreventionEffect").equals("NextN")) || apiType == ApiType.ReplaceSplitDamage) { if (apiType == ApiType.ReplaceDamage) { shieldAmount = AbilityUtils.calculateAmount(effectSA.getHostCard(), effectSA.getParamOrDefault("Amount", "1"), effectSA); diff --git a/forge-game/src/main/java/forge/game/zone/MagicStack.java b/forge-game/src/main/java/forge/game/zone/MagicStack.java index e60c7535549..22b1acf4133 100644 --- a/forge-game/src/main/java/forge/game/zone/MagicStack.java +++ b/forge-game/src/main/java/forge/game/zone/MagicStack.java @@ -625,9 +625,11 @@ public final void resolveStack() { } game.fireEvent(new GameEventSpellResolved(sa, thisHasFizzled)); - finishResolving(sa, thisHasFizzled); game.getAction().checkStaticAbilities(); + + finishResolving(sa, thisHasFizzled); + game.copyLastState(); if (isEmpty() && !hasSimultaneousStackEntries()) { // assuming that if the stack is empty, no reason to hold on to old LKI data (everything is a new object) diff --git a/forge-gui/res/cardsfolder/a/arcums_weathervane.txt b/forge-gui/res/cardsfolder/a/arcums_weathervane.txt index f63ba1a0eb0..d56194d7845 100644 --- a/forge-gui/res/cardsfolder/a/arcums_weathervane.txt +++ b/forge-gui/res/cardsfolder/a/arcums_weathervane.txt @@ -2,6 +2,6 @@ Name:Arcum's Weathervane ManaCost:2 Types:Artifact A:AB$ Animate | Cost$ 2 T | ValidTgts$ Land.Snow | TgtPrompt$ Select target snow land | RemoveTypes$ Snow | Duration$ Permanent | SpellDescription$ Target snow land is no longer snow. -A:AB$ Animate | Cost$ 2 T | ValidTgts$ Land.nonSnow | TgtPrompt$ Select target nonsnow land | Types$ Snow | Duration$ Permanent | SpellDescription$ Target nonsnow basic land becomes snow. +A:AB$ Animate | Cost$ 2 T | ValidTgts$ Land.nonSnow+Basic | TgtPrompt$ Select target nonsnow basic land | Types$ Snow | Duration$ Permanent | SpellDescription$ Target nonsnow basic land becomes snow. AI:RemoveDeck:Random Oracle:{2}, {T}: Target snow land is no longer snow.\n{2}, {T}: Target nonsnow basic land becomes snow. diff --git a/forge-gui/res/cardsfolder/g/graveyard_shovel.txt b/forge-gui/res/cardsfolder/g/graveyard_shovel.txt index 520581fcebe..83d667bbadc 100644 --- a/forge-gui/res/cardsfolder/g/graveyard_shovel.txt +++ b/forge-gui/res/cardsfolder/g/graveyard_shovel.txt @@ -1,7 +1,7 @@ Name:Graveyard Shovel ManaCost:2 Types:Artifact -A:AB$ ChangeZone | Cost$ 2 T | ValidTgts$ Player | DefinedPlayer$ Targeted | TgtPrompt$ Select target player | Origin$ Graveyard | Destination$ Exile | ChangeType$ Card | ChangeNum$ 1 | Hidden$ True | Chooser$ Targeted | Mandatory$ True | SubAbility$ DBGainLife | ForgetOtherTargets$ True | RememberChanged$ True | IsCurse$ True | StackDescription$ Target player exiles a card from their graveyard. If it's a creature card, you gain 2 life. | SpellDescription$ Target player exiles a card from their graveyard. If it's a creature card, you gain 2 life. +A:AB$ ChangeZone | Cost$ 2 T | ValidTgts$ Player | DefinedPlayer$ Targeted | TgtPrompt$ Select target player | Origin$ Graveyard | Destination$ Exile | ChangeType$ Card | ChangeNum$ 1 | Hidden$ True | Chooser$ Targeted | Mandatory$ True | SubAbility$ DBGainLife | RememberChanged$ True | IsCurse$ True | StackDescription$ SpellDescription | SpellDescription$ Target player exiles a card from their graveyard. If it's a creature card, you gain 2 life. SVar:DBGainLife:DB$ GainLife | Defined$ You | LifeAmount$ 2 | ConditionDefined$ Remembered | ConditionPresent$ Creature | SubAbility$ DBCleanup SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True Oracle:{2}, {T}: Target player exiles a card from their graveyard. If it's a creature card, you gain 2 life. diff --git a/forge-gui/res/cardsfolder/j/jinnie_fay_jetmirs_second.txt b/forge-gui/res/cardsfolder/j/jinnie_fay_jetmirs_second.txt index 0dfec835e14..ed143ab314d 100644 --- a/forge-gui/res/cardsfolder/j/jinnie_fay_jetmirs_second.txt +++ b/forge-gui/res/cardsfolder/j/jinnie_fay_jetmirs_second.txt @@ -2,10 +2,10 @@ Name:Jinnie Fay, Jetmir's Second ManaCost:RG G GW Types:Legendary Creature Elf Druid PT:3/3 -R:Event$ CreateToken | ActiveZones$ Battlefield | ValidToken$ Card.YouCtrl | ReplaceWith$ GenericChoice | Optional$ True | Description$ If you would create one or more tokens, you may instead create that many 2/2 green Cat creature tokens with haste or that many 3/1 green Dog creature tokens with vigilance. +R:Event$ CreateToken | ActiveZones$ Battlefield | ValidPlayer$ You | ReplaceWith$ GenericChoice | Optional$ True | Description$ If you would create one or more tokens, you may instead create that many 2/2 green Cat creature tokens with haste or that many 3/1 green Dog creature tokens with vigilance. SVar:GenericChoice:DB$ GenericChoice | Choices$ Cat,Dog -SVar:Cat:DB$ ReplaceToken | Type$ ReplaceToken | ValidCard$ Card.YouCtrl | TokenScript$ g_2_2_cat_haste | SpellDescription$ Create that many 2/2 green Cat creature tokens with haste. -SVar:Dog:DB$ ReplaceToken | Type$ ReplaceToken | ValidCard$ Card.YouCtrl | TokenScript$ g_3_1_dog_vigilance | SpellDescription$ Create that many 3/1 green Dog creature tokens with vigilance. +SVar:Cat:DB$ ReplaceToken | Type$ ReplaceToken | TokenScript$ g_2_2_cat_haste | SpellDescription$ Create that many 2/2 green Cat creature tokens with haste. +SVar:Dog:DB$ ReplaceToken | Type$ ReplaceToken | TokenScript$ g_3_1_dog_vigilance | SpellDescription$ Create that many 3/1 green Dog creature tokens with vigilance. AI:RemoveDeck:Random DeckHas:Type$Cat|Dog DeckNeeds:Ability$Token diff --git a/forge-gui/res/cardsfolder/r/ratonhnhake_ton.txt b/forge-gui/res/cardsfolder/r/ratonhnhake_ton.txt index 20b78d63103..28657d09ed6 100644 --- a/forge-gui/res/cardsfolder/r/ratonhnhake_ton.txt +++ b/forge-gui/res/cardsfolder/r/ratonhnhake_ton.txt @@ -5,10 +5,10 @@ PT:3/3 S:Mode$ Continuous | Affected$ Card.Self | AddKeyword$ Hexproof | IsPresent$ Card.Self+dealtDamagetoAny | PresentCompare$ EQ0 | Description$ As long as CARDNAME hasn't dealt damage yet, it has hexproof and can't be blocked. S:Mode$ CantBlockBy | ValidAttacker$ Card.Self | Secondary$ True | IsPresent$ Card.Self+dealtDamagetoAny | PresentCompare$ EQ0 | Description$ As long as CARDNAME hasn't dealt damage yet, it has hexproof and can't be blocked. T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | CombatDamage$ True | Execute$ TrigToken | TriggerDescription$ Whenever CARDNAME deals combat damage to a player, create a 1/1 black Assassin creature token with menace. When you do, return target Equipment card from your graveyard to the battlefield, then attach it to that token. -SVar:TrigToken:DB$ Token | TokenScript$ b_1_1_assassin_menace | RememberTokens$ True | SubAbility$ DBTrigger -SVar:DBTrigger:DB$ ImmediateTrigger | Execute$ TrigChangeZone | ConditionDefined$ Remembered | ConditionPresent$ Card | TriggerDescription$ When you do, return target creature card from your graveyard to your hand. +SVar:TrigToken:DB$ Token | TokenScript$ b_1_1_assassin_menace | RememberOriginalTokens$ True | SubAbility$ DBTrigger +SVar:DBTrigger:DB$ ImmediateTrigger | Execute$ TrigChangeZone | TriggerAmount$ Remembered$Amount | RememberObjects$ Remembered | SubAbility$ DBCleanup | TriggerDescription$ When you do, return target creature card from your graveyard to your hand. SVar:TrigChangeZone:DB$ ChangeZone | Origin$ Graveyard | Destination$ Battlefield | ValidTgts$ Equipment.YouCtrl | SubAbility$ DBAttach -SVar:DBAttach:DB$ Attach | Object$ Targeted | Defined$ Remembered | SubAbility$ DBCleanup +SVar:DBAttach:DB$ Attach | Object$ Targeted | Defined$ DelayTriggerRememberedLKI SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True DeckHas:Ability$Token Oracle:As long as Ratonhnhaké:ton hasn't dealt damage yet, it has hexproof and can't be blocked.\nWhenever Ratonhnhaké:ton deals combat damage to a player, create a 1/1 black Assassin creature token with menace. When you do, return target Equipment card from your graveyard to the battlefield, then attach it to that token. diff --git a/forge-gui/res/cardsfolder/t/the_war_doctor.txt b/forge-gui/res/cardsfolder/t/the_war_doctor.txt index 60ce8c7d6b7..ae2c46fa837 100644 --- a/forge-gui/res/cardsfolder/t/the_war_doctor.txt +++ b/forge-gui/res/cardsfolder/t/the_war_doctor.txt @@ -6,7 +6,8 @@ T:Mode$ PhaseOutAll | ValidCards$ Permanent.phasedOutOther | TriggerZones$ Battl T:Mode$ ChangesZoneAll | ValidCards$ Card.Other+nonToken+!copiedSpell | Origin$ Any | Destination$ Exile | TriggerZones$ Battlefield | Execute$ TrigPutCounter | Secondary$ True | TriggerDescription$ Whenever one or more other permanents phase out and whenever one or more other cards are put into exile from anywhere, put a time counter on CARDNAME. SVar:TrigPutCounter:DB$ PutCounter | CounterType$ TIME T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigDamage | TriggerDescription$ Whenever CARDNAME attacks, it deals damage equal to the number of time counters on it to any target. If a creature dealt damage this way would die this turn, exile it instead. -SVar:TrigDamage:DB$ DealDamage | ValidTgts$ Any | DamageSource$ TriggeredAttackerLKICopy | NumDmg$ Count$CardCounters.TIME | ReplaceDyingDefined$ Targeted.Creature +SVar:TrigDamage:DB$ DealDamage | ValidTgts$ Any | DamageSource$ TriggeredAttackerLKICopy | NumDmg$ Count$CardCounters.TIME | RememberDamaged$ True | ReplaceDyingDefined$ Remembered.Creature | SubAbility$ DBCleanup +SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True DeckHas:Ability$Counters DeckHints:Keyword$Phasing Oracle:Whenever one or more other permanents phase out and whenever one or more other cards are put into exile from anywhere, put a time counter on The War Doctor.\nWhenever The War Doctor attacks, it deals damage equal to the number of time counters on it to any target. If a creature dealt damage this way would die this turn, exile it instead. diff --git a/forge-gui/res/cardsfolder/t/time_lord_regeneration.txt b/forge-gui/res/cardsfolder/t/time_lord_regeneration.txt index f42bb971f71..a4f5dbe0f5a 100644 --- a/forge-gui/res/cardsfolder/t/time_lord_regeneration.txt +++ b/forge-gui/res/cardsfolder/t/time_lord_regeneration.txt @@ -5,5 +5,4 @@ A:SP$ Animate | ValidTgts$ Time Lord.YouCtrl | TgtPrompt$ Select target Time Lor SVar:DiesTrig:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigReveal | TriggerDescription$ When this creature dies, reveal cards from the top of your library until you reveal a Time Lord creature card. Put that card onto the battlefield and the rest on the bottom of your library in a random order. SVar:TrigReveal:DB$ DigUntil | Defined$ You | Valid$ Creature.Time Lord | FoundDestination$ Battlefield | RevealedDestination$ Library | RevealedLibraryPosition$ -1 | RevealRandomOrder$ True | StackDescription$ None DeckNeeds:Type$Time Lord -DeckHints:Type$Changeling Oracle:Until end of turn, target Time Lord you control gains "When this creature dies, reveal cards from the top of your library until you reveal a Time Lord creature card. Put that card onto the battlefield and the rest on the bottom of your library in a random order." diff --git a/forge-gui/res/cardsfolder/w/wishing_well.txt b/forge-gui/res/cardsfolder/w/wishing_well.txt index ef24ab19977..2546c85a483 100644 --- a/forge-gui/res/cardsfolder/w/wishing_well.txt +++ b/forge-gui/res/cardsfolder/w/wishing_well.txt @@ -1,8 +1,8 @@ Name:Wishing Well ManaCost:3 U Types:Artifact -A:AB$ PutCounter | Cost$ T | Defined$ Self | SorcerySpeed$ True | CounterType$ COIN | CounterNum$ 1 | RememberPut$ True | SubAbility$ DBImmediateTrig | SpellDescription$ Put a coin counter on CARDNAME. When you do, you may cast target instant or sorcery card with mana value equal to the number of coin counters on CARDNAME from your graveyard without paying its mana cost. If that spell would be put into your graveyard, exile it instead. Activate only as a sorcery. -SVar:DBImmediateTrig:DB$ ImmediateTrigger | Execute$ TrigPlay | ConditionDefined$ Remembered | ConditionPresent$ Card | SubAbility$ DBCleanup | TriggerDescription$ When you do, you may cast target instant or sorcery card with mana value equal to the number of coin counters on CARDNAME from your graveyard without paying its mana cost. If that spell would be put into your graveyard, exile it instead. Activate only as a sorcery. +A:AB$ PutCounter | Cost$ T | Defined$ Self | SorcerySpeed$ True | CounterType$ COIN | CounterNum$ 1 | RememberAmount$ True | SubAbility$ DBImmediateTrig | SpellDescription$ Put a coin counter on CARDNAME. When you do, you may cast target instant or sorcery card with mana value equal to the number of coin counters on CARDNAME from your graveyard without paying its mana cost. If that spell would be put into your graveyard, exile it instead. Activate only as a sorcery. +SVar:DBImmediateTrig:DB$ ImmediateTrigger | Execute$ TrigPlay | TriggerAmount$ Count$RememberedNumber | SubAbility$ DBCleanup | TriggerDescription$ When you do, you may cast target instant or sorcery card with mana value equal to the number of coin counters on CARDNAME from your graveyard without paying its mana cost. If that spell would be put into your graveyard, exile it instead. Activate only as a sorcery. SVar:TrigPlay:DB$ Play | TgtZone$ Graveyard | ValidTgts$ Instant.YouCtrl+cmcEQX,Sorcery.YouCtrl+cmcEQX | ValidSA$ Spell | TgtPrompt$ Choose target instant or sorcery card with mana value equal to the number of coin counters on CARDNAME from your graveyard | WithoutManaCost$ True | Optional$ True | ReplaceGraveyard$ Exile | AILogic$ ReplaySpell SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True SVar:X:Count$CardCounters.COIN