Fix Stonebinder's Familiar not triggering from Nivmagus Elemental (#4424)

* Fix Stonebinder's Familiar not triggering from Nivmagus Elemental

* Fix so it only triggers for cards

* Surveil triggers on empty library

* Fix missing trigger

* Fix trigger

* fix script

* Fix corner case freeze by trigger for loser (Kharn the Betrayer)

* Fix loser making trigger decision e.g. Shakedown Heavy

* Obeka fix when resolving after AP lost

* fix script

---------

Co-authored-by: tool4EvEr <tool4EvEr@192.168.0.60>
This commit is contained in:
tool4ever
2023-12-26 04:55:53 +01:00
committed by GitHub
parent e6a9ea20c7
commit a24af8d50e
17 changed files with 71 additions and 60 deletions

View File

@@ -19,6 +19,7 @@ package forge.game;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.collect.*; import com.google.common.collect.*;
import forge.GameCommand; import forge.GameCommand;
import forge.StaticData; import forge.StaticData;
import forge.card.CardStateName; import forge.card.CardStateName;
@@ -54,6 +55,7 @@ import forge.item.PaperCard;
import forge.util.*; import forge.util.*;
import forge.util.collect.FCollection; import forge.util.collect.FCollection;
import forge.util.collect.FCollectionView; import forge.util.collect.FCollectionView;
import org.apache.commons.lang3.tuple.ImmutablePair; import org.apache.commons.lang3.tuple.ImmutablePair;
import java.util.*; import java.util.*;
@@ -902,14 +904,10 @@ public class GameAction {
CardZoneTable table = new CardZoneTable(getLastState(AbilityKey.LastStateBattlefield, cause, params), getLastState(AbilityKey.LastStateGraveyard, cause, params)); CardZoneTable table = new CardZoneTable(getLastState(AbilityKey.LastStateBattlefield, cause, params), getLastState(AbilityKey.LastStateGraveyard, cause, params));
CardCollection result = new CardCollection(); CardCollection result = new CardCollection();
for (Card card : cards) { for (Card card : cards) {
if (cause != null) { table.put(card.getZone().getZoneType(), ZoneType.Exile, card);
table.put(card.getZone().getZoneType(), ZoneType.Exile, card);
}
result.add(exile(card, cause, params)); result.add(exile(card, cause, params));
} }
if (cause != null) { table.triggerChangesZoneAll(game, cause);
table.triggerChangesZoneAll(game, cause);
}
return result; return result;
} }
public final Card exile(final Card c, SpellAbility cause, Map<AbilityKey, Object> params) { public final Card exile(final Card c, SpellAbility cause, Map<AbilityKey, Object> params) {

View File

@@ -1537,6 +1537,10 @@ public class AbilityUtils {
boolean alreadyPaid = false; boolean alreadyPaid = false;
for (Player payer : allPayers) { for (Player payer : allPayers) {
if (!payer.isInGame()) {
// CR 800.4f
continue;
}
if (unlessCost.equals("LifeTotalHalfUp")) { if (unlessCost.equals("LifeTotalHalfUp")) {
String halfup = Integer.toString(Math.max(0,(int) Math.ceil(payer.getLife() / 2.0))); String halfup = Integer.toString(Math.max(0,(int) Math.ceil(payer.getLife() / 2.0)));
cost = new Cost("PayLife<" + halfup + ">", true); cost = new Cost("PayLife<" + halfup + ">", true);

View File

@@ -876,7 +876,7 @@ public abstract class SpellAbilityEffect {
} }
} }
public Player getNewChooser(final SpellAbility sa, final Player activator, final Player loser) { public static Player getNewChooser(final SpellAbility sa, final Player activator, final Player loser) {
// CR 800.4g // CR 800.4g
final PlayerCollection options; final PlayerCollection options;
if (loser.isOpponentOf(activator)) { if (loser.isOpponentOf(activator)) {

View File

@@ -7,10 +7,10 @@ import forge.game.GameLogEntryType;
import forge.game.ability.AbilityKey; import forge.game.ability.AbilityKey;
import forge.game.ability.SpellAbilityEffect; import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView; import forge.game.card.CardCollectionView;
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.util.CardTranslation; import forge.util.CardTranslation;
import forge.util.Localizer; import forge.util.Localizer;
@@ -57,7 +57,7 @@ public class EncodeEffect extends SpellAbilityEffect {
moveParams.put(AbilityKey.LastStateGraveyard, sa.getLastStateGraveyard()); moveParams.put(AbilityKey.LastStateGraveyard, sa.getLastStateGraveyard());
// move host card to exile // move host card to exile
Card movedCard = game.getAction().moveTo(ZoneType.Exile, host, sa, moveParams); Card movedCard = game.getAction().exile(new CardCollection(host), sa, moveParams).get(0);
// choose a creature // choose a creature
Card choice = player.getController().chooseSingleEntityForEffect(choices, sa, Localizer.getInstance().getMessage("lblChooseACreatureYouControlToEncode") + " ", false, null); Card choice = player.getController().chooseSingleEntityForEffect(choices, sa, Localizer.getInstance().getMessage("lblChooseACreatureYouControlToEncode") + " ", false, null);

View File

@@ -17,7 +17,11 @@ public class EndTurnEffect extends SpellAbilityEffect {
@Override @Override
public void resolve(SpellAbility sa) { public void resolve(SpellAbility sa) {
final List<Player> enders = getDefinedPlayersOrTargeted(sa, "Defined"); final List<Player> enders = getDefinedPlayersOrTargeted(sa, "Defined");
final Player ender = enders.isEmpty() ? sa.getActivatingPlayer() : enders.get(0); Player ender = enders.isEmpty() ? sa.getActivatingPlayer() : enders.get(0);
if (!ender.isInGame()) {
ender = getNewChooser(sa, sa.getActivatingPlayer(), ender);
}
if (sa.hasParam("Optional") && !ender.getController().confirmAction(sa, null, Localizer.getInstance().getMessage("lblDoYouWantEndTurn"), null)) { if (sa.hasParam("Optional") && !ender.getController().confirmAction(sa, null, Localizer.getInstance().getMessage("lblDoYouWantEndTurn"), null)) {
return; return;
} }

View File

@@ -9,7 +9,6 @@ import forge.game.Game;
import forge.game.ability.AbilityKey; import forge.game.ability.AbilityKey;
import forge.game.ability.SpellAbilityEffect; import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.card.CardCollectionView;
import forge.game.card.CardZoneTable; import forge.game.card.CardZoneTable;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
@@ -30,12 +29,9 @@ public class PermanentEffect extends SpellAbilityEffect {
CardZoneTable table = new CardZoneTable(); CardZoneTable table = new CardZoneTable();
ZoneType previousZone = host.getZone().getZoneType(); ZoneType previousZone = host.getZone().getZoneType();
CardCollectionView lastStateBattlefield = game.copyLastStateBattlefield();
CardCollectionView lastStateGraveyard = game.copyLastStateGraveyard();
Map<AbilityKey, Object> moveParams = AbilityKey.newMap(); Map<AbilityKey, Object> moveParams = AbilityKey.newMap();
moveParams.put(AbilityKey.LastStateBattlefield, lastStateBattlefield); moveParams.put(AbilityKey.LastStateBattlefield, game.copyLastStateBattlefield());
moveParams.put(AbilityKey.LastStateGraveyard, lastStateGraveyard); moveParams.put(AbilityKey.LastStateGraveyard, game.copyLastStateGraveyard());
final Card c = game.getAction().moveToPlay(host, host.getController(), sa, moveParams); final Card c = game.getAction().moveToPlay(host, host.getController(), sa, moveParams);
sa.setHostCard(c); sa.setHostCard(c);

View File

@@ -31,6 +31,7 @@ import forge.game.cost.CostPart;
import forge.game.event.GameEventCardForetold; import forge.game.event.GameEventCardForetold;
import forge.game.trigger.TriggerType; import forge.game.trigger.TriggerType;
import forge.util.Localizer; import forge.util.Localizer;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
@@ -78,6 +79,7 @@ import forge.game.trigger.TriggerHandler;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import forge.util.Lang; import forge.util.Lang;
import forge.util.TextUtil; import forge.util.TextUtil;
import io.sentry.Breadcrumb; import io.sentry.Breadcrumb;
import io.sentry.Sentry; import io.sentry.Sentry;
@@ -109,12 +111,9 @@ public class CardFactoryUtil {
} }
final Game game = hostCard.getGame(); final Game game = hostCard.getGame();
CardCollectionView lastStateBattlefield = game.copyLastStateBattlefield();
CardCollectionView lastStateGraveyard = game.copyLastStateGraveyard();
Map<AbilityKey, Object> moveParams = AbilityKey.newMap(); Map<AbilityKey, Object> moveParams = AbilityKey.newMap();
moveParams.put(AbilityKey.LastStateBattlefield, lastStateBattlefield); moveParams.put(AbilityKey.LastStateBattlefield, game.copyLastStateBattlefield());
moveParams.put(AbilityKey.LastStateGraveyard, lastStateGraveyard); moveParams.put(AbilityKey.LastStateGraveyard, game.copyLastStateGraveyard());
hostCard.getGame().getAction().moveToPlay(hostCard, this, moveParams); hostCard.getGame().getAction().moveToPlay(hostCard, this, moveParams);
} }

View File

@@ -19,6 +19,7 @@ package forge.game.cost;
import forge.game.Game; import forge.game.Game;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView; import forge.game.card.CardCollectionView;
import forge.game.card.CardLists; import forge.game.card.CardLists;
import forge.game.card.CardUtil; import forge.game.card.CardUtil;
@@ -110,7 +111,7 @@ public class CostExileFromStack extends CostPart {
if (si != null) { if (si != null) {
game.getStack().remove(si); game.getStack().remove(si);
} }
game.getAction().exile(sa.getHostCard(), null, null); game.getAction().exile(new CardCollection(sa.getHostCard()), null, null);
} }
return true; return true;
} }

View File

@@ -1122,38 +1122,36 @@ public class Player extends GameEntity implements Comparable<Player> {
final CardCollection topN = getTopXCardsFromLibrary(num); final CardCollection topN = getTopXCardsFromLibrary(num);
if (topN.isEmpty()) { if (!topN.isEmpty()) {
return; final ImmutablePair<CardCollection, CardCollection> lists = getController().arrangeForSurveil(topN);
} final CardCollection toTop = lists.getLeft();
final CardCollection toGrave = lists.getRight();
final ImmutablePair<CardCollection, CardCollection> lists = getController().arrangeForSurveil(topN); int numToGrave = 0;
final CardCollection toTop = lists.getLeft(); int numToTop = 0;
final CardCollection toGrave = lists.getRight();
int numToGrave = 0; if (toGrave != null) {
int numToTop = 0; for (Card c : toGrave) {
ZoneType oZone = c.getZone().getZoneType();
if (toGrave != null) { Card moved = getGame().getAction().moveToGraveyard(c, cause, params);
for (Card c : toGrave) { table.put(oZone, moved.getZone().getZoneType(), moved);
ZoneType oZone = c.getZone().getZoneType(); numToGrave++;
Card moved = getGame().getAction().moveToGraveyard(c, cause, params); }
table.put(oZone, moved.getZone().getZoneType(), moved);
numToGrave++;
} }
}
if (toTop != null) { if (toTop != null) {
Collections.reverse(toTop); // the last card in list will become topmost in library, have to revert thus. Collections.reverse(toTop); // the last card in list will become topmost in library, have to revert thus.
for (Card c : toTop) { for (Card c : toTop) {
getGame().getAction().moveToLibrary(c, cause, params); getGame().getAction().moveToLibrary(c, cause, params);
numToTop++; numToTop++;
}
if (cause.hasParam("RememberKept")) {
cause.getHostCard().addRemembered(toTop);
}
} }
if (cause.hasParam("RememberKept")) {
cause.getHostCard().addRemembered(toTop);
}
}
getGame().fireEvent(new GameEventSurveil(this, numToTop, numToGrave)); getGame().fireEvent(new GameEventSurveil(this, numToTop, numToGrave));
}
surveilThisTurn++; surveilThisTurn++;
final Map<AbilityKey, Object> runParams = AbilityKey.mapFromPlayer(this); final Map<AbilityKey, Object> runParams = AbilityKey.mapFromPlayer(this);
@@ -2276,7 +2274,7 @@ public class Player extends GameEntity implements Comparable<Player> {
public final void addInvestigatedThisTurn() { public final void addInvestigatedThisTurn() {
investigatedThisTurn++; investigatedThisTurn++;
final Map<AbilityKey, Object> runParams = AbilityKey.mapFromPlayer(this); final Map<AbilityKey, Object> runParams = AbilityKey.mapFromPlayer(this);
runParams.put(AbilityKey.Num, investigatedThisTurn); runParams.put(AbilityKey.FirstTime, investigatedThisTurn == 1);
game.getTriggerHandler().runTrigger(TriggerType.Investigated, runParams, false); game.getTriggerHandler().runTrigger(TriggerType.Investigated, runParams, false);
} }
public final void resetInvestigatedThisTurn() { public final void resetInvestigatedThisTurn() {

View File

@@ -531,6 +531,10 @@ public class TriggerHandler {
host.addRemembered(triggeredCard); host.addRemembered(triggeredCard);
} }
if (!sa.getActivatingPlayer().isInGame()) {
return;
}
sa.setStackDescription(sa.toString()); sa.setStackDescription(sa.toString());
Player decider = null; Player decider = null;

View File

@@ -71,11 +71,12 @@ public class TriggerInvestigated extends Trigger {
return false; return false;
} }
if (hasParam("OnlyFirst")) { if (hasParam("FirstTime")) {
if ((int) runParams.get(AbilityKey.Num) != 1) { if (!(boolean) runParams.get(AbilityKey.FirstTime)) {
return false; return false;
} }
} }
return true; return true;
} }

View File

@@ -14,6 +14,7 @@ import forge.game.Game;
import forge.game.GameEntityCounterTable; import forge.game.GameEntityCounterTable;
import forge.game.ability.AbilityKey; import forge.game.ability.AbilityKey;
import forge.game.ability.ApiType; import forge.game.ability.ApiType;
import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.card.CardCollection; import forge.game.card.CardCollection;
import forge.game.card.CardDamageMap; import forge.game.card.CardDamageMap;
@@ -74,7 +75,7 @@ public class WrappedAbility extends Ability {
); );
private final SpellAbility sa; private final SpellAbility sa;
private final Player decider; private Player decider;
boolean mandatory = false; boolean mandatory = false;
@@ -465,7 +466,7 @@ public class WrappedAbility extends Ability {
// ////////////////////////////////////// // //////////////////////////////////////
@Override @Override
public void resolve() { public void resolve() {
final Game game = sa.getActivatingPlayer().getGame(); final Game game = getActivatingPlayer().getGame();
final Trigger regtrig = getTrigger(); final Trigger regtrig = getTrigger();
if (!(TriggerType.Always.equals(regtrig.getMode())) && !regtrig.hasParam("NoResolvingCheck")) { if (!(TriggerType.Always.equals(regtrig.getMode())) && !regtrig.hasParam("NoResolvingCheck")) {
@@ -490,8 +491,13 @@ public class WrappedAbility extends Ability {
} }
} }
if (decider != null && !decider.getController().confirmTrigger(this)) { if (decider != null) {
return; if (!decider.isInGame()) {
decider = SpellAbilityEffect.getNewChooser(sa, getActivatingPlayer(), decider);
}
if (!decider.getController().confirmTrigger(this)) {
return;
}
} }
if (!regtrig.hasParam("NoTimestampCheck")) { if (!regtrig.hasParam("NoTimestampCheck")) {

View File

@@ -8,7 +8,7 @@ T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.S
SVar:DBBoon:DB$ Effect | Boon$ True | Duration$ Permanent | Triggers$ SpellCast SVar:DBBoon:DB$ Effect | Boon$ True | Duration$ Permanent | Triggers$ SpellCast
SVar:SpellCast:Mode$ SpellCast | ValidCard$ Creature | ValidActivatingPlayer$ You | TriggerZones$ Command | Execute$ ReplEffAddCounter | TriggerDescription$ When you cast your next creature spell, that creature enters the battlefield with an additional +1/+1 counter, flying counter, and lifelink counter on it. SVar:SpellCast:Mode$ SpellCast | ValidCard$ Creature | ValidActivatingPlayer$ You | TriggerZones$ Command | Execute$ ReplEffAddCounter | TriggerDescription$ When you cast your next creature spell, that creature enters the battlefield with an additional +1/+1 counter, flying counter, and lifelink counter on it.
SVar:ReplEffAddCounter:DB$ Effect | ReplacementEffects$ ETBAddCounter | RememberObjects$ TriggeredCard SVar:ReplEffAddCounter:DB$ Effect | ReplacementEffects$ ETBAddCounter | RememberObjects$ TriggeredCard
SVar:ETBAddCounter:Event$ Moved | Origin$ Stack | Destination$ Battlefield | ValidCard$ Card.IsRemembered | ReplaceWith$ ETBAddExtraCounter SVar:ETBAddCounter:Event$ Moved | Origin$ Stack | Destination$ Battlefield | ValidCard$ Card.IsRemembered | ReplacementResult$ Updated | ReplaceWith$ ETBAddExtraCounter
SVar:ETBAddExtraCounter:DB$ PutCounter | ETB$ True | Defined$ ReplacedCard | CounterType$ P1P1,Flying,Lifelink | CounterNum$ 1 | SubAbility$ DBRemoveSelf SVar:ETBAddExtraCounter:DB$ PutCounter | ETB$ True | Defined$ ReplacedCard | CounterType$ P1P1,Flying,Lifelink | CounterNum$ 1 | SubAbility$ DBRemoveSelf
SVar:DBRemoveSelf:DB$ ChangeZone | Defined$ Self | Origin$ Command | Destination$ Exile SVar:DBRemoveSelf:DB$ ChangeZone | Defined$ Self | Origin$ Command | Destination$ Exile
DeckHas:Ability$LifeGain|Counters & Keyword$Lifelink|Flying DeckHas:Ability$LifeGain|Counters & Keyword$Lifelink|Flying

View File

@@ -3,7 +3,7 @@ ManaCost:4 R
Types:Sorcery Types:Sorcery
A:SP$ RepeatEach | RepeatPlayers$ Player | RepeatSubAbility$ DBDraw | SpellDescription$ Each player may discard their hand and draw cards equal to the greatest mana value of a commander they own on the battlefield or in the command zone. A:SP$ RepeatEach | RepeatPlayers$ Player | RepeatSubAbility$ DBDraw | SpellDescription$ Each player may discard their hand and draw cards equal to the greatest mana value of a commander they own on the battlefield or in the command zone.
SVar:DBDraw:DB$ Draw | UnlessCost$ Discard<1/Hand> | UnlessPayer$ Remembered | UnlessSwitched$ True | Defined$ Remembered | NumCards$ X SVar:DBDraw:DB$ Draw | UnlessCost$ Discard<1/Hand> | UnlessPayer$ Remembered | UnlessSwitched$ True | Defined$ Remembered | NumCards$ X
SVar:X:Count$ValidBattlefield,Command Card.IsCommander+YouOwn$GreatestCMC SVar:X:Count$ValidBattlefield,Command Card.IsCommander+RememberedPlayerOwn$GreatestCMC
DeckHas:Ability$Discard DeckHas:Ability$Discard
AI:RemoveDeck:NonCommander AI:RemoveDeck:NonCommander
Oracle:Each player may discard their hand and draw cards equal to the greatest mana value of a commander they own on the battlefield or in the command zone. Oracle:Each player may discard their hand and draw cards equal to the greatest mana value of a commander they own on the battlefield or in the command zone.

View File

@@ -1,7 +1,7 @@
Name:Siren's Call Name:Siren's Call
ManaCost:U ManaCost:U
Types:Instant Types:Instant
A:SP$ Effect | StaticAbilities$ MustAttack | ActivationPhases$ Upkeep->BeginCombat | OpponentTurn$ True | SpellDescription$ Cast this spell only during an opponent's turn, before attackers are declared. Creatures the active player controls attack this turn if able. At the beginning of the next end step, destroy all non-Wall creatures that player controls that didn't attack this turn. Ignore this effect for each creature the player didn't control continuously since the beginning of the turn. | SubAbility$ DestroyPacifist A:SP$ Effect | StaticAbilities$ MustAttack | ActivationPhases$ Upkeep->BeginCombat | ActivationFirstCombat$ True | OpponentTurn$ True | SpellDescription$ Cast this spell only during an opponent's turn, before attackers are declared. Creatures the active player controls attack this turn if able. At the beginning of the next end step, destroy all non-Wall creatures that player controls that didn't attack this turn. Ignore this effect for each creature the player didn't control continuously since the beginning of the turn. | SubAbility$ DestroyPacifist
SVar:MustAttack:Mode$ MustAttack | EffectZone$ Command | AffectedZone$ Battlefield | ValidCreature$ Creature.ActivePlayerCtrl | Description$ Creatures the active player controls attack this turn if able. SVar:MustAttack:Mode$ MustAttack | EffectZone$ Command | AffectedZone$ Battlefield | ValidCreature$ Creature.ActivePlayerCtrl | Description$ Creatures the active player controls attack this turn if able.
SVar:DestroyPacifist:DB$ DelayedTrigger | Mode$ Phase | Phase$ End of Turn | Execute$ TrigDestroy | TriggerDescription$ At the beginning of the next end step, destroy all non-Wall creatures that player controls that didn't attack this turn. SVar:DestroyPacifist:DB$ DelayedTrigger | Mode$ Phase | Phase$ End of Turn | Execute$ TrigDestroy | TriggerDescription$ At the beginning of the next end step, destroy all non-Wall creatures that player controls that didn't attack this turn.
SVar:TrigDestroy:DB$ DestroyAll | ValidCards$ Creature.ActivePlayerCtrl+notAttackedThisTurn+nonWall+notFirstTurnControlled | SubAbility$ DBCleanup SVar:TrigDestroy:DB$ DestroyAll | ValidCards$ Creature.ActivePlayerCtrl+notAttackedThisTurn+nonWall+notFirstTurnControlled | SubAbility$ DBCleanup

View File

@@ -2,7 +2,7 @@ Name:Stonebinder's Familiar
ManaCost:W ManaCost:W
Types:Creature Spirit Dog Types:Creature Spirit Dog
PT:1/1 PT:1/1
T:Mode$ ChangesZoneAll | Destination$ Exile | TriggerZones$ Battlefield | Execute$ TrigPutcounter | PlayerTurn$ True | ActivationLimit$ 1 | TriggerDescription$ Whenever one or more cards are put into exile during your turn, put a +1/+1 counter on CARDNAME. This ability triggers only once each turn. T:Mode$ ChangesZoneAll | ValidCard$ Card.nonToken+nonCopiedSpell | Destination$ Exile | TriggerZones$ Battlefield | Execute$ TrigPutcounter | PlayerTurn$ True | ActivationLimit$ 1 | TriggerDescription$ Whenever one or more cards are put into exile during your turn, put a +1/+1 counter on CARDNAME. This ability triggers only once each turn.
SVar:TrigPutcounter:DB$ PutCounter | CounterType$ P1P1 | Defined$ Self | CounterNum$ 1 SVar:TrigPutcounter:DB$ PutCounter | CounterType$ P1P1 | Defined$ Self | CounterNum$ 1
DeckHas:Ability$Counters DeckHas:Ability$Counters
Oracle:Whenever one or more cards are put into exile during your turn, put a +1/+1 counter on Stonebinder's Familiar. This ability triggers only once each turn. Oracle:Whenever one or more cards are put into exile during your turn, put a +1/+1 counter on Stonebinder's Familiar. This ability triggers only once each turn.

View File

@@ -3,7 +3,7 @@ ManaCost:2 R W
Types:Legendary Creature Time Lord Doctor Types:Legendary Creature Time Lord Doctor
PT:3/5 PT:3/5
T:Mode$ PhaseOutAll | ValidCards$ Permanent.phasedOutOther | TriggerZones$ Battlefield | Execute$ TrigPutCounter | 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. T:Mode$ PhaseOutAll | ValidCards$ Permanent.phasedOutOther | TriggerZones$ Battlefield | Execute$ TrigPutCounter | 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.
T:Mode$ ChangesZoneAll | ValidCards$ Card.Other | 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. T:Mode$ ChangesZoneAll | ValidCards$ Card.Other+nonToken+nonCopiedSpell | 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 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. 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 | ReplaceDyingDefined$ Targeted.Creature