mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-20 12:48:00 +00:00
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:
@@ -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) {
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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)) {
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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() {
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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")) {
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user