Merge remote-tracking branch 'upstream/master'

This commit is contained in:
CCTV-1
2021-02-03 08:26:22 +08:00
130 changed files with 1649 additions and 195 deletions

View File

@@ -81,7 +81,12 @@ public class ControlExchangeAi extends SpellAbilityAi {
final TargetRestrictions tgt = sa.getTargetRestrictions();
CardCollection list = CardLists.getValidCards(aiPlayer.getGame().getCardsIn(ZoneType.Battlefield),
// for TrigTwoTargets logic, only get the opponents' cards for the first target
CardCollectionView unfilteredList = "TrigTwoTargets".equals(sa.getParam("AILogic")) ?
aiPlayer.getOpponents().getCardsIn(ZoneType.Battlefield) :
aiPlayer.getGame().getCardsIn(ZoneType.Battlefield);
CardCollection list = CardLists.getValidCards(unfilteredList,
tgt.getValidTgts(), aiPlayer, sa.getHostCard(), sa);
// only select the cards that can be targeted
@@ -106,7 +111,51 @@ public class ControlExchangeAi extends SpellAbilityAi {
// add best Target
sa.getTargets().add(best);
// second target needed (the AI's own worst)
if ("TrigTwoTargets".equals(sa.getParam("AILogic"))) {
return doTrigTwoTargetsLogic(aiPlayer, sa, best);
}
return true;
}
private boolean doTrigTwoTargetsLogic(Player ai, SpellAbility sa, Card bestFirstTgt) {
final TargetRestrictions tgt = sa.getTargetRestrictions();
final int creatureThreshold = 100; // TODO: make this configurable from the AI profile
final int nonCreatureThreshold = 2;
CardCollection list = CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield),
tgt.getValidTgts(), ai, sa.getHostCard(), sa);
// only select the cards that can be targeted
list = CardLists.getTargetableCards(list, sa);
if (list.isEmpty()) {
return false;
}
Card aiWorst = ComputerUtilCard.getWorstAI(list);
if (aiWorst == null) {
return false;
}
if (aiWorst != null && aiWorst != bestFirstTgt) {
if (bestFirstTgt.isCreature() && aiWorst.isCreature()) {
if ((ComputerUtilCard.evaluateCreature(bestFirstTgt) > ComputerUtilCard.evaluateCreature(aiWorst) + creatureThreshold) || sa.isMandatory()) {
sa.getTargets().add(aiWorst);
return true;
}
} else {
// TODO: compare non-creatures by CMC - can be improved, at least shouldn't give control of things like the Power Nine
if ((bestFirstTgt.getCMC() > aiWorst.getCMC() + nonCreatureThreshold) || sa.isMandatory()) {
sa.getTargets().add(aiWorst);
return true;
}
}
}
sa.clearTargets();
return false;
}
}

View File

@@ -153,6 +153,10 @@ public class ForgeScript {
return sa.hasParam("Equip");
} else if (property.equals("Boast")) {
return sa.isBoast();
} else if (property.equals("Foretelling")) {
return sa.isForetelling();
} else if (property.equals("Foretold")) {
return sa.isForetold();
} else if (property.equals("MayPlaySource")) {
StaticAbility m = sa.getMayPlay();
if (m == null) {

View File

@@ -109,6 +109,7 @@ public class Game {
private final Match match;
private GameStage age = GameStage.BeforeMulligan;
private GameOutcome outcome;
private Game maingame = null;
private final GameView view;
private final Tracker tracker = new Tracker();
@@ -219,7 +220,11 @@ public class Game {
changeZoneLKIInfo.clear();
}
public Game(Iterable<RegisteredPlayer> players0, GameRules rules0, Match match0) { /* no more zones to map here */
public Game(Iterable<RegisteredPlayer> players0, GameRules rules0, Match match0) {
this(players0, rules0, match0, -1);
}
public Game(Iterable<RegisteredPlayer> players0, GameRules rules0, Match match0, int startingLife) { /* no more zones to map here */
rules = rules0;
match = match0;
this.id = nextId();
@@ -243,7 +248,11 @@ public class Game {
allPlayers.add(pl);
ingamePlayers.add(pl);
pl.setStartingLife(psc.getStartingLife());
if (startingLife != -1) {
pl.setStartingLife(startingLife);
} else {
pl.setStartingLife(psc.getStartingLife());
}
pl.setMaxHandSize(psc.getStartingHand());
pl.setStartingHandSize(psc.getStartingHand());
@@ -430,6 +439,14 @@ public class Game {
return outcome;
}
public final Game getMaingame() {
return maingame;
}
public void setMaingame(final Game maingame0) {
maingame = maingame0;
}
public ReplacementHandler getReplacementHandler() {
return replacementHandler;
}
@@ -452,12 +469,16 @@ public class Game {
result.setTurnsPlayed(getPhaseHandler().getTurn());
outcome = result;
match.addGamePlayed(this);
if (maingame == null) {
match.addGamePlayed(this);
}
view.updateGameOver(this);
// The log shall listen to events and generate text internally
fireEvent(new GameEventGameOutcome(result, match.getOutcomes()));
if (maingame == null) {
fireEvent(new GameEventGameOutcome(result, match.getOutcomes()));
}
}
public Zone getZoneOf(final Card card) {
@@ -492,6 +513,14 @@ public class Game {
return cards;
}
public CardCollectionView getCardsInOwnedBy(final Iterable<ZoneType> zones, Player p) {
CardCollection cards = new CardCollection();
for (final ZoneType z : zones) {
cards.addAll(getCardsIncludePhasingIn(z));
}
return CardLists.filter(cards, CardPredicates.isOwner(p));
}
public boolean isCardExiled(final Card c) {
return getCardsIn(ZoneType.Exile).contains(c);
}

View File

@@ -73,6 +73,8 @@ public class GameAction {
// Reset Activations per Turn
for (final Card card : game.getCardsInGame()) {
card.resetActivationsPerTurn();
// need to reset this in exile
card.resetForetoldThisTurn();
}
}
@@ -168,7 +170,7 @@ public class GameAction {
// Don't copy Tokens, copy only cards leaving the battlefield
// and returning to hand (to recreate their spell ability information)
if (suppress || toBattlefield || zoneTo.is(ZoneType.Stack)) {
if (suppress || toBattlefield) {
copied = c;
if (lastKnownInfo == null) {
@@ -193,10 +195,6 @@ public class GameAction {
lastKnownInfo = CardUtil.getLKICopy(c);
}
if (wasFacedown) {
c.forceTurnFaceUp();
}
if (!c.isToken()) {
copied = CardFactory.copyCard(c, false);
@@ -518,6 +516,18 @@ public class GameAction {
c = changeZone(zoneFrom, zoneTo, c, position, cause, params);
// Move card in maingame if take card from subgame
// 720.4a
if (zoneFrom != null && zoneFrom.is(ZoneType.Sideboard) && game.getMaingame() != null) {
Card maingameCard = c.getOwner().getMappingMaingameCard(c);
if (maingameCard != null) {
if (maingameCard.getZone().is(ZoneType.Stack)) {
game.getMaingame().getStack().remove(maingameCard);
}
game.getMaingame().getAction().moveTo(ZoneType.Subgame, maingameCard, null);
}
}
if (zoneFrom == null) {
c.setCastFrom(null);
c.setCastSA(null);

View File

@@ -6,12 +6,12 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
@@ -54,7 +54,7 @@ import java.util.List;
* <p>
* GameActionUtil class.
* </p>
*
*
* @author Forge
* @version $Id$
*/
@@ -68,7 +68,7 @@ public final class GameActionUtil {
* <p>
* Find the alternative costs to a {@link SpellAbility}.
* </p>
*
*
* @param sa
* a {@link SpellAbility}.
* @param activator
@@ -204,8 +204,51 @@ public final class GameActionUtil {
flashback.setPayCosts(new Cost(k[1], false));
}
alternatives.add(flashback);
} else if (keyword.startsWith("Foretell")) {
// Fortell cast only from Exile
if (!source.isInZone(ZoneType.Exile) || !source.isForetold() || source.isForetoldThisTurn()) {
continue;
}
// skip this part for fortell by external source
if (keyword.equals("Foretell")) {
continue;
}
final SpellAbility foretold = sa.copy(activator);
foretold.setAlternativeCost(AlternativeCost.Foretold);
foretold.getRestrictions().setZone(ZoneType.Exile);
// Stack Description only for Permanent or it might crash
if (source.isPermanent()) {
final StringBuilder sbStack = new StringBuilder();
sbStack.append(sa.getStackDescription()).append(" (Foretold)");
foretold.setStackDescription(sbStack.toString());
}
final String[] k = keyword.split(":");
foretold.setPayCosts(new Cost(k[1], false));
alternatives.add(foretold);
}
}
// foretell by external source
if (source.isForetoldByEffect() && source.isInZone(ZoneType.Exile) && source.isForetold() && !source.isForetoldThisTurn() && !source.getManaCost().isNoCost()) {
// Its foretell cost is equal to its mana cost reduced by {2}.
final SpellAbility foretold = sa.copy(activator);
foretold.putParam("ReduceCost", "2");
foretold.setAlternativeCost(AlternativeCost.Foretold);
foretold.getRestrictions().setZone(ZoneType.Exile);
// Stack Description only for Permanent or it might crash
if (source.isPermanent()) {
final StringBuilder sbStack = new StringBuilder();
sbStack.append(sa.getStackDescription()).append(" (Foretold)");
foretold.setStackDescription(sbStack.toString());
}
alternatives.add(foretold);
}
}
// reset static abilities
@@ -295,12 +338,12 @@ public final class GameActionUtil {
final Cost cost = new Cost(k[1], false);
costs.add(new OptionalCostValue(OptionalCost.Flash, cost));
}
// Surge while having OptionalCost is none of them
}
return costs;
}
public static SpellAbility addOptionalCosts(final SpellAbility sa, List<OptionalCostValue> list) {
if (sa == null || list.isEmpty()) {
return sa;
@@ -309,7 +352,7 @@ public final class GameActionUtil {
for (OptionalCostValue v : list) {
result.getPayCosts().add(v.getCost());
result.addOptionalCost(v.getType());
// add some extra logic, try to move it to other parts
switch (v.getType()) {
case Retrace:
@@ -325,7 +368,7 @@ public final class GameActionUtil {
}
return result;
}
public static List<SpellAbility> getAdditionalCostSpell(final SpellAbility sa) {
final List<SpellAbility> abilities = Lists.newArrayList(sa);
if (!sa.isSpell()) {
@@ -358,14 +401,14 @@ public final class GameActionUtil {
if (newSA2.canPlay()) {
newAbilities.add(newSA2);
}
abilities.clear();
abilities.addAll(newAbilities);
}
}
return abilities;
}
public static SpellAbility addExtraKeywordCost(final SpellAbility sa) {
if (!sa.isSpell() || sa.isCopied()) {
return sa;

View File

@@ -352,6 +352,9 @@ public final class AbilityFactory {
if (mapParams.containsKey("TargetsWithSameCreatureType")) {
abTgt.setWithSameCreatureType(true);
}
if (mapParams.containsKey("TargetsWithSameCardType")) {
abTgt.setWithSameCardType(true);
}
if (mapParams.containsKey("TargetsWithSameController")) {
abTgt.setSameController(true);
}

View File

@@ -153,6 +153,7 @@ public enum ApiType {
SkipTurn (SkipTurnEffect.class),
StoreSVar (StoreSVarEffect.class),
StoreMap (StoreMapEffect.class),
Subgame (SubgameEffect.class),
Surveil (SurveilEffect.class),
SwitchBlock (SwitchBlockEffect.class),
Tap (TapEffect.class),

View File

@@ -332,8 +332,7 @@ public abstract class SpellAbilityEffect {
}
}
protected static void addForgetOnMovedTrigger(final Card card, final String zone) {
String trig = "Mode$ ChangesZone | ValidCard$ Card.IsRemembered | Origin$ " + zone + " | Destination$ Any | TriggerZones$ Command | Static$ True";
protected static SpellAbility getForgetSpellAbility(final Card card) {
String forgetEffect = "DB$ Pump | ForgetObjects$ TriggeredCard";
String exileEffect = "DB$ ChangeZone | Defined$ Self | Origin$ Command | Destination$ Exile"
+ " | ConditionDefined$ Remembered | ConditionPresent$ Card | ConditionCompare$ EQ0";
@@ -341,11 +340,23 @@ public abstract class SpellAbilityEffect {
SpellAbility saForget = AbilityFactory.getAbility(forgetEffect, card);
AbilitySub saExile = (AbilitySub) AbilityFactory.getAbility(exileEffect, card);
saForget.setSubAbility(saExile);
return saForget;
}
protected static void addForgetOnMovedTrigger(final Card card, final String zone) {
String trig = "Mode$ ChangesZone | ValidCard$ Card.IsRemembered | Origin$ " + zone + " | ExcludedDestinations$ Stack | Destination$ Any | TriggerZones$ Command | Static$ True";
final Trigger parsedTrigger = TriggerHandler.parseTrigger(trig, card, true);
parsedTrigger.setOverridingAbility(saForget);
final Trigger addedTrigger = card.addTrigger(parsedTrigger);
addedTrigger.setIntrinsic(true);
parsedTrigger.setOverridingAbility(getForgetSpellAbility(card));
card.addTrigger(parsedTrigger);
}
protected static void addForgetOnCastTrigger(final Card card) {
String trig = "Mode$ SpellCast | ValidCard$ Card.IsRemembered | TriggerZones$ Command | Static$ True";
final Trigger parsedTrigger = TriggerHandler.parseTrigger(trig, card, true);
parsedTrigger.setOverridingAbility(getForgetSpellAbility(card));
card.addTrigger(parsedTrigger);
}
protected static void addExileOnMovedTrigger(final Card card, final String zone) {
@@ -368,35 +379,18 @@ public abstract class SpellAbilityEffect {
protected static void addForgetOnPhasedInTrigger(final Card card) {
String trig = "Mode$ PhaseIn | ValidCard$ Card.IsRemembered | TriggerZones$ Command | Static$ True";
String forgetEffect = "DB$ Pump | ForgetObjects$ TriggeredCard";
String exileEffect = "DB$ ChangeZone | Defined$ Self | Origin$ Command | Destination$ Exile"
+ " | ConditionDefined$ Remembered | ConditionPresent$ Card | ConditionCompare$ EQ0";
SpellAbility saForget = AbilityFactory.getAbility(forgetEffect, card);
AbilitySub saExile = (AbilitySub) AbilityFactory.getAbility(exileEffect, card);
saForget.setSubAbility(saExile);
final Trigger parsedTrigger = TriggerHandler.parseTrigger(trig, card, true);
parsedTrigger.setOverridingAbility(saForget);
final Trigger addedTrigger = card.addTrigger(parsedTrigger);
addedTrigger.setIntrinsic(true);
parsedTrigger.setOverridingAbility(getForgetSpellAbility(card));
card.addTrigger(parsedTrigger);
}
protected static void addForgetCounterTrigger(final Card card, final String counterType) {
String trig = "Mode$ CounterRemoved | TriggerZones$ Command | ValidCard$ Card.IsRemembered | CounterType$ " + counterType + " | NewCounterAmount$ 0 | Static$ True";
String forgetEffect = "DB$ Pump | ForgetObjects$ TriggeredCard";
String exileEffect = "DB$ ChangeZone | Defined$ Self | Origin$ Command | Destination$ Exile"
+ " | ConditionDefined$ Remembered | ConditionPresent$ Card | ConditionCompare$ EQ0";
SpellAbility saForget = AbilityFactory.getAbility(forgetEffect, card);
AbilitySub saExile = (AbilitySub) AbilityFactory.getAbility(exileEffect, card);
saForget.setSubAbility(saExile);
final Trigger parsedTrigger = TriggerHandler.parseTrigger(trig, card, true);
parsedTrigger.setOverridingAbility(saForget);
final Trigger addedTrigger = card.addTrigger(parsedTrigger);
addedTrigger.setIntrinsic(true);
parsedTrigger.setOverridingAbility(getForgetSpellAbility(card));
card.addTrigger(parsedTrigger);
}
protected static void addLeaveBattlefieldReplacement(final Card card, final SpellAbility sa, final String zone) {

View File

@@ -701,6 +701,13 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
if (sa.hasParam("ExileFaceDown")) {
movedCard.turnFaceDown(true);
}
if (sa.hasParam("Foretold")) {
movedCard.setForetold(true);
movedCard.setForetoldThisTurn(true);
movedCard.setForetoldByEffect(true);
// look at the exiled card
movedCard.addMayLookTemp(sa.getActivatingPlayer());
}
if (sa.hasParam("TrackDiscarded")) {
movedCard.setMadnessWithoutCast(true);
@@ -1240,6 +1247,13 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
if (sa.hasParam("ExileFaceDown")) {
movedCard.turnFaceDown(true);
}
if (sa.hasParam("Foretold")) {
movedCard.setForetold(true);
movedCard.setForetoldThisTurn(true);
movedCard.setForetoldByEffect(true);
// look at the exiled card
movedCard.addMayLookTemp(sa.getActivatingPlayer());
}
}
else {
movedCard = game.getAction().moveTo(destination, c, 0, cause, moveParams);

View File

@@ -1,14 +1,16 @@
package forge.game.ability.effects;
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.player.Player;
import forge.game.spellability.SpellAbility;
import forge.game.spellability.TargetRestrictions;
import forge.util.CardTranslation;
import forge.util.Localizer;
import java.util.ArrayList;
import java.util.List;
@@ -21,21 +23,27 @@ public class ControlExchangeEffect extends SpellAbilityEffect {
protected String getStackDescription(SpellAbility sa) {
Card object1 = null;
Card object2 = null;
final TargetRestrictions tgt = sa.getTargetRestrictions();
List<Card> tgts = tgt == null ? new ArrayList<>() : Lists.newArrayList(sa.getTargets().getTargetCards());
if (tgts.size() > 0) {
object1 = tgts.get(0);
List<Card> tgts = null;
if (sa.usesTargeting()) {
tgts = Lists.newArrayList(sa.getTargets().getTargetCards());
if (tgts.size() > 0) {
object1 = tgts.get(0);
}
}
if (sa.hasParam("Defined")) {
List<Card> cards = AbilityUtils.getDefinedCards(sa.getHostCard(), sa.getParam("Defined"), sa);
object2 = cards.isEmpty() ? null : cards.get(0);
if (cards.size() > 1 && sa.hasParam("BothDefined")) {
if (cards.size() > 1 && !sa.usesTargeting()) {
object1 = cards.get(1);
}
} else if (tgts.size() > 1) {
object2 = tgts.get(1);
}
if (object1 == null || object2 == null) {
return "";
}
return object1 + " exchanges controller with " + object2;
}
@@ -44,17 +52,22 @@ public class ControlExchangeEffect extends SpellAbilityEffect {
*/
@Override
public void resolve(SpellAbility sa) {
Card host = sa.getHostCard();
Game game = host.getGame();
Card object1 = null;
Card object2 = null;
final TargetRestrictions tgt = sa.getTargetRestrictions();
List<Card> tgts = tgt == null ? new ArrayList<>() : Lists.newArrayList(sa.getTargets().getTargetCards());
if (tgts.size() > 0) {
object1 = tgts.get(0);
List<Card> tgts = null;
if (sa.usesTargeting()) {
tgts = Lists.newArrayList(sa.getTargets().getTargetCards());
if (tgts.size() > 0) {
object1 = tgts.get(0);
}
}
if (sa.hasParam("Defined")) {
final List<Card> cards = AbilityUtils.getDefinedCards(sa.getHostCard(), sa.getParam("Defined"), sa);
final List<Card> cards = AbilityUtils.getDefinedCards(host, sa.getParam("Defined"), sa);
object2 = cards.isEmpty() ? null : cards.get(0);
if (cards.size() > 1 && sa.hasParam("BothDefined")) {
if (cards.size() > 1 && !sa.usesTargeting()) {
object1 = cards.get(1);
}
} else if (tgts.size() > 1) {
@@ -73,7 +86,16 @@ public class ControlExchangeEffect extends SpellAbilityEffect {
return;
}
final long tStamp = sa.getActivatingPlayer().getGame().getNextTimestamp();
if (sa.hasParam("Optional")) {
if (!sa.getActivatingPlayer().getController().confirmAction(sa, null,
Localizer.getInstance().getMessage("lblExchangeControl",
CardTranslation.getTranslatedName(object1.getName()),
CardTranslation.getTranslatedName(object2.getName())))) {
return;
}
}
final long tStamp = game.getNextTimestamp();
object2.setController(player1, tStamp);
object1.setController(player2, tStamp);
if (sa.hasParam("RememberExchanged")) {

View File

@@ -13,9 +13,11 @@ import forge.game.card.Card;
import forge.game.card.CardCollectionView;
import forge.game.card.CardFactory;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.card.CardZoneTable;
import forge.game.event.GameEventCombatChanged;
import forge.game.player.Player;
import forge.game.player.PlayerActionConfirmMode;
import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType;
import forge.item.PaperCard;
@@ -141,12 +143,25 @@ public class CopyPermanentEffect extends TokenEffectBase {
CardCollectionView choices = game.getCardsIn(ZoneType.Battlefield);
choices = CardLists.getValidCards(choices, sa.getParam("Choices"), activator, host);
if (!choices.isEmpty()) {
String title = sa.hasParam("ChoiceTitle") ? sa.getParam("ChoiceTitle") : Localizer.getInstance().getMessage("lblChooseaCard") +" ";
String title = sa.hasParam("ChoiceTitle") ? sa.getParam("ChoiceTitle") : Localizer.getInstance().getMessage("lblChooseaCard");
Card choosen = chooser.getController().chooseSingleEntityForEffect(choices, sa, title, false, null);
if (sa.hasParam("WithDifferentNames")) {
// any Number of choices with different names
while (!choices.isEmpty()) {
Card choosen = chooser.getController().chooseSingleEntityForEffect(choices, sa, title, true, null);
if (choosen != null) {
tgtCards.add(choosen);
if (choosen != null) {
tgtCards.add(choosen);
choices = CardLists.filter(choices, Predicates.not(CardPredicates.sharesNameWith(choosen)));
} else if (chooser.getController().confirmAction(sa, PlayerActionConfirmMode.OptionalChoose, Localizer.getInstance().getMessage("lblCancelChooseConfirm"))) {
break;
}
}
} else {
Card choosen = chooser.getController().chooseSingleEntityForEffect(choices, sa, title, false, null);
if (choosen != null) {
tgtCards.add(choosen);
}
}
}
} else {
@@ -208,3 +223,5 @@ public class CopyPermanentEffect extends TokenEffectBase {
return copy;
}
}

View File

@@ -215,6 +215,7 @@ public class EffectEffect extends SpellAbilityEffect {
}
if (sa.hasParam("ForgetOnMoved")) {
addForgetOnMovedTrigger(eff, sa.getParam("ForgetOnMoved"));
addForgetOnCastTrigger(eff);
} else if (sa.hasParam("ExileOnMoved")) {
addExileOnMovedTrigger(eff, sa.getParam("ExileOnMoved"));
}

View File

@@ -0,0 +1,254 @@
package forge.game.ability.effects;
import java.util.*;
import com.google.common.collect.Lists;
import forge.card.MagicColor;
import forge.game.Game;
import forge.game.GameOutcome;
import forge.game.ability.ApiType;
import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card;
import forge.game.card.CardCollectionView;
import forge.game.event.GameEventSubgameStart;
import forge.game.event.GameEventSubgameEnd;
import forge.game.player.Player;
import forge.game.player.PlayerController;
import forge.game.player.RegisteredPlayer;
import forge.game.spellability.SpellAbility;
import forge.game.zone.PlayerZone;
import forge.game.zone.ZoneType;
import forge.item.PaperCard;
import forge.util.CardTranslation;
import forge.util.Lang;
import forge.util.Localizer;
import forge.util.collect.FCollectionView;
public class SubgameEffect extends SpellAbilityEffect {
private final Game createSubGame(Game maingame, int startingLife) {
List<RegisteredPlayer> players = Lists.newArrayList();
// Add remaining players to subgame
for (Player p : maingame.getPlayers()) {
players.add(p.getRegisteredPlayer());
}
return new Game(players, maingame.getRules(), maingame.getMatch(), startingLife);
}
private final void setCardsInZone(Player player, final ZoneType zoneType, final CardCollectionView oldCards, boolean addMapping) {
PlayerZone zone = player.getZone(zoneType);
List<Card> newCards = Lists.newArrayList();
for (final Card card : oldCards) {
if (card.isToken() || card.isCopiedSpell()) continue;
Card newCard = Card.fromPaperCard(card.getPaperCard(), player);
newCards.add(newCard);
if (addMapping) {
// Build mapping between maingame cards and subgame cards,
// so when subgame pick a card from maingame (like Wish effects),
// The maingame card will also be moved.
// (Will be move to Subgame zone, which will be added back to libary after subgame ends.)
player.addMaingameCardMapping(newCard, card);
}
}
zone.setCards(newCards);
}
private final void initVariantsZonesSubgame(final Game subgame, final Player maingamePlayer, final Player player) {
PlayerZone com = player.getZone(ZoneType.Command);
RegisteredPlayer registeredPlayer = player.getRegisteredPlayer();
// Vanguard
if (registeredPlayer.getVanguardAvatars() != null) {
for(PaperCard avatar:registeredPlayer.getVanguardAvatars()) {
com.add(Card.fromPaperCard(avatar, player));
}
}
// Commander
List<Card> commanders = Lists.newArrayList();
final CardCollectionView commandCards = maingamePlayer.getCardsIn(ZoneType.Command);
for (final Card card : commandCards) {
if (card.isCommander()) {
Card cmd = Card.fromPaperCard(card.getPaperCard(), player);
if (cmd.hasKeyword("If CARDNAME is your commander, choose a color before the game begins.")) {
List<String> colorChoices = new ArrayList<>(MagicColor.Constant.ONLY_COLORS);
String prompt = Localizer.getInstance().getMessage("lblChooseAColorFor", cmd.getName());
List<String> chosenColors;
SpellAbility cmdColorsa = new SpellAbility.EmptySa(ApiType.ChooseColor, cmd, player);
chosenColors = player.getController().chooseColors(prompt,cmdColorsa, 1, 1, colorChoices);
cmd.setChosenColors(chosenColors);
subgame.getAction().nofityOfValue(cmdColorsa, cmd, Localizer.getInstance().getMessage("lblPlayerPickedChosen", player.getName(), Lang.joinHomogenous(chosenColors)), player);
}
cmd.setCommander(true);
com.add(cmd);
commanders.add(cmd);
com.add(Player.createCommanderEffect(subgame, cmd));
}
}
if (!commanders.isEmpty()) {
player.setCommanders(commanders);
}
// Conspiracies
// 720.2 doesn't mention Conspiracy cards so I guess they don't move
}
private void prepareAllZonesSubgame(final Game maingame, final Game subgame) {
final FCollectionView<Player> players = subgame.getPlayers();
final FCollectionView<Player> maingamePlayers = maingame.getPlayers();
final List<ZoneType> outsideZones = Arrays.asList(ZoneType.Hand, ZoneType.Battlefield,
ZoneType.Graveyard, ZoneType.Exile, ZoneType.Stack, ZoneType.Sideboard, ZoneType.Ante);
for (int i = 0; i < players.size(); i++) {
final Player player = players.get(i);
final Player maingamePlayer = maingamePlayers.get(i);
// Library
setCardsInZone(player, ZoneType.Library, maingamePlayer.getCardsIn(ZoneType.Library), false);
// Sideboard
// 720.4
final CardCollectionView outsideCards = maingame.getCardsInOwnedBy(outsideZones, maingamePlayer);
if (!outsideCards.isEmpty()) {
setCardsInZone(player, ZoneType.Sideboard, outsideCards, true);
// Assign Companion
PlayerController person = player.getController();
Card companion = player.assignCompanion(subgame, person);
// Create an effect that lets you cast your companion from your sideboard
if (companion != null) {
PlayerZone commandZone = player.getZone(ZoneType.Command);
companion = subgame.getAction().moveTo(ZoneType.Command, companion, null);
commandZone.add(Player.createCompanionEffect(subgame, companion));
player.updateZoneForView(commandZone);
}
}
// Schemes
setCardsInZone(player, ZoneType.SchemeDeck, maingamePlayer.getCardsIn(ZoneType.SchemeDeck), false);
// Planes
setCardsInZone(player, ZoneType.PlanarDeck, maingamePlayer.getCardsIn(ZoneType.PlanarDeck), false);
// Vanguard and Commanders
initVariantsZonesSubgame(subgame, maingamePlayer, player);
player.shuffle(null);
player.getZone(ZoneType.SchemeDeck).shuffle();
player.getZone(ZoneType.PlanarDeck).shuffle();
}
}
@Override
public void resolve(SpellAbility sa) {
final Card hostCard = sa.getHostCard();
final Game maingame = hostCard.getGame();
int startingLife = -1;
if (sa.hasParam("StartingLife")) {
startingLife = Integer.parseInt(sa.getParam("StartingLife"));
}
Game subgame = createSubGame(maingame, startingLife);
subgame.setMaingame(maingame);
String startMessage = Localizer.getInstance().getMessage("lblSubgameStart",
CardTranslation.getTranslatedName(hostCard.getName()));
maingame.fireEvent(new GameEventSubgameStart(subgame, startMessage));
prepareAllZonesSubgame(maingame, subgame);
subgame.getAction().startGame(null, null);
subgame.clearCaches();
// Find out winners and losers
final GameOutcome outcome = subgame.getOutcome();
List<Player> winPlayers = Lists.newArrayList();
List<Player> notWinPlayers = Lists.newArrayList();
StringBuilder sbWinners = new StringBuilder();
StringBuilder sbLosers = new StringBuilder();
for (Player p : maingame.getPlayers()) {
if (outcome.isWinner(p.getRegisteredPlayer())) {
if (!winPlayers.isEmpty()) {
sbWinners.append(", ");
}
sbWinners.append(p.getName());
winPlayers.add(p);
} else {
if (!notWinPlayers.isEmpty()) {
sbLosers.append(", ");
}
sbLosers.append(p.getName());
notWinPlayers.add(p);
}
}
if (sa.hasParam("RememberPlayers")) {
final String param = sa.getParam("RememberPlayers");
if (param.equals("Win")) {
for (Player p : winPlayers) {
hostCard.addRemembered(p);
}
} else if (param.equals("NotWin")) {
for (Player p : notWinPlayers) {
hostCard.addRemembered(p);
}
}
}
String endMessage = outcome.isDraw() ? Localizer.getInstance().getMessage("lblSubgameEndDraw") :
Localizer.getInstance().getMessage("lblSubgameEnd", sbWinners.toString(), sbLosers.toString());
maingame.fireEvent(new GameEventSubgameEnd(maingame, endMessage));
// Setup maingame library
final FCollectionView<Player> subgamePlayers = subgame.getRegisteredPlayers();
final FCollectionView<Player> players = maingame.getPlayers();
for (int i = 0; i < players.size(); i++) {
final Player subgamePlayer = subgamePlayers.get(i);
final Player player = players.get(i);
// All cards moved to Subgame Zone will be put into library when subgame ends.
// 720.5
final CardCollectionView movedCards = player.getCardsIn(ZoneType.Subgame);
PlayerZone library = player.getZone(ZoneType.Library);
for (final Card card : movedCards) {
library.add(card);
}
player.getZone(ZoneType.Subgame).removeAllCards(true);
// Move commander if it is no longer in subgame's commander zone
// 720.5c
List<Card> subgameCommanders = Lists.newArrayList();
List<Card> movedCommanders = Lists.newArrayList();
for (final Card card : subgamePlayer.getCardsIn(ZoneType.Command)) {
if (card.isCommander()) {
subgameCommanders.add(card);
}
}
for (final Card card : player.getCardsIn(ZoneType.Command)) {
if (card.isCommander()) {
boolean isInSubgameCommand = false;
for (final Card subCard : subgameCommanders) {
if (card.getName().equals(subCard.getName())) {
isInSubgameCommand = true;
}
}
if (!isInSubgameCommand) {
movedCommanders.add(card);
}
}
}
for (final Card card : movedCommanders) {
maingame.getAction().moveTo(ZoneType.Library, card, null);
}
player.shuffle(sa);
player.getZone(ZoneType.SchemeDeck).shuffle();
player.getZone(ZoneType.PlanarDeck).shuffle();
}
}
}

View File

@@ -154,7 +154,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
private boolean hasdealtDamagetoAny = false;
private boolean isCommander = false;
private boolean canMoveToCommandZone = false;
private boolean canMoveToCommandZone = false;
private boolean startsGameInPlay = false;
private boolean drawnThisTurn = false;
@@ -177,6 +177,10 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
private boolean manifested = false;
private boolean foretold = false;
private boolean foretoldThisTurn = false;
private boolean foretoldByEffect = false;
private long bestowTimestamp = -1;
private long transformedTimestamp = 0;
private boolean tributed = false;
@@ -1694,7 +1698,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
} else {
sbLong.append(parts[0]).append(" ").append(ManaCostParser.parse(parts[1])).append("\r\n");
}
} else if (keyword.startsWith("Morph") || keyword.startsWith("Megamorph") || keyword.startsWith("Escape")) {
} else if (keyword.startsWith("Morph") || keyword.startsWith("Megamorph") || keyword.startsWith("Escape") || keyword.startsWith("Foretell:")) {
String[] k = keyword.split(":");
sbLong.append(k[0]);
if (k.length > 1) {
@@ -1789,6 +1793,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|| keyword.equals("Changeling") || keyword.equals("Delve")
|| keyword.equals("Split second") || keyword.equals("Sunburst")
|| keyword.equals("Suspend") // for the ones without amounnt
|| keyword.equals("Foretell") // for the ones without cost
|| keyword.equals("Hideaway") || keyword.equals("Ascend")
|| keyword.equals("Totem armor") || keyword.equals("Battle cry")
|| keyword.equals("Devoid") || keyword.equals("Riot")){
@@ -2236,7 +2241,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
sbBefore.append("\r\n");
} else if (keyword.startsWith("Entwine") || keyword.startsWith("Madness")
|| keyword.startsWith("Miracle") || keyword.startsWith("Recover")
|| keyword.startsWith("Escape")) {
|| keyword.startsWith("Escape") || keyword.startsWith("Foretell:")) {
final String[] k = keyword.split(":");
final Cost cost = new Cost(k[1], false);
@@ -5319,6 +5324,42 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
}
}
public final boolean isForetold() {
// in exile and foretold
if (this.isInZone(ZoneType.Exile)) {
return this.foretold;
}
// cast as foretold, currently only spells
if (this.getCastSA() != null) {
return this.getCastSA().isForetold();
}
return false;
}
public final void setForetold(final boolean foretold) {
this.foretold = foretold;
}
public boolean isForetoldByEffect() {
return foretoldByEffect;
}
public void setForetoldByEffect(final boolean val) {
this.foretoldByEffect = val;
}
public boolean isForetoldThisTurn() {
return foretoldThisTurn;
}
public final void setForetoldThisTurn(final boolean foretoldThisTurn) {
this.foretoldThisTurn = foretoldThisTurn;
}
public void resetForetoldThisTurn() {
foretoldThisTurn = false;
}
public final void animateBestow() {
animateBestow(true);
}
@@ -6567,11 +6608,6 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
return numberGameActivations.containsKey(original) ? numberGameActivations.get(original) : 0;
}
public void resetTurnActivations() {
numberTurnActivations.clear();
numberTurnActivationsStatic.clear();
}
public List<String> getChosenModesTurn(SpellAbility ability) {
SpellAbility original = null;
SpellAbility root = ability.getRootAbility();

View File

@@ -88,7 +88,7 @@ public class CardFactory {
}
out.setZone(in.getZone());
out.setState(in.getCurrentStateName(), true);
out.setState(in.getFaceupCardStateName(), true);
out.setBackSide(in.isBackSide());
// this's necessary for forge.game.GameAction.unattachCardLeavingBattlefield(Card)

View File

@@ -66,7 +66,6 @@ import java.util.Map.Entry;
import io.sentry.Sentry;
import io.sentry.event.BreadcrumbBuilder;
/**
* <p>
* CardFactoryUtil class.
@@ -1404,6 +1403,13 @@ public class CardFactoryUtil {
return doXMath(StringUtils.isNumeric(v) ? Integer.parseInt(v) : xCount(c, c.getSVar(v)), m, c);
}
// Count$Foretold.<True>.<False>
if (sq[0].startsWith("Foretold")) {
String v = c.isForetold() ? sq[1] : sq[2];
// TODO move this to AbilityUtils
return doXMath(StringUtils.isNumeric(v) ? Integer.parseInt(v) : xCount(c, c.getSVar(v)), m, c);
}
// Count$Presence_<Type>.<True>.<False>
if (sq[0].startsWith("Presence")) {
final String type = sq[0].split("_")[1];
@@ -1449,7 +1455,6 @@ public class CardFactoryUtil {
return forge.util.MyRandom.getRandom().nextInt(1+max-min) + min;
}
// Count$Domain
if (sq[0].startsWith("Domain")) {
int n = 0;
@@ -1997,7 +2002,6 @@ public class CardFactoryUtil {
final Set<String> hexproofkw = Sets.newHashSet();
final Set<String> allkw = Sets.newHashSet();
for (Card c : CardLists.getValidCards(cardlist, restrictions, p, host, null)) {
for (KeywordInterface inst : c.getKeywords()) {
final String k = inst.getOriginal();
@@ -2155,7 +2159,6 @@ public class CardFactoryUtil {
return re;
}
public static ReplacementEffect makeEtbCounter(final String kw, final Card card, final boolean intrinsic)
{
String parse = kw;
@@ -4095,6 +4098,60 @@ public class CardFactoryUtil {
newSA.setAlternativeCost(AlternativeCost.Evoke);
newSA.setIntrinsic(intrinsic);
inst.addSpellAbility(newSA);
} else if (keyword.startsWith("Foretell")) {
final SpellAbility foretell = new AbilityStatic(card, new Cost(ManaCost.TWO, false), null) {
@Override
public boolean canPlay() {
if (!getRestrictions().canPlay(getHostCard(), this)) {
return false;
}
Player activator = this.getActivatingPlayer();
final Game game = activator.getGame();
if (!activator.hasKeyword("Foretell on any players turn") && !game.getPhaseHandler().isPlayerTurn(activator)) {
return false;
}
return true;
}
@Override
public boolean isForetelling() {
return true;
}
@Override
public void resolve() {
final Game game = getHostCard().getGame();
final Card c = game.getAction().exile(getHostCard(), this);
c.setForetold(true);
c.setForetoldThisTurn(true);
c.turnFaceDown(true);
// look at the exiled card
c.addMayLookTemp(getActivatingPlayer());
// only done when the card is foretold by the static ability
getActivatingPlayer().addForetoldThisTurn();
if (!isIntrinsic()) {
// because it doesn't work other wise
c.setForetoldByEffect(true);
}
String sb = TextUtil.concatWithSpace(getActivatingPlayer().toString(),"has foretold.");
game.getGameLog().add(GameLogEntryType.STACK_RESOLVE, sb);
}
};
final StringBuilder sbDesc = new StringBuilder();
sbDesc.append("Foretell (").append(inst.getReminderText()).append(")");
foretell.setDescription(sbDesc.toString());
foretell.putParam("Secondary", "True");
foretell.getRestrictions().setZone(ZoneType.Hand);
foretell.setIntrinsic(intrinsic);
inst.addSpellAbility(foretell);
} else if (keyword.startsWith("Fortify")) {
String[] k = keyword.split(":");
// Get cost string

View File

@@ -1670,36 +1670,40 @@ public class CardProperty {
if (property.equals("pseudokicked")) {
if (!card.isOptionalCostPaid(OptionalCost.Generic)) return false;
}
} else if (property.startsWith("surged")) {
} else if (property.equals("surged")) {
if (card.getCastSA() == null) {
return false;
}
return card.getCastSA().isSurged();
} else if (property.startsWith("dashed")) {
} else if (property.equals("dashed")) {
if (card.getCastSA() == null) {
return false;
}
return card.getCastSA().isDash();
} else if (property.startsWith("escaped")) {
} else if (property.equals("escaped")) {
if (card.getCastSA() == null) {
return false;
}
return card.getCastSA().isEscape();
} else if (property.startsWith("evoked")) {
} else if (property.equals("evoked")) {
if (card.getCastSA() == null) {
return false;
}
return card.getCastSA().isEvoke();
} else if (property.startsWith("prowled")) {
} else if (property.equals("prowled")) {
if (card.getCastSA() == null) {
return false;
}
return card.getCastSA().isProwl();
} else if (property.startsWith("spectacle")) {
} else if (property.equals("spectacle")) {
if (card.getCastSA() == null) {
return false;
}
return card.getCastSA().isSpectacle();
} else if (property.equals("foretold")) {
if (!card.isForetold()) {
return false;
}
} else if (property.equals("HasDevoured")) {
if (card.getDevouredCards().isEmpty()) {
return false;

View File

@@ -278,6 +278,10 @@ public final class CardUtil {
newCopy.copyChangedTextFrom(in);
newCopy.setForetold(in.isForetold());
newCopy.setForetoldThisTurn(in.isForetoldThisTurn());
newCopy.setForetoldByEffect(in.isForetoldByEffect());
newCopy.setMeldedWith(getLKICopy(in.getMeldedWith(), cachedMap));
newCopy.setTimestamp(in.getTimestamp());

View File

@@ -19,7 +19,6 @@ package forge.game.cost;
import com.google.common.collect.Lists;
import forge.game.ability.AbilityUtils;
import forge.game.card.Card;
import forge.game.card.CardLists;
import forge.game.card.CounterEnumType;

View File

@@ -0,0 +1,18 @@
package forge.game.event;
import forge.game.Game;
public class GameEventSubgameEnd extends GameEvent {
public final Game maingame;
public final String message;
public GameEventSubgameEnd(Game game, String message0) {
maingame = game;
message = message0;
}
@Override
public <T> T visit(IGameEventVisitor<T> visitor) {
return visitor.visit(this);
}
}

View File

@@ -0,0 +1,18 @@
package forge.game.event;
import forge.game.Game;
public class GameEventSubgameStart extends GameEvent {
public final Game subgame;
public final String message;
public GameEventSubgameStart(Game subgame0, String message0) {
subgame = subgame0;
message = message0;
}
@Override
public <T> T visit(IGameEventVisitor<T> visitor) {
return visitor.visit(this);
}
}

View File

@@ -44,6 +44,8 @@ public interface IGameEventVisitor<T> {
T visit(GameEventSpellAbilityCast gameEventSpellAbilityCast);
T visit(GameEventSpellResolved event);
T visit(GameEventSpellRemovedFromStack event);
T visit(GameEventSubgameStart event);
T visit(GameEventSubgameEnd event);
T visit(GameEventSurveil event);
T visit(GameEventTokenCreated event);
T visit(GameEventTurnBegan gameEventTurnBegan);
@@ -92,6 +94,8 @@ public interface IGameEventVisitor<T> {
public T visit(GameEventSpellResolved event) { return null; }
public T visit(GameEventSpellAbilityCast event) { return null; }
public T visit(GameEventSpellRemovedFromStack event) { return null; }
public T visit(GameEventSubgameStart event) { return null; }
public T visit(GameEventSubgameEnd event) { return null; }
public T visit(GameEventSurveil event) { return null; }
public T visit(GameEventTokenCreated event) { return null; }
public T visit(GameEventTurnBegan event) { return null; }

View File

@@ -70,6 +70,7 @@ public enum Keyword {
FLASH("Flash", SimpleKeyword.class, true, "You may cast this spell any time you could cast an instant."),
FLASHBACK("Flashback", KeywordWithCost.class, false, "You may cast this card from your graveyard by paying %s rather than paying its mana cost. If you do, exile it as it resolves."),
FLYING("Flying", SimpleKeyword.class, true, "This creature can't be blocked except by creatures with flying or reach."),
FORETELL("Foretell", KeywordWithCost.class, false, "During your turn, you may pay {2} and exile this card from your hand face down. Cast it on a later turn for its foretell cost."),
FORTIFY("Fortify", KeywordWithCost.class, false, "%s: Attach to target land you control. Fortify only as a sorcery."),
FRENZY("Frenzy", KeywordWithAmount.class, false, "Whenever this creature attacks and isn't blocked, it gets +%d/+0 until end of turn."),
GRAFT("Graft", KeywordWithAmount.class, false, "This permanent enters the battlefield with {%d:+1/+1 counter} on it. Whenever another creature enters the battlefield, you may move a +1/+1 counter from this permanent onto it."),

View File

@@ -26,7 +26,6 @@ import forge.game.*;
import forge.game.ability.AbilityKey;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates.Presets;
import forge.game.card.CardZoneTable;
@@ -175,8 +174,7 @@ public class PhaseHandler implements java.io.Serializable {
game.fireEvent(new GameEventTurnBegan(playerTurn, turn));
// Tokens starting game in play should suffer from Sum. Sickness
final CardCollectionView list = playerTurn.getCardsIncludePhasingIn(ZoneType.Battlefield);
for (final Card c : list) {
for (final Card c : playerTurn.getCardsIncludePhasingIn(ZoneType.Battlefield)) {
if (playerTurn.getTurn() > 0 || !c.isStartsGameInPlay()) {
c.setSickness(false);
}

View File

@@ -77,7 +77,7 @@ import java.util.concurrent.ConcurrentSkipListMap;
public class Player extends GameEntity implements Comparable<Player> {
public static final List<ZoneType> ALL_ZONES = Collections.unmodifiableList(Arrays.asList(ZoneType.Battlefield,
ZoneType.Library, ZoneType.Graveyard, ZoneType.Hand, ZoneType.Exile, ZoneType.Command, ZoneType.Ante,
ZoneType.Sideboard, ZoneType.PlanarDeck, ZoneType.SchemeDeck));
ZoneType.Sideboard, ZoneType.PlanarDeck, ZoneType.SchemeDeck, ZoneType.Subgame));
private final Map<Card, Integer> commanderDamage = Maps.newHashMap();
@@ -111,6 +111,7 @@ public class Player extends GameEntity implements Comparable<Player> {
private int numDrawnThisDrawStep = 0;
private int numDiscardedThisTurn = 0;
private int numTokenCreatedThisTurn = 0;
private int numForetoldThisTurn = 0;
private int numCardsInHandStartedThisTurnWith = 0;
private final Map<String, FCollection<String>> notes = Maps.newHashMap();
@@ -140,6 +141,7 @@ public class Player extends GameEntity implements Comparable<Player> {
private final Map<ZoneType, PlayerZone> zones = Maps.newEnumMap(ZoneType.class);
private final Map<Long, Integer> adjustLandPlays = Maps.newHashMap();
private final Set<Long> adjustLandPlaysInfinite = Sets.newHashSet();
private Map<Card, Card> maingameCardsMap = Maps.newHashMap();;
private CardCollection currentPlanes = new CardCollection();
private Set<String> prowl = Sets.newHashSet();
@@ -1666,6 +1668,22 @@ public class Player extends GameEntity implements Comparable<Player> {
numTokenCreatedThisTurn = 0;
}
public final int getNumForetoldThisTurn() {
return numForetoldThisTurn;
}
public final void addForetoldThisTurn() {
numForetoldThisTurn++;
final Map<AbilityKey, Object> runParams = AbilityKey.newMap();
runParams.put(AbilityKey.Player, this);
runParams.put(AbilityKey.Num, numForetoldThisTurn);
game.getTriggerHandler().runTrigger(TriggerType.Foretell, runParams, false);
}
public final void resetNumForetoldThisTurn() {
numForetoldThisTurn = 0;
}
public final int getNumDiscardedThisTurn() {
return numDiscardedThisTurn;
}
@@ -1905,6 +1923,14 @@ public class Player extends GameEntity implements Comparable<Player> {
return !adjustLandPlaysInfinite.isEmpty();
}
public final void addMaingameCardMapping(Card subgameCard, Card maingameCard) {
maingameCardsMap.put(subgameCard, maingameCard);
}
public final Card getMappingMaingameCard(Card subgameCard) {
return maingameCardsMap.get(subgameCard);
}
public final ManaPool getManaPool() {
return manaPool;
}
@@ -2581,7 +2607,7 @@ public class Player extends GameEntity implements Comparable<Player> {
controlledBy.remove(timestamp);
getView().updateMindSlaveMaster(this);
if (event) {
game.fireEvent(new GameEventPlayerControl(this, oldLobbyPlayer, oldController, getLobbyPlayer(), getController()));
}

View File

@@ -45,7 +45,7 @@ public class ReplaceAddCounter extends ReplacementEffect {
if (!(o instanceof Card)) {
return false;
}
if (!matchesValid(o, getParam("ValidCard").split(","), this.getHostCard())) {
if (!matchesValid(o, getParam("ValidCard").split(","), getHostCard())) {
return false;
}
} else if (hasParam("ValidPlayer")) {
@@ -53,7 +53,17 @@ public class ReplaceAddCounter extends ReplacementEffect {
if (!(o instanceof Player)) {
return false;
}
if (!matchesValid(o, getParam("ValidPlayer").split(","), this.getHostCard())) {
if (!matchesValid(o, getParam("ValidPlayer").split(","), getHostCard())) {
return false;
}
} else if (hasParam("ValidObject")) {
if (!matchesValid(runParams.get(AbilityKey.Affected), getParam("ValidObject").split(","), getHostCard())) {
return false;
}
}
if (hasParam("ValidSource")) {
if (!matchesValid(runParams.get(AbilityKey.Source), getParam("ValidSource").split(","), getHostCard())) {
return false;
}
}
@@ -81,6 +91,7 @@ public class ReplaceAddCounter extends ReplacementEffect {
} else if (o instanceof Player) {
sa.setReplacingObject(AbilityKey.Player, o);
}
sa.setReplacingObject(AbilityKey.Object, o);
}
}

View File

@@ -9,6 +9,7 @@ public enum AlternativeCost {
Escape,
Evoke,
Flashback,
Foretold,
Madness,
Offering,
Outlast, // ActivatedAbility

View File

@@ -466,23 +466,23 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
public final void clearManaPaid() {
payingMana.clear();
}
public final void applyPayingManaEffects() {
Card host = getHostCard();
for (Mana mana : getPayingMana()) {
if (mana.triggersWhenSpent()) {
mana.getManaAbility().addTriggersWhenSpent(this, host);
}
if (mana.addsCounters(this)) {
mana.getManaAbility().createETBCounters(host, getActivatingPlayer());
}
if (mana.addsNoCounterMagic(this) && host != null) {
host.setCanCounter(false);
}
if (isSpell() && host != null) {
if (mana.addsKeywords(this) && mana.addsKeywordsType()
&& host.getType().hasStringType(mana.getManaAbility().getAddsKeywordsType())) {
@@ -823,6 +823,14 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
return this.isAlternativeCost(AlternativeCost.Flashback);
}
public boolean isForetelling() {
return false;
}
public boolean isForetold() {
return this.isAlternativeCost(AlternativeCost.Foretold);
}
/**
* @return the aftermath
*/
@@ -1048,29 +1056,26 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
final Card c = (Card) entity;
CardCollection pl = AbilityUtils.getDefinedCards(getHostCard(), getParam("TargetsWithSharedCardType"), this);
for (final Card crd : pl) {
if (!c.sharesCardTypeWith(crd)) {
return false;
// one of those types
if (hasParam("TargetsWithSharedTypes")) {
boolean flag = false;
for (final String type : getParam("TargetsWithSharedTypes").split(",")) {
if (c.getType().hasStringType(type) && crd.getType().hasStringType(type)) {
flag = true;
break;
}
}
if (!flag) {
return false;
}
} else {
if (!c.sharesCardTypeWith(crd)) {
return false;
}
}
}
}
if (hasParam("TargetsWithSharedTypes") && entity instanceof Card) {
final Card c = (Card) entity;
final SpellAbility parent = getParentTargetingCard();
final Card parentTargeted = parent != null ? parent.getTargetCard() : null;
if (parentTargeted == null) {
return false;
}
boolean flag = false;
for (final String type : getParam("TargetsWithSharedTypes").split(",")) {
if (c.getType().hasStringType(type) && parentTargeted.getType().hasStringType(type)) {
flag = true;
break;
}
}
if (!flag) {
return false;
}
}
if (hasParam("TargetsWithControllerProperty") && entity instanceof Card) {
final String prop = getParam("TargetsWithControllerProperty");
final Card c = (Card) entity;
@@ -1164,6 +1169,16 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
}
}
if (tr.isWithSameCardType()) {
if (entity instanceof Card) {
for (final Card c : targetChosen.getTargetCards()) {
if (entity != c && !c.sharesCardTypeWith((Card) entity)) {
return false;
}
}
}
}
String[] validTgt = tr.getValidTgts();
if (entity instanceof GameEntity) {
GameEntity e = (GameEntity)entity;
@@ -1780,6 +1795,11 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
return false;
}
}
else if (incR[0].equals("Static")) {
if (!(root instanceof AbilityStatic)) {
return false;
}
}
else { //not a spell/ability type
return false;
}

View File

@@ -118,6 +118,10 @@ public class SpellAbilityCondition extends SpellAbilityVariables {
this.optionalCostPaid = true;
}
if (value.equals("Foretold")) {
this.foretold = true;
}
if (params.containsKey("ConditionOptionalPaid")) {
this.optionalBoolean = Boolean.parseBoolean(params.get("ConditionOptionalPaid"));
}
@@ -250,6 +254,7 @@ public class SpellAbilityCondition extends SpellAbilityVariables {
if (this.kicked2 && !sa.isOptionalCostPaid(OptionalCost.Kicker2)) return false;
if (this.altCostPaid && !sa.isOptionalCostPaid(OptionalCost.AltCost)) return false;
if (this.surgeCostPaid && !sa.isSurged()) return false;
if (this.foretold && !sa.isForetold()) return false;
if (this.optionalCostPaid && this.optionalBoolean && !sa.isOptionalCostPaid(OptionalCost.Generic)) return false;
if (this.optionalCostPaid && !this.optionalBoolean && sa.isOptionalCostPaid(OptionalCost.Generic)) return false;

View File

@@ -405,6 +405,7 @@ public class SpellAbilityVariables implements Cloneable {
protected boolean optionalCostPaid = false; // Undergrowth other Pseudo-kickers
protected boolean optionalBoolean = true; // Just in case you need to check if something wasn't kicked, etc
protected boolean surgeCostPaid = false;
protected boolean foretold = false;
/**
* @return the allTargetsLegal

View File

@@ -65,6 +65,7 @@ public class TargetRestrictions {
private boolean sameController = false;
private boolean withoutSameCreatureType = false;
private boolean withSameCreatureType = false;
private boolean withSameCardType = false;
private boolean singleTarget = false;
private boolean randomTarget = false;
@@ -108,6 +109,7 @@ public class TargetRestrictions {
this.sameController = target.isSameController();
this.withoutSameCreatureType = target.isWithoutSameCreatureType();
this.withSameCreatureType = target.isWithSameCreatureType();
this.withSameCardType = target.isWithSameCardType();
this.singleTarget = target.isSingleTarget();
this.randomTarget = target.isRandomTarget();
}
@@ -622,6 +624,20 @@ public class TargetRestrictions {
this.withSameCreatureType = b;
}
/**
* @return the withSameCardType
*/
public boolean isWithSameCardType() {
return withSameCardType;
}
/**
* @param b the withSameCardType to set
*/
public void setWithSameCardType(boolean b) {
this.withSameCardType = b;
}
/**
* <p>
* copy.

View File

@@ -0,0 +1,78 @@
/*
* Forge: Play Magic: the Gathering.
* Copyright (C) 2011 Forge Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package forge.game.trigger;
import forge.game.ability.AbilityKey;
import forge.game.card.Card;
import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
import forge.util.Localizer;
import java.util.Map;
/**
* @author Forge
*/
public class TriggerForetell extends Trigger {
/**
*
* @param params
* a {@link java.util.HashMap} object.
* @param host
* a {@link forge.game.card.Card} object.
* @param intrinsic
* the intrinsic
*/
public TriggerForetell(final Map<String, String> params, final Card host, final boolean intrinsic) {
super(params, host, intrinsic);
}
@Override
public String getImportantStackObjects(SpellAbility sa) {
StringBuilder sb = new StringBuilder();
sb.append(Localizer.getInstance().getMessage("lblPlayer")).append(": ").append(sa.getTriggeringObject(AbilityKey.Player));
return sb.toString();
}
/** {@inheritDoc} */
@Override
public final void setTriggeringObjects(final SpellAbility sa, Map<AbilityKey, Object> runParams) {
sa.setTriggeringObjectsFrom(runParams, AbilityKey.Player);
}
/** {@inheritDoc}
* @param runParams*/
@Override
public final boolean performTest(final Map<AbilityKey, Object> runParams) {
Player p = (Player) runParams.get(AbilityKey.Player);
if (hasParam("ValidPlayer")) {
if (!matchesValid(p, getParam("ValidPlayer").split(","), getHostCard())) {
return false;
}
}
if (hasParam("OnlyFirst")) {
if ((int) runParams.get(AbilityKey.Num) != 1) {
return false;
}
}
return true;
}
}

View File

@@ -64,6 +64,7 @@ public enum TriggerType {
Fight(TriggerFight.class),
FightOnce(TriggerFightOnce.class),
FlippedCoin(TriggerFlippedCoin.class),
Foretell(TriggerForetell.class),
Immediate(TriggerImmediate.class),
Investigated(TriggerInvestigated.class),
LandPlayed(TriggerLandPlayed.class),

View File

@@ -52,7 +52,6 @@ import forge.game.keyword.Keyword;
import forge.game.player.Player;
import forge.game.spellability.AbilityStatic;
import forge.game.spellability.OptionalCost;
import forge.game.spellability.Spell;
import forge.game.spellability.SpellAbility;
import forge.game.spellability.SpellAbilityStackInstance;
import forge.game.spellability.TargetChoices;
@@ -241,8 +240,7 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
if (sp.isSpell()) {
source.setController(activator, 0);
final Spell spell = (Spell) sp;
if (spell.isCastFaceDown()) {
if (sp.isCastFaceDown()) {
// Need to override for double faced cards
source.turnFaceDown(true);
} else if (source.isFaceDown()) {

View File

@@ -24,6 +24,7 @@ public enum ZoneType {
Ante(false, "lblAnteZone"),
SchemeDeck(true, "lblSchemeDeckZone"),
PlanarDeck(true, "lblPlanarDeckZone"),
Subgame(true, "lblSubgameZone"),
None(true, "lblNoneZone");
public static final List<ZoneType> STATIC_ABILITIES_SOURCE_ZONES = Arrays.asList(Battlefield, Graveyard, Exile, Command/*, Hand*/);

View File

@@ -1847,7 +1847,7 @@ public class GameSimulatorTest extends SimulationTestCase {
sim.simulateSpellAbility(gideonSA);
sim.simulateSpellAbility(sparkDoubleSA);
Card simSpark = (Card)sim.getGameCopier().find(sparkDouble);
Card simSpark = sim.getSimulatedGameState().findById(sparkDouble.getId());
assertNotNull(simSpark);
assertTrue(simSpark.isInZone(ZoneType.Battlefield));

View File

@@ -202,6 +202,12 @@ public class Forge implements ApplicationListener {
ImageCache.preloadCache(filteredkeys);
}
public static void openHomeScreen(boolean openNewGameMenu) {
openScreen(HomeScreen.instance);
if(openNewGameMenu)
HomeScreen.instance.openNewGamMenu();
}
private void afterDbLoaded() {
stopContinuousRendering(); //save power consumption by disabling continuous rendering once assets loaded
@@ -210,7 +216,7 @@ public class Forge implements ApplicationListener {
SoundSystem.instance.setBackgroundMusic(MusicPlaylist.MENUS); //start background music
destroyThis = false; //Allow back()
Gdx.input.setCatchKey(Keys.MENU, true);
openScreen(HomeScreen.instance);
openHomeScreen(false);
splashScreen = null;
boolean isLandscapeMode = isLandscapeMode();

View File

@@ -135,6 +135,10 @@ public class HomeScreen extends FScreen {
QuestWorld = questWorld;
}
public void openNewGamMenu(){
NewGameMenu.getPreferredScreen().open();
}
public boolean getQuestCommanderMode() {
return QuestCommander;
}

View File

@@ -77,14 +77,22 @@ public class ControlWinLose {
/** Action performed when "quit" button is pressed in default win/lose UI. */
public void actionOnQuit() {
boolean openHomeScreen = false;
// Reset other stuff
saveOptions();
try { MatchController.getHostedMatch().endCurrentGame();
try {
if(MatchController.getHostedMatch().subGameCount > 0) {
openHomeScreen = true;
MatchController.getHostedMatch().subGameCount--;
}
MatchController.getHostedMatch().endCurrentGame();
} catch (NullPointerException e) {}
view.hide();
if(humancount == 0) {
Forge.back();
}
if (openHomeScreen)
Forge.openHomeScreen(true);
}
/**

View File

@@ -5,9 +5,7 @@ T:Mode$ PlaneswalkedTo | ValidCard$ Card.Self | Execute$ TrigLife | OptionalDeci
T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | Execute$ TrigLife | TriggerZones$ Command | Secondary$ True | OptionalDecider$ You | TriggerDescription$ When you planeswalk to CARDNAME or at the beginning of your upkeep, you may exchange life totals with target player.
SVar:TrigLife:DB$ ExchangeLife | Optional$ True | ValidTgts$ Player | TgtPrompt$ Select target player to exchange life totals with
T:Mode$ PlanarDice | Result$ Chaos | TriggerZones$ Command | Execute$ RolledChaos | TriggerDescription$ Whenever you roll {CHAOS}, exchange control of two target permanents that share a card type.
SVar:RolledChaos:DB$ Pump | ValidTgts$ Permanent | TgtPrompt$ Select target permanent | SubAbility$ DBExchange
SVar:DBExchange:DB$ ExchangeControl | Defined$ ParentTarget | ValidTgts$ Permanent | TgtPrompt$ Select target permanent card | TargetsWithSharedTypes$ Creature,Artifact,Enchantment,Planeswalker,Land,Tribal | TargetUnique$ True
SVar:RolledChaos:DB$ ExchangeControl | TargetMin$ 2 | TargetMax$ 2 | ValidTgts$ Permanent | TgtPrompt$ Select target permanents that share a permanent type | TargetsWithSameCardType$ True
AI:RemoveDeck:All
AI:RemoveDeck:Random
SVar:Picture:http://www.wizards.com/global/images/magic/general/cliffside_market.jpg
Oracle:When you planeswalk to Cliffside Market or at the beginning of your upkeep, you may exchange life totals with target player.\nWhenever you roll {CHAOS}, exchange control of two target permanents that share a card type.

View File

@@ -4,5 +4,4 @@ Types:Enchantment
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Artifact,Creature,Enchantment | TriggerZones$ Battlefield | Execute$ TrigExchangeControl | TriggerDescription$ Whenever an artifact, creature, or enchantment enters the battlefield, its controller chooses target permanent another player controls that shares a card type with it. Exchange control of those permanents.
SVar:TrigExchangeControl:DB$ ExchangeControl | Defined$ TriggeredCard | TargetingPlayer$ TriggeredCardController | TargetsWithDefinedController$ NonTriggeredCardController | ValidTgts$ Permanent | TargetsWithSharedCardType$ TriggeredCard
AI:RemoveDeck:Random
SVar:Picture:http://www.wizards.com/global/images/magic/general/confusion_in_the_ranks.jpg
Oracle:Whenever an artifact, creature, or enchantment enters the battlefield, its controller chooses target permanent another player controls that shares a card type with it. Exchange control of those permanents.

View File

@@ -4,8 +4,7 @@ Types:Creature Human Rogue
PT:2/3
T:Mode$ Untaps | ValidCard$ Card.Self | TriggerZones$ Battlefield | Execute$ TrigExchangeControl | OptionalDecider$ You | TriggerDescription$ Inspired — Whenever CARDNAME becomes untapped, you may exchange control of target nonland permanent you control and target permanent an opponent controls that shares a card type with it.
SVar:TrigExchangeControl:DB$ Pump | ValidTgts$ Permanent.YouCtrl+nonLand | TgtPrompt$ Select target nonland permanent you control | SubAbility$ DBExchange
SVar:DBExchange:DB$ ExchangeControl | Defined$ ParentTarget | ValidTgts$ Permanent.OppCtrl | TgtPrompt$ Select target permanent an opponent controls that shares a card type with it | TargetsWithSharedTypes$ Creature,Artifact,Enchantment,Planeswalker,Tribal
SVar:DBExchange:DB$ ExchangeControl | Defined$ ParentTarget | ValidTgts$ Permanent.OppCtrl | TgtPrompt$ Select target permanent an opponent controls that shares a card type with it | TargetsWithSharedCardType$ ParentTarget
AI:RemoveDeck:All
AI:RemoveDeck:Random
SVar:Picture:http://www.wizards.com/global/images/magic/general/daring_thief.jpg
Oracle:Inspired — Whenever Daring Thief becomes untapped, you may exchange control of target nonland permanent you control and target permanent an opponent controls that shares a card type with it.

View File

@@ -2,9 +2,8 @@ Name:Gauntlets of Chaos
ManaCost:5
Types:Artifact
A:AB$ Pump | Cost$ 5 Sac<1/CARDNAME> | ValidTgts$ Artifact.YouCtrl,Creature.YouCtrl,Land.YouCtrl | TgtPrompt$ target artifact, creature, or land you control | StackDescription$ None | SubAbility$ DBExchange | SpellDescription$ Exchange control of target artifact, creature, or land you control and target permanent an opponent controls that shares one of those types with it. If those permanents are exchanged this way, destroy all Auras attached to them.
SVar:DBExchange:DB$ ExchangeControl | Defined$ ParentTarget | ValidTgts$ Permanent.OppCtrl | TgtPrompt$ Select target permanent an opponent controls that shares one of those types | TargetsWithSharedTypes$ Artifact,Creature,Land | RememberExchanged$ True | SubAbility$ DBDestroyAll
SVar:DBExchange:DB$ ExchangeControl | Defined$ ParentTarget | ValidTgts$ Permanent.OppCtrl | TgtPrompt$ Select target permanent an opponent controls that shares one of those types | TargetsWithSharedCardType$ ParentTarget | TargetsWithSharedTypes$ Artifact,Creature,Land | RememberExchanged$ True | SubAbility$ DBDestroyAll
SVar:DBDestroyAll:DB$ DestroyAll | ValidCards$ Aura.AttachedTo Card.IsRemembered | SubAbility$ DBCleanup
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
AI:RemoveDeck:All
SVar:Picture:http://www.wizards.com/global/images/magic/general/gauntlets_of_chaos.jpg
Oracle:{5}, Sacrifice Gauntlets of Chaos: Exchange control of target artifact, creature, or land you control and target permanent an opponent controls that shares one of those types with it. If those permanents are exchanged this way, destroy all Auras attached to them.

View File

@@ -5,12 +5,9 @@ PT:2/3
K:Deathtouch
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigDig | TriggerDescription$ When CARDNAME enters the battlefield, look at the top four cards of target opponent's library, exile one of them face down, then put the rest on the bottom of that library in a random order. For as long as that card remains exiled, you may look at it, you may cast it, and you may spend mana as though it were mana of any type to cast that spell.
SVar:TrigDig:DB$Dig | ValidTgts$ Opponent | DigNum$ 4 | ChangeNum$ 1 | DestinationZone$ Exile | DestinationZone2$ Library | LibraryPosition$ -1 | RestRandomOrder$ True | ExileFaceDown$ True | ChangeValid$ Card | RememberChanged$ True | SubAbility$ DBEffect | RememberChanged$ True
SVar:DBEffect:DB$ Effect | RememberObjects$ Remembered | StaticAbilities$ STPlay1,STPlay2 | Duration$ Permanent | Triggers$ TrigCleanup | SVars$ DBExileSelf | SubAbility$ DBCleanup
SVar:DBEffect:DB$ Effect | RememberObjects$ Remembered | StaticAbilities$ STPlay1,STPlay2 | Duration$ Permanent | ForgetOnMoved$ Exile | SubAbility$ DBCleanup
SVar:STPlay1:Mode$ Continuous | MayLookAt$ You | EffectZone$ Command | Affected$ Card.IsRemembered | AffectedZone$ Exile | Description$ You may look at the card, you may cast it, and you may spend mana as though it were mana of any type to cast that spell.
SVar:STPlay2:Mode$ Continuous | MayPlay$ True | MayPlayIgnoreType$ True | EffectZone$ Command | Affected$ Card.IsRemembered+nonLand | AffectedZone$ Exile | Secondary$ True | Description$ You may look at the card, you may cast it, and you may spend mana as though it were mana of any type to cast that spell.
SVar:TrigCleanup:Mode$ ChangesZone | ValidCard$ Card.IsRemembered | Origin$ Exile | Destination$ Any | TriggerZones$ Command | Execute$ DBExileSelf | Static$ True
SVar:DBExileSelf:DB$ ChangeZone | Defined$ Self | Origin$ Command | Destination$ Exile
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
SVar:PlayMain1:TRUE
SVar:Picture:http://www.wizards.com/global/images/magic/general/gonti_lord_of_luxury.jpg
Oracle:Deathtouch\nWhen Gonti, Lord of Luxury enters the battlefield, look at the top four cards of target opponent's library, exile one of them face down, then put the rest on the bottom of that library in a random order. You may look at and cast that card for as long as it remains exiled, and you may spend mana as though it were mana of any type to cast that spell.

View File

@@ -2,10 +2,8 @@ Name:Gustha's Scepter
ManaCost:0
Types:Artifact
A:AB$ ChangeZone | Cost$ T | ChangeType$ Card | ChangeNum$ 1 | Origin$ Hand | Destination$ Exile | ExileFaceDown$ True | RememberChanged$ True | Mandatory$ True | SubAbility$ DBEffect | SpellDescription$ Exile a card from your hand face down. You may look at it for as long as it remains exiled.
SVar:DBEffect:DB$ Effect | RememberObjects$ Remembered | StaticAbilities$ STLook | Duration$ Permanent | Triggers$ TrigCleanup | SVars$ DBExileSelf | SubAbility$ DBCleanup
SVar:DBEffect:DB$ Effect | RememberObjects$ Remembered | StaticAbilities$ STLook | Duration$ Permanent | ForgetOnMoved$ Exile | SubAbility$ DBCleanup
SVar:STLook:Mode$ Continuous | MayLookAt$ You | EffectZone$ Command | Affected$ Card.IsRemembered | AffectedZone$ Exile | Description$ You may look at it for as long as it remains exiled.
SVar:TrigCleanup:Mode$ ChangesZone | ValidCard$ Card.IsRemembered | Origin$ Exile | Destination$ Any | TriggerZones$ Command | Execute$ DBExileSelf | Static$ True
SVar:DBExileSelf:DB$ ChangeZone | Defined$ Self | Origin$ Command | Destination$ Exile
A:AB$ ChooseCard | Cost$ T | Defined$ You | Amount$ 1 | Mandatory$ True | AILogic$ AtLeast1 | ChoiceTitle$ Choose a card you own to put into your hand | Choices$ Card.IsRemembered+YouOwn+ExiledWithSource | ChoiceZone$ Exile | SubAbility$ MoveChosen | SpellDescription$ Return a card you own exiled with CARDNAME to your hand.
SVar:MoveChosen:DB$ ChangeZone | Origin$ Exile | Destination$ Hand | Defined$ ChosenCard
T:Mode$ ChangesZone | Origin$ Exile | Destination$ Any | Static$ True | ValidCard$ Card.IsRemembered+ExiledWithSource | Execute$ DBForget
@@ -15,5 +13,4 @@ T:Mode$ ChangesController | ValidCard$ Card.Self | TriggerZones$ Battlefield | E
SVar:DBChangeZoneAll:DB$ ChangeZoneAll | ChangeType$ Card.IsRemembered | Origin$ Exile | Destination$ Graveyard | SubAbility$ DBCleanup
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
AI:RemoveDeck:All
SVar:Picture:http://www.wizards.com/global/images/magic/general/gusthas_scepter.jpg
Oracle:{T}: Exile a card from your hand face down. You may look at it for as long as it remains exiled.\n{T}: Return a card you own exiled with Gustha's Scepter to your hand.\nWhen you lose control of Gustha's Scepter, put all cards exiled with Gustha's Scepter into their owner's graveyard.

View File

@@ -3,16 +3,15 @@ ManaCost:3 U
Types:Sorcery
A:SP$ ChooseCard | Cost$ 3 U | ValidTgts$ Player | Choices$ Creature.cmcEQY | TargetControls$ True | References$ Y | Mandatory$ True | AILogic$ WorstCard | RememberChosen$ True | SubAbility$ DBChooseCreatureYou | SpellDescription$ You and target player exchange control of the creature you each control with the highest converted mana cost. Then exchange control of artifacts the same way. If two or more permanents a player controls are tied for highest cost, their controller chooses one of them.
SVar:DBChooseCreatureYou:DB$ ChooseCard | Choices$ Creature.YouCtrl+cmcEQX | References$ X | Mandatory$ True | RememberChosen$ True | SubAbility$ DBExchangeCreature
SVar:DBExchangeCreature:DB$ ExchangeControl | BothDefined$ True | Defined$ Remembered | SubAbility$ DBCleanCreature
SVar:DBExchangeCreature:DB$ ExchangeControl | Defined$ Remembered | SubAbility$ DBCleanCreature
SVar:DBCleanCreature:DB$ Cleanup | ClearRemembered$ True | SubAbility$ DBChooseArtifactYou
SVar:DBChooseArtifactYou:DB$ ChooseCard | Choices$ Artifact.YouCtrl+cmcEQZ | References$ Z | Mandatory$ True | RememberChosen$ True | SubAbility$ DBChooseArtifactOpp
SVar:DBChooseArtifactOpp:DB$ ChooseCard | Defined$ ParentTarget | Choices$ Artifact.cmcEQW | TargetControls$ True | References$ W | Mandatory$ True | AILogic$ WorstCard | RememberChosen$ True | SubAbility$ DBExchangeArtifact
SVar:DBExchangeArtifact:DB$ ExchangeControl | BothDefined$ True | Defined$ Remembered | SubAbility$ DBCleanup
SVar:DBExchangeArtifact:DB$ ExchangeControl | Defined$ Remembered | SubAbility$ DBCleanup
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
SVar:X:Count$HighestCMC_Creature.YouCtrl+inZoneBattlefield
SVar:Y:Count$HighestCMC_Creature.TargetedPlayerCtrl+inZoneBattlefield
SVar:Z:Count$HighestCMC_Artifact.YouCtrl+inZoneBattlefield
SVar:W:Count$HighestCMC_Artifact.TargetedPlayerCtrl+inZoneBattlefield
AI:RemoveDeck:All
SVar:Picture:http://www.wizards.com/global/images/magic/general/juxtapose.jpg
Oracle:You and target player exchange control of the creature you each control with the highest converted mana cost. Then exchange control of artifacts the same way. If two or more permanents a player controls are tied for highest cost, their controller chooses one of them.

View File

@@ -5,7 +5,7 @@ HandLifeModifier:-1/+8
T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | TriggerZones$ Command | Execute$ TrigExchangeChoose | TriggerDescription$ At the beginning of your upkeep, exchange control of a permanent you control chosen at random and a permanent target opponent controls chosen at random.
SVar:TrigExchangeChoose:DB$ ChooseCard | ValidTgts$ Opponent | Choices$ Permanent.TargetedPlayerCtrl | AtRandom$ True | Amount$ 1 | RememberChosen$ True | SubAbility$ ChooseYou
SVar:ChooseYou:DB$ ChooseCard | Choices$ Permanent.YouCtrl | Amount$ 1 | AtRandom$ True | RememberChosen$ True | SubAbility$ DBExchange
SVar:DBExchange:DB$ ExchangeControl | Defined$ Remembered | BothDefined$ True | SubAbility$ DBCleanup
SVar:DBExchange:DB$ ExchangeControl | Defined$ Remembered | SubAbility$ DBCleanup
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
SVar:Picture:https://downloads.cardforge.org/images/cards/VAN/Karona, False God Avatar.full.jpg
Oracle:Hand -1, life +8\nAt the beginning of your upkeep, exchange control of a permanent you control chosen at random and a permanent target opponent controls chosen at random.

View File

@@ -5,10 +5,8 @@ PT:3/3
K:Morph:4 U U
T:Mode$ TurnFaceUp | ValidCard$ Card.Self | Execute$ TrigCounter | TriggerZones$ Battlefield | TriggerDescription$ When CARDNAME is turned face up, counter target spell. If that spell is countered this way, exile it instead of putting it into its owner's graveyard. You may cast that card without paying its mana cost as long as it remains exiled.
SVar:TrigCounter:DB$ Counter | TargetType$ Spell | TgtPrompt$ Select target spell | ValidTgts$ Card | RememberCountered$ True | ForgetOtherTargets$ True | Destination$ Exile | SubAbility$ DBEffect
SVar:DBEffect:DB$ Effect | RememberObjects$ Remembered | StaticAbilities$ STPlay | Duration$ Permanent | Triggers$ TrigCleanup | SVars$ DBCleanup | References$ PlayOpp,PlayYou,TrigCleanup,DBCleanup
SVar:DBEffect:DB$ Effect | RememberObjects$ Remembered | StaticAbilities$ STPlay | Duration$ Permanent | ForgetOnMoved$ Exile | SubAbility$ DBCleanup
SVar:STPlay:Mode$ Continuous | MayPlay$ True | MayPlayWithoutManaCost$ True | EffectZone$ Command | Affected$ Card.IsRemembered | AffectedZone$ Exile | Description$ You may cast cards without paying their mana cost as long as they remain exiled.
SVar:TrigCleanup:Mode$ ChangesZone | ValidCard$ Card.IsRemembered | Origin$ Exile | Destination$ Any | TriggerZones$ Command | Execute$ DBCleanup | Static$ True
SVar:DBCleanup:DB$ ChangeZone | Defined$ Self | Origin$ Command | Destination$ Exile
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
AI:RemoveDeck:All
SVar:Picture:http://www.wizards.com/global/images/magic/general/kheru_spellsnatcher.jpg
Oracle:Morph {4}{U}{U} (You may cast this card face down as a 2/2 creature for {3}. Turn it face up any time for its morph cost.)\nWhen Kheru Spellsnatcher is turned face up, counter target spell. If that spell is countered this way, exile it instead of putting it into its owner's graveyard. You may cast that card without paying its mana cost for as long as it remains exiled.

View File

@@ -4,10 +4,8 @@ Types:Creature Faerie Rogue
PT:1/4
K:Flying
A:AB$ Dig | Cost$ 1 U Q | ValidTgts$ Opponent | TgtPrompt$ Select target opponent | DigNum$ 1 | ChangeNum$ All | DestinationZone$ Exile | RememberChanged$ True | SubAbility$ DBEffect | SpellDescription$ Target opponent exiles the top card of their library. Until end of turn, you may play that card.
SVar:DBEffect:DB$ Effect | Duration$ EndOfTurn | RememberObjects$ Remembered | StaticAbilities$ STPlay | Triggers$ TrigCleanup | SVars$ DBExileSelf | SubAbility$ DBCleanup
SVar:DBEffect:DB$ Effect | Duration$ EndOfTurn | RememberObjects$ Remembered | StaticAbilities$ STPlay | ForgetOnMoved$ Exile | SubAbility$ DBCleanup
SVar:STPlay:Mode$ Continuous | MayPlay$ True | EffectZone$ Command | Affected$ Card.IsRemembered | AffectedZone$ Exile | Description$ You may play a card this turn.
SVar:TrigCleanup:Mode$ ChangesZone | ValidCard$ Card.IsRemembered | Origin$ Exile | Destination$ Any | TriggerZones$ Command | Execute$ DBExileSelf | Static$ True
SVar:DBExileSelf:DB$ ChangeZone | Defined$ Self | Origin$ Command | Destination$ Exile
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
AI:RemoveDeck:All
Oracle:Flying\n{1}{U}, {Q}: Target opponent exiles the top card of their library. Until end of turn, you may play that card. ({Q} is the untap symbol.)

View File

@@ -2,7 +2,7 @@ Name:Legerdemain
ManaCost:2 U U
Types:Sorcery
A:SP$ Pump | Cost$ 2 U U | ValidTgts$ Artifact,Creature | TgtPrompt$ target artifact or creature | StackDescription$ None | SubAbility$ DBExchange | SpellDescription$ Exchange control of target artifact or creature and another target permanent that shares one of those types with it. (This effect lasts indefinitely.)
SVar:DBExchange:DB$ ExchangeControl | Defined$ ParentTarget | ValidTgts$ Permanent | TgtPrompt$ Select target permanent that shares one of those types | TargetsWithSharedTypes$ Artifact,Creature | TargetUnique$ True
SVar:DBExchange:DB$ ExchangeControl | Defined$ ParentTarget | ValidTgts$ Permanent | TgtPrompt$ Select target permanent that shares one of those types | TargetsWithSharedCardType$ ParentTarget | TargetsWithSharedTypes$ Artifact,Creature | TargetUnique$ True
AI:RemoveDeck:All
SVar:Picture:http://www.wizards.com/global/images/magic/general/legerdemain.jpg
Oracle:Exchange control of target artifact or creature and another target permanent that shares one of those types with it. (This effect lasts indefinitely.)

View File

@@ -2,10 +2,8 @@ Name:Ornate Kanzashi
ManaCost:5
Types:Artifact
A:AB$ Dig | Cost$ 2 T | ValidTgts$ Opponent | TgtPrompt$ Select target opponent | DigNum$ 1 | ChangeNum$ All | DestinationZone$ Exile | RememberChanged$ True | SubAbility$ DBEffect | SpellDescription$ Target opponent exiles the top card of their library. You may play that card this turn.
SVar:DBEffect:DB$ Effect | Duration$ EndOfTurn | RememberObjects$ Remembered | StaticAbilities$ STPlay | Triggers$ TrigCleanup | SVars$ DBExileSelf | SubAbility$ DBCleanup
SVar:DBEffect:DB$ Effect | Duration$ EndOfTurn | RememberObjects$ Remembered | StaticAbilities$ STPlay | ForgetOnMoved$ Exile | SubAbility$ DBCleanup
SVar:STPlay:Mode$ Continuous | MayPlay$ True | EffectZone$ Command | Affected$ Card.IsRemembered | AffectedZone$ Exile | Description$ You may play a card this turn.
SVar:TrigCleanup:Mode$ ChangesZone | ValidCard$ Card.IsRemembered | Origin$ Exile | Destination$ Any | TriggerZones$ Command | Execute$ DBExileSelf | Static$ True
SVar:DBExileSelf:DB$ ChangeZone | Defined$ Self | Origin$ Command | Destination$ Exile
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
AI:RemoveDeck:All
Oracle:{2}, {T}: Target opponent exiles the top card of their library. You may play that card this turn.

View File

@@ -2,11 +2,8 @@ Name:Praetor's Grasp
ManaCost:1 B B
Types:Sorcery
A:SP$ ChangeZone | Cost$ 1 B B | Origin$ Library | Destination$ Exile | ExileFaceDown$ True | ValidTgts$ Opponent | ChangeType$ Card | ChangeNum$ 1 | IsCurse$ True | RememberChanged$ True | SubAbility$ DBEffect | StackDescription$ SpellDescription | SpellDescription$ Search target opponent's library for a card and exile it face down. Then that player shuffles their library. You may look at and play that card for as long as it remains exiled.
SVar:DBEffect:DB$ Effect | RememberObjects$ Remembered | StaticAbilities$ STPlay | Duration$ Permanent | Triggers$ TrigCleanup | SVars$ DBExileSelf | SubAbility$ DBCleanup
SVar:DBEffect:DB$ Effect | RememberObjects$ Remembered | StaticAbilities$ STPlay | Duration$ Permanent | ForgetOnMoved$ Exile | SubAbility$ DBCleanup
SVar:STPlay:Mode$ Continuous | MayLookAt$ You | MayPlay$ True | EffectZone$ Command | Affected$ Card.IsRemembered | AffectedZone$ Exile | Description$ You may look at and play a card as long as it remains exiled.
SVar:TrigCleanup:Mode$ ChangesZone | ValidCard$ Card.IsRemembered | Origin$ Exile | Destination$ Any | TriggerZones$ Command | Execute$ DBExileSelf | Static$ True
SVar:DBExileSelf:DB$ ChangeZone | Defined$ Self | Origin$ Command | Destination$ Exile
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
AI:RemoveDeck:All
SVar:Picture:http://www.wizards.com/global/images/magic/general/praetors_grasp.jpg
Oracle:Search target opponent's library for a card and exile it face down. Then that player shuffles their library. You may look at and play that card for as long as it remains exiled.

View File

@@ -2,11 +2,8 @@ Name:Release to the Wind
ManaCost:2 U
Types:Instant
A:SP$ ChangeZone | Cost$ 2 U | ValidTgts$ Permanent.nonLand | TgtPrompt$ Select target nonland permanent | Origin$ Battlefield | SubAbility$ DBEffect | Destination$ Exile | SpellDescription$ Exile target nonland permanent. For as long as that card remains exiled, its owner may cast it without paying its mana cost.
SVar:DBEffect:DB$ Effect | RememberObjects$ ParentTarget | EffectOwner$ TargetedOwner | StaticAbilities$ STPlay1,STPlay2 | Duration$ Permanent | Triggers$ TrigCleanup | SVars$ DBExileSelf | SubAbility$ DBCleanup
SVar:DBEffect:DB$ Effect | RememberObjects$ ParentTarget | EffectOwner$ TargetedOwner | StaticAbilities$ STPlay1,STPlay2 | Duration$ Permanent | ForgetOnMoved$ Exile | SubAbility$ DBCleanup
SVar:STPlay1:Mode$ Continuous | MayLookAt$ You | EffectZone$ Command | Affected$ Card.IsRemembered | AffectedZone$ Exile | Description$ For as long as that card remains exiled, its owner may cast it without paying its mana cost.
SVar:STPlay2:Mode$ Continuous | MayPlay$ True | MayPlayWithoutManaCost$ True | EffectZone$ Command | Affected$ Card.IsRemembered | AffectedZone$ Exile | Secondary$ True
SVar:TrigCleanup:Mode$ ChangesZone | ValidCard$ Card.IsRemembered | Origin$ Exile | Destination$ Any | TriggerZones$ Command | Execute$ DBExileSelf | Static$ True
SVar:DBExileSelf:DB$ ChangeZone | Defined$ Self | Origin$ Command | Destination$ Exile
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
SVar:Picture:http://www.wizards.com/global/images/magic/general/release_to_the_wind.jpg
Oracle:Exile target nonland permanent. For as long as that card remains exiled, its owner may cast it without paying its mana cost.

View File

@@ -1,8 +1,7 @@
Name:Role Reversal
ManaCost:U U R
Types:Sorcery
A:SP$ Pump | Cost$ U U R | ValidTgts$ Permanent | TgtPrompt$ Select target permanent | SubAbility$ DBExchange | StackDescription$ None | SpellDescription$ Exchange control of two target permanents that share a permanent type.
SVar:DBExchange:DB$ ExchangeControl | Defined$ ParentTarget | ValidTgts$ Permanent | TgtPrompt$ Select target permanent shares a card type with it | TargetsWithSharedTypes$ Creature,Artifact,Enchantment,Planeswalker,Land | TargetUnique$ True
A:SP$ ExchangeControl | Cost$ U U R | TargetMin$ 2 | TargetMax$ 2 | ValidTgts$ Permanent | TgtPrompt$ Select target permanents that share a permanent type | TargetsWithSameCardType$ True | SpellDescription$ Exchange control of two target permanents that share a permanent type.
AI:RemoveDeck:All
AI:RemoveDeck:Random
Oracle:Exchange control of two target permanents that share a permanent type.

View File

@@ -0,0 +1,10 @@
Name:Shahrazad
ManaCost:W W
Types:Sorcery
A:SP$ Subgame | RememberPlayers$ NotWin | SubAbility$ DBRepeatEachPlayer | SpellDescription$ Players play a Magic subgame, using their libraries as their decks. Each player who doesn't win the subgame loses half their life, rounded up. | StackDescription$ SpellDescription
SVar:DBRepeatEachPlayer:DB$ RepeatEach | RepeatPlayers$ Remembered | ClearRememberedBeforeLoop$ True | RepeatSubAbility$ DBLoseLife | SpellDescription$ Each player who doesn't win the subgame loses half their life, rounded up. | StackDescription$ SpellDescription
SVar:DBLoseLife:DB$ LoseLife | LifeAmount$ X | References$ X | Defined$ Player.IsRemembered
SVar:X:PlayerCountRemembered$LifeTotal/HalfUp
AI:RemoveDeck:All
AI:RemoveDeck:Random
Oracle:Players play a Magic subgame, using their libraries as their decks. Each player who doesn't win the subgame loses half their life, rounded up.

View File

@@ -5,13 +5,11 @@ Text:If a player would draw a card, that player exiles the top card of an oppone
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigEffects | Static$ True
#Create an effect for each player. The effect contains both Shared Fate's abilities.
SVar:TrigEffects:DB$ RepeatEach | RepeatPlayers$ Player | RepeatSubAbility$ DBEffect
SVar:DBEffect:DB$ Effect | EffectOwner$ Remembered | StaticAbilities$ STPlay | Triggers$ TrigCleanup | ReplacementEffects$ RDraw | SVars$ DBChooseOpp,DBExile,DBCleanup | Duration$ UntilHostLeavesPlay
SVar:DBEffect:DB$ Effect | EffectOwner$ Remembered | StaticAbilities$ STPlay | ReplacementEffects$ RDraw | SVars$ DBChooseOpp,DBExile | Duration$ UntilHostLeavesPlay | ForgetOnMoved$ Exile
SVar:RDraw:Event$ Draw | ActiveZones$ Command | ValidPlayer$ You | ReplaceWith$ DBChooseOpp | Description$ If you would draw a card, exile the top card of an opponent's library face down instead.
SVar:DBChooseOpp:DB$ ChoosePlayer | ChoiceTitle$ Choose an opponent whose top library card to exile | Choices$ Player.Opponent | AILogic$ Curse | SubAbility$ DBExile
SVar:DBExile:DB$ Dig | DigNum$ 1 | ChangeNum$ All | DestinationZone$ Exile | ExileFaceDown$ True | Defined$ Player.Chosen | RememberChanged$ True
SVar:STPlay:Mode$ Continuous | MayLookAt$ You | MayPlay$ True | EffectZone$ Command | Affected$ Card.IsRemembered | AffectedZone$ Exile | Description$ You may look at and play cards exiled with Shared Fate.
SVar:TrigCleanup:Mode$ ChangesZone | ValidCard$ Card.IsRemembered | Origin$ Exile | Destination$ Any | TriggerZones$ Command | Execute$ DBCleanup | Static$ True
SVar:DBCleanup:DB$ Cleanup | ForgetDefined$ TriggeredCard
AI:RemoveDeck:All
AI:RemoveDeck:Random
Oracle:If a player would draw a card, that player exiles the top card of an opponent's library face down instead.\nEach player may look at and play cards they exiled with Shared Fate.

View File

@@ -1,9 +1,7 @@
Name:Shifting Loyalties
ManaCost:5 U
Types:Sorcery
A:SP$ Pump | Cost$ 5 U | ValidTgts$ Permanent | TgtPrompt$ Select target permanent | SubAbility$ DBExchange | StackDescription$ None | SpellDescription$ Exchange control of two target permanents that share a card type.
SVar:DBExchange:DB$ ExchangeControl | Defined$ ParentTarget | ValidTgts$ Permanent | TgtPrompt$ Select target permanent shares a card type with it | TargetsWithSharedTypes$ Creature,Artifact,Enchantment,Planeswalker,Land,Tribal | TargetUnique$ True
A:SP$ ExchangeControl | Cost$ 5 U | TargetMin$ 2 | TargetMax$ 2 | ValidTgts$ Permanent | TgtPrompt$ Select target permanents that share a permanent type | TargetsWithSameCardType$ True | SpellDescription$ Exchange control of two target permanents that share a card type.
AI:RemoveDeck:All
AI:RemoveDeck:Random
SVar:Picture:http://www.wizards.com/global/images/magic/general/shifting_loyalties.jpg
Oracle:Exchange control of two target permanents that share a card type. (Artifact, creature, enchantment, land, and planeswalker are card types.)

View File

@@ -2,9 +2,7 @@ Name:Spelljack
ManaCost:3 U U U
Types:Instant
A:SP$ Counter | Cost$ 3 U U U | TargetType$ Spell | TgtPrompt$ Select target spell | ValidTgts$ Card | RememberCountered$ True | ForgetOtherTargets$ True | Destination$ Exile | SubAbility$ DBEffect | SpellDescription$ Counter target spell. If that spell is countered this way, exile it instead of putting it into its owner's graveyard. You may play it without paying its mana cost for as long as it remains exiled. (If it has X in its mana cost, X is 0.)
SVar:DBEffect:DB$ Effect | Name$ Spelljack Effect | RememberObjects$ Remembered | StaticAbilities$ Play | Duration$ Permanent | Triggers$ TrigCleanup | SVars$ DBCleanup | References$ Play,TrigCleanup,DBCleanup
SVar:DBEffect:DB$ Effect | Name$ Spelljack Effect | RememberObjects$ Remembered | StaticAbilities$ Play | Duration$ Permanent | ForgetOnMoved$ Exile | SubAbility$ DBCleanup
SVar:Play:Mode$ Continuous | MayPlay$ True | MayPlayWithoutManaCost$ True | EffectZone$ Command | Affected$ Card.IsRemembered | AffectedZone$ Exile | Description$ You may play cards exiled with Spelljack.
SVar:TrigCleanup:Mode$ ChangesZone | ValidCard$ Card.IsRemembered | Origin$ Exile | Destination$ Any | TriggerZones$ Command | Execute$ DBCleanup | Static$ True
SVar:DBCleanup:DB$ ChangeZone | Defined$ Self | Origin$ Command | Destination$ Exile
SVar:Picture:http://www.wizards.com/global/images/magic/general/spelljack.jpg
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
Oracle:Counter target spell. If that spell is countered this way, exile it instead of putting it into its owner's graveyard. You may play it without paying its mana cost for as long as it remains exiled. (If it has X in its mana cost, X is 0.)

View File

@@ -0,0 +1,9 @@
Name:Alrund's Epiphany
ManaCost:5 U U
Types:Sorcery
A:SP$ Token | Cost$ 5 U U | LegacyImage$ u 1 1 bird flying khm | TokenAmount$ 2 | TokenScript$ u_1_1_bird_flying | TokenOwner$ You | SubAbility$ DBAddTurn | SpellDescription$ Create two 1/1 blue Bird creature tokens with flying. Take an extra turn after this one. Exile CARDNAME.
SVar:DBAddTurn: DB$ AddTurn | Defined$ You | NumTurns$ 1 | SubAbility$ DBChange | StackDescription$ None
SVar:DBChange:DB$ ChangeZone | Origin$ Stack | Destination$ Exile | StackDescription$ None
K:Foretell:4 U U
DeckHas:Ability$Token
Oracle:Create two 1/1 blue Bird creature tokens with flying. Take an extra turn after this one. Exile Alrund's Epiphany.\nForetell {4}{U}{U} (During your turn, you may pay {2} and exile this card from your hand face down. Cast it on a later turn for its foretell cost.)

View File

@@ -0,0 +1,11 @@
Name:Ascent of the Worthy
ManaCost:1 W B
Types:Enchantment Saga
K:Saga:3:DBChoose,DBChoose,DBChangeZone
SVar:DBChoose:DB$ ChooseCard | Choices$ Creature.YouCtrl | SubAbility$ DBEffect | SpellDescription$ Choose a creature you control. Until your next turn, all damage that would be dealt to creatures you control is dealt to that creature instead.
SVar:DBEffect:DB$ Effect | ReplacementEffects$ DamageEvent | SVars$ GideonSac | References$ DamageEvent,GideonSac | ExileOnMoved$ True | RememberObjects$ ChosenCard | Duration$ UntilYourNextTurn
SVar:DamageEvent:Event$ DamageDone | ActiveZones$ Command | ValidTarget$ Creature.YouCtrl | ReplaceWith$ GideonSac | DamageTarget$ Remembered | Description$ All damage that would be dealt this turn to creatures you control is dealt to the chosen creature instead (if it's still on the battlefield).
SVar:DBChangeZone:DB$ ChangeZone | Origin$ Graveyard | Destination$ Battlefield | TgtPrompt$ Choose target creature card in your graveyard | ValidTgts$ Creature.YouOwn | WithCounters$ Flying_1 | AnimateSubAbility$ Animate | SpellDescription$ Return target creature card from your graveyard to the battlefield with a flying counter on it.
SVar:GideonSac:DB$ ReplaceEffect | VarName$ Affected | VarValue$ Remembered | VarType$ Card
SVar:Animate:DB$Animate | Defined$ Remembered | Types$ Angel,Warrior | Permanent$ True
Oracle:(As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.)\nI, II — Choose a creature you control. Until your next turn, all damage that would be dealt to creatures you control is dealt to that creature instead.\nIII — Return target creature card from your graveyard to the battlefield with a flying counter on it. That creature is an Angel Warrior in addition to its other types.

View File

@@ -0,0 +1,7 @@
Name:Augury Raven
ManaCost:3 U
Types:Creature Bird
PT:3/3
K:Flying
K:Foretell:1 U
Oracle:Flying\nForetell {1}{U} (During your turn, you may pay {2} and exile this card from your hand face down. Cast it on a later turn for its foretell cost.)

View File

@@ -0,0 +1,10 @@
Name:Battle for Bretagard
ManaCost:1 G W
Types:Enchantment Saga
K:Saga:3:TrigToken1,TrigToken2,DBCopy
SVar:TrigToken1:DB$ Token | TokenAmount$ 1 | TokenScript$ w_1_1_human_warrior | TokenOwner$ You | SpellDescription$ Create a 1/1 white Human Warrior creature token.
SVar:TrigToken2:DB$ Token | TokenAmount$ 1 | TokenScript$ g_1_1_elf_warrior | TokenOwner$ You | SpellDescription$ Create a 1/1 green Elf Warrior creature token.
SVar:DBCopy:DB$ CopyPermanent | Choices$ Artifact.token+YouCtrl,Creature.token+YouCtrl | WithDifferentNames$ True | SpellDescription$ Choose any number of artifact tokens and/or creature tokens you control with different names. For each of them, create a token thats a copy of it.
DeckHas:Ability$Token
Oracle:(As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.)\nI — Create a 1/1 white Human Warrior creature token.\nII — Create a 1/1 green Elf Warrior creature token.\nIII — Choose any number of artifact tokens and/or creature tokens you control with different names. For each of them, create a token thats a copy of it.

View File

@@ -0,0 +1,9 @@
Name:Battle Mammoth
ManaCost:3 G G
Types:Creature Elephant
PT:6/5
K:Trample
T:Mode$ BecomesTarget | ValidTarget$ Permanent.YouCtrl+inZoneBattlefield | ValidSource$ Card.OppCtrl | TriggerZones$ Battlefield | Execute$ TrigDraw | OptionalDecider$ You | TriggerDescription$ Whenever a permanent you control becomes the target of a spell or ability an opponent controls, you may draw a card.
SVar:TrigDraw:DB$Draw | NumCards$ 1 | SpellDescription$ Draw a card.
K:Foretell:2 G G
Oracle:Trample\nWhenever a permanent you control becomes the target of a spell or ability an opponent controls, you may draw a card.\nForetell {2}{G}{G} (During your turn, you may pay {2} and exile this card from your hand face down. Cast it on a later turn for its foretell cost.)

View File

@@ -0,0 +1,12 @@
Name:Battle of Frost and Fire
ManaCost:3 U R
Types:Enchantment Saga
K:Saga:3:DBDamageAll,DBScry,DBEffect
SVar:DBDamageAll:DB$ DamageAll | NumDmg$ 4 | ValidCards$ Creature.nonGiant,Planeswalker | ValidDescription$ each non-Giant creature and each planeswalker. | SpellDescription$ CARDNAME deals 4 damage to each non-Giant creature and each planeswalker.
SVar:DBScry:DB$ Scry | ScryNum$ 3 | SpellDescription$ Scry 3.
SVar:DBEffect:DB$ Effect | Triggers$ CastSpell | SpellDescription$ Whenever you cast a spell with converted mana cost 5 or greater this turn, draw two cards, then discard a card.
SVar:CastSpell:Mode$ SpellCast | ValidCard$ Card.cmcGE5 | ValidActivatingPlayer$ You | TriggerZones$ Command | Execute$ DBDraw | TriggerDescription$ Whenever you cast a spell with converted mana cost 5 or greater this turn, draw two cards, then discard a card.
SVar:DBDraw:DB$ Draw | Defined$ You | NumCards$ 2 | SubAbility$ DBDiscard
SVar:DBDiscard:DB$ Discard | Defined$ You | NumCards$ 1 | Mode$ TgtChoose
DeckHints:Type$Giant
Oracle:(As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.)\nI — Battle of Frost and Fire deals 4 damage to each non-Giant creature and each planeswalker.\nII — Scry 3.\nIII — Whenever you cast a spell with converted mana cost 5 or greater this turn, draw two cards, then discard a card.

View File

@@ -0,0 +1,7 @@
Name:Behold the Multiverse
ManaCost:3 U
Types:Instant
A:SP$ Scry | Cost$ 3 U | ScryNum$ 2 | SubAbility$ DBDraw | AILogic$ BestOpportunity | SpellDescription$ Scry 2, then draw two cards.
SVar:DBDraw:DB$Draw | NumCards$ 2
K:Foretell:1 U
Oracle:Scry 2, then draw two cards.\nForetell {1}{U} (During your turn, you may pay {2} and exile this card from your hand face down. Cast it on a later turn for its foretell cost.)

View File

@@ -0,0 +1,11 @@
Name:Bloodline Pretender
ManaCost:3
Types:Artifact Creature Shapeshifter
PT:2/2
K:Changeling
K:ETBReplacement:Other:ChooseCT
SVar:ChooseCT:DB$ ChooseType | Defined$ You | Type$ Creature | AILogic$ MostProminentInComputerDeck | SpellDescription$ As CARDNAME enters the battlefield, choose a creature type.
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Creature.Other+ChosenType+YouCtrl | TriggerZones$ Battlefield | Execute$ TrigPutCounter | TriggerDescription$ Whenever another creature of the chosen type enters the battlefield under your control, put a +1/+1 counter on CARDNAME.
SVar:TrigPutCounter:DB$PutCounter | CounterType$ P1P1 | CounterNum$ 1
DeckHas:Ability$Counters
Oracle:Changeling\nAs Bloodline Pretender enters the battlefield, choose a creature type.\nWhenever another creature of the chosen type enters the battlefield under your control, put a +1/+1 counter on Bloodline Pretender.

View File

@@ -0,0 +1,11 @@
Name:Cosmos Charger
ManaCost:3 U
Types:Creature Horse Spirit
PT:3/3
K:Flash
K:Flying
S:Mode$ ReduceCost | ValidSpell$ Static.Foretelling | Activator$ You | Amount$ 1 | Description$ Foretelling cards from your hand costs {1} less and can be done on any players turn.
S:Mode$ Continuous | Affected$ You | AddKeyword$ Foretell on any players turn | Secondary$ True | Description$ Foretelling cards from your hand on any players turn.
K:Foretell:2 U
Oracle:Flash\nFlying\nForetelling cards from your hand costs {1} less and can be done on any players turn.\nForetell {2}{U} (During your turn, you may pay {2} and exile this card from your hand face down. Cast it on a later turn for its foretell cost.)

View File

@@ -0,0 +1,7 @@
Name:Crush the Weak
ManaCost:2 R
Types:Sorcery
A:SP$ DamageAll | Cost$ 2 R | ValidCards$ Creature | NumDmg$ 2 | RememberDamaged$ True | ReplaceDyingDefined$ Remembered | SubAbility$ DBCleanup | SpellDescription$ CARDNAME deals 2 damage to each creature. If a creature dealt damage this way would die this turn, exile it instead. | StackDescription$ SpellDescription
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
K:Foretell:R
Oracle:Crush the Weak deals 2 damage to each creature. If a creature dealt damage this way would die this turn, exile it instead.\nForetell {R} (During your turn, you may pay {2} and exile this card from your hand face down. Cast it on a later turn for its foretell cost.)

View File

@@ -0,0 +1,6 @@
Name:Demon Bolt
ManaCost:2 R
Types:Instant
A:SP$ DealDamage | Cost$ 2 R | ValidTgts$ Creature,Planeswalker | TgtPrompt$ Select target creature or planeswalker. | NumDmg$ 4 | SpellDescription$ CARDNAME deals 4 damage to target creature or planeswalker.
K:Foretell:R
Oracle:Demon Bolt deals 4 damage to target creature or planeswalker.\nForetell {R} (During your turn, you may pay {2} and exile this card from your hand face down. Cast it on a later turn for its foretell cost.)

View File

@@ -0,0 +1,6 @@
Name:Depart the Realm
ManaCost:1 U
Types:Instant
A:SP$ ChangeZone | Cost$ 1 U | ValidTgts$ Permanent.nonLand | TgtPrompt$ Select target nonland permanent | Origin$ Battlefield | Destination$ Hand | SpellDescription$ Return target nonland permanent to its owner's hand.
K:Foretell:U
Oracle:Return target nonland permanent to its owner's hand.\nForetell {U} (During your turn, you may pay {2} and exile this card from your hand face down. Cast it on a later turn for its foretell cost.)

View File

@@ -0,0 +1,6 @@
Name:Doomskar
ManaCost:3 W W
Types:Sorcery
A:SP$ DestroyAll | Cost$ 3 W W | ValidCards$ Creature | SpellDescription$ Destroy all creatures.
K:Foretell:1 W W
Oracle:Destroy all creatures.\nForetell {1}{W}{W} (During your turn, you may pay {2} and exile this card from your hand face down. Cast it on a later turn for its foretell cost.)

View File

@@ -0,0 +1,11 @@
Name:Doomskar Oracle
ManaCost:2 W
Types:Creature Human Cleric
PT:3/2
T:Mode$ SpellCast | ValidCard$ Card.YouCtrl | TriggerZones$ Battlefield | Execute$ TrigGainLife | CheckSVar$ YouCastThisTurn | SVarCompare$ EQ2 | NoResolvingCheck$ True | TriggerDescription$ Whenever you cast your second spell each turn, you gain 2 life.
SVar:TrigGainLife:DB$ GainLife | Defined$ You | LifeAmount$ 2
SVar:YouCastThisTurn:Count$ThisTurnCast_Card.YouCtrl
SVar:BuffedBy:Card
K:Foretell:W
DeckHas:Ability$LifeGain
Oracle:Whenever you cast your second spell each turn, you gain 2 life.\nForetell {W} (During your turn, you may pay {2} and exile this card from your hand face down. Cast it on a later turn for its foretell cost.)

View File

@@ -0,0 +1,9 @@
Name:Doomskar Titan
ManaCost:4 R R
Types:Creature Giant Berserker
PT:4/4
T:Mode$ ChangesZone | ValidCard$ Card.Self | Origin$ Any | Destination$ Battlefield | Execute$ TrigPumpAll | TriggerDescription$ When CARDNAME enters the battlefield, creatures you control get +1/0 and gain haste until end of turn.
SVar:TrigPumpAll:DB$ PumpAll | ValidCards$ Creature.YouCtrl | NumAtt$ 1 | KW$ Haste
SVar:PlayMain1:TRUE
K:Foretell:4 R
Oracle:When Doomskar Titan enters the battlefield, creatures you control get +1/+) and gain haste until end of turn.\nForetell {4}{R} (During your turn, you may pay {2} and exile this card from your hand face down. Cast it on a later turn for its foretell cost.)

View File

@@ -0,0 +1,8 @@
Name:Dream Devourer
ManaCost:1 B
Types:Creature Demon Cleric
PT:0/3
S:Mode$ Continuous | Affected$ Card.nonLand+YouOwn+withoutForetell | AffectedZone$ Hand | AddKeyword$ Foretell | Description$ Each nonland card in your hand without foretell has foretell. Its foretell cost is equal to its mana cost reduced by {2}. (During your turn, you may pay {2} and exile it from your hand face down. Cast it on a later turn for its foretell cost.)
T:Mode$ Foretell | ValidPlayer$ You | Execute$ TrigPump | TriggerZones$ Battlefield | TriggerDescription$ Whenever you foretell a card, CARDNAME gets +2/+0 until end of turn.
SVar:TrigPump:DB$ Pump | Defined$ Self | NumAtt$ 2
Oracle:Each nonland card in your hand without foretell has foretell. Its foretell cost is equal to its mana cost reduced by {2}. (During your turn, you may pay {2} and exile it from your hand face down. Cast it on a later turn for its foretell cost.)\n Whenever you foretell a card, Dream Devourer gets +2/+0 until end of turn.

View File

@@ -0,0 +1,8 @@
Name:Dual Strike
ManaCost:R R
Types:Instant
A:SP$ DelayedTrigger | Cost$ R R | AILogic$ SpellCopy | Execute$ EffTrigCopy | ThisTurn$ True | Mode$ SpellCast | ValidCard$ Instant.cmcLE4,Sorcery.cmcLE4 | ValidActivatingPlayer$ You | SpellDescription$ When you cast your next instant or sorcery spell with converted mana cost 4 or less this turn, copy that spell. You may choose new targets for the copy.
SVar:EffTrigCopy:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | MayChooseTarget$ True
SVar:AIPriorityModifier:9
K:Foretell:R
Oracle:When you cast your next instant or sorcery spell with converted mana cost 4 or less this turn, copy that spell. You may choose new targets for that copy.\nForetell {R} (During your turn, you may pay {2} and exile this card from your hand face down. Cast it on a later turn for its foretell cost.)

View File

@@ -0,0 +1,7 @@
Name:Dwarven Reinforcements
ManaCost:3 R
Types:Sorcery
A:SP$ Token | Cost$ 3 R | LegacyImage$ r 2 1 dwarf berserker khm | TokenAmount$ 2 | TokenScript$ r_2_1_dwarf_berserker | TokenOwner$ You | SpellDescription$ Create 2 2/1 red Dwarf Berserker creature tokens.
K:Foretell:1 R
DeckHas:Ability$Token
Oracle:Create 2 2/1 red Dwarf Berserker creature tokens.\nForetell {1}{R} (During your turn, you may pay {2} and exile this card from your hand face down. Cast it on a later turn for its foretell cost.)

View File

@@ -0,0 +1,11 @@
Name:Ethereal Valkyrie
ManaCost:4 U W
Types:Creature Spirit Angel
PT:4/4
K:Flying
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ DBDraw | TriggerDescription$ Whenever CARDNAME enters the battlefield or attacks, draw a card, then exile a card from your hand face down. It becomes foretold. Its foretell cost is its mana cost reduced by {2}. (On a later turn, you may cast it for its foretell cost, even if this creature has left the battlefield.)
T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ DBDraw | Secondary$ True | TriggerDescription$ Whenever CARDNAME enters the battlefield or attacks, draw a card, then exile a card from your hand face down. It becomes foretold. Its foretell cost is its mana cost reduced by {2}. (On a later turn, you may cast it for its foretell cost, even if this creature has left the battlefield.)
SVar:DBDraw:DB$ Draw | NumCards$ 1 | SubAbility$ DBExile
SVar:DBExile:DB$ ChangeZone | Origin$ Hand | Destination$ Exile | ChangeType$ Card | ChangeNum$ 1 | ExileFaceDown$ True | Mandatory$ True | Foretold$ True
Oracle:Whenever Ethereal Valkyrie enters the battlefield or attacks, draw a card, then exile a card from your hand face down. It becomes foretold. Its foretell cost is its mana cost reduced by {2}. (On a later turn, you may cast it for its foretell cost, even if this creature has left the battlefield.)

View File

@@ -0,0 +1,11 @@
Name:Fall of the Impostor
ManaCost:1 G W
Types:Enchantment Saga
K:Saga:3:DBPutCounter,DBPutCounter,DBExileGreatest
SVar:DBPutCounter:DB$ PutCounter | ValidTgts$ Creature | TgtPrompt$ Select target creature | CounterType$ P1P1 | CounterNum$ 1 | TargetMin$ 0 | TargetMax$ 1 | SpellDescription$ Put a +1/+1 counter on up to one target creature.
SVar:DBExileGreatest:DB$ Pump | ValidTgts$ Player.Opponent | RememberTargets$ True | SubAbility$ DBChooseExiled | SpellDescription$ Exile a creature with the greatest power among creatures target opponent controls.
SVar:DBChooseExiled:DB$ ChooseCard | Choices$ Creature.greatestPowerControlledByRemembered | MinAmount$ 1 | Amount$ 1 | Mandatory$ True | ChoiceZone$ Battlefield | SubAbility$ DBChangeZone
SVar:DBChangeZone:DB$ ChangeZone | Origin$ Battlefield | Destination$ Exile | Defined$ ChosenCard | SubAbility$ DBCleanup
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
DeckHas:Ability$Counters
Oracle:I - Put a +1/+1 counter on up to one target creature.\nII - Put a +1/+1 counter on up to one target creature.\nIII - Exile a creature with the greatest power among creatures target opponent controls.

View File

@@ -0,0 +1,8 @@
Name:Forging the Tyrite Sword
ManaCost:1 R W
Types:Enchantment Saga
K:Saga:3:DBToken,DBToken,DBChangeZone
SVar:DBToken:DB$ Token | TokenAmount$ 1 | TokenScript$ c_a_treasure_sac | TokenOwner$ You $ SpellDescription
SVar:DBChangeZone:DB$ ChangeZone | Origin$ Library | Destination$ Hand | ChangeType$ Card.namedHalvar; God of Battle,Equipment | ChangeNum$ 1 | SpellDescription$ Search your library for a card named Halvar, God of Battle or an Equipment card, reveal it, put it into your hand, then shuffle your library.
DeckHas:Ability$Token
Oracle:(As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.)\nI, II — Create a Treasure token.\nIII — Search your library for a card named Halvar, God of Battle or an Equipment card, reveal it, put it into your hand, then shuffle your library.

View File

@@ -0,0 +1,22 @@
Name:Glorious Protector
ManaCost:2 W W
Types:Creature Angel Cleric
PT:3/4
K:Flash
K:Flying
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigExile | TriggerDescription$ When CARDNAME enters the battlefield, you may exile any number of other non-Angel creatures you control until CARDNAME leaves the battlefield.
SVar:TrigExile:DB$ ChangeZone | Origin$ Battlefield | Destination$ Exile | RememberChanged$ True | Hidden$ True | ChangeType$ Creature.nonAngel+YouCtrl | ChangeNum$ MaxTgts | SelectPrompt$ Choose any number of non-Angel creatures you control | SubAbility$ DBEffect | References$ MaxTgts
SVar:DBEffect:DB$ Effect | Triggers$ ComeBack | RememberObjects$ RememberedCard | ImprintCards$ Self | SVars$ TrigReturn,ExileSelf | ConditionPresent$ Card.Self | Duration$ Permanent | ForgetOnMoved$ Exile
SVar:ComeBack:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Any | ValidCard$ Card.IsImprinted | Execute$ TrigReturn | TriggerZones$ Command | TriggerController$ TriggeredCardController | Static$ True | TriggerDescription$ That creature is exiled until EFFECTSOURCE leaves the battlefield
SVar:TrigReturn:DB$ ChangeZoneAll | Origin$ Exile | Destination$ Battlefield | ChangeType$ Card.IsRemembered | SubAbility$ ExileSelf
SVar:ExileSelf:DB$ ChangeZone | Origin$ Command | Destination$ Exile | Defined$ Self
#Triggers to forget remembered on this
T:Mode$ ChangesZone | ValidCard$ Card.IsRemembered | Origin$ Exile | Destination$ Any | TriggerZones$ Battlefield | Static$ True | Execute$ TrigForget
SVar:TrigForget:DB$ Pump | ForgetObjects$ TriggeredCard
T:Mode$ ChangesZone | ValidCard$ Card.Self | Origin$ Battlefield | Destination$ Any | Static$ True | Execute$ TrigForgetAll
SVar:TrigForgetAll:DB$ Cleanup | ClearRemembered$ True
SVar:X:Count$ValidExile Card.IsRemembered+ExiledWithSource/Times.2
SVar:MaxTgts:Count$Valid Creature.nonAngel+YouCtrl
AI:RemoveDeck:Random
K:Foretell:2 W
Oracle:Flash\nFlying\nWhen Glorious Protector enters the battlefield, you may exile any number of non-Angel creatures you control until Glorious Protector leaves the battlefield.\nForetell {2}{W} (During your turn, you may pay {2} and exile this card from your hand face down. Cast it on a later turn for its foretell cost.)

View File

@@ -0,0 +1,7 @@
Name:Gods' Hall Guardian
ManaCost:5 W
Types:Creature Cat
PT:3/6
K:Vigilance
K:Foretell:3 W
Oracle:Vigilance\nForetell {3}{W} (During your turn, you may pay {2} and exile this card from your hand face down. Cast it on a later turn for its foretell cost.)

View File

@@ -0,0 +1,9 @@
Name:Harald, King of Skemfar
ManaCost:1 B G
Types:Legendary Creature Elf Warrior
PT:3/2
K:Menace
T:Mode$ ChangesZone | ValidCard$ Card.Self | Origin$ Any | Destination$ Battlefield | Execute$ TrigDig | TriggerDescription$ When CARDNAME enters the battlefield, look at the top five cards of your library. You may reveal an Elf, Warrior, or Tyvar card from among them and put it into your hand. Put the rest on the bottom of your library in a random order.
SVar:TrigDig:DB$ Dig | DigNum$ 5 | ChangeNum$ 1 | Optional$ True | ForceRevealToController$ True | ChangeValid$ Elf,Warrior,Tyvar | RestRandomOrder$ True
DeckHints:Type$Elf|Tyvar
Oracle:Menace (This creature cant be blocked except by two or more creatures.)\nWhen Harald, King of Skemfar enters the battlefield, look at the top five cards of your library. You may reveal an Elf, Warrior, or Tyvar card from among them and put it into your hand. Put the rest on the bottom of your library in a random order.

View File

@@ -0,0 +1,13 @@
Name:Harald Unites the Elves
ManaCost:2 B G
Types:Enchantment Saga
K:Saga:3:DBMill,DBPutCounterAll,DBEffect
SVar:DBMill:DB$ Mill | NumCards$ 3 | Defined$ You | SubAbility$ DBChangeZone | SpellDescription$ Mill three cards. You may put an Elf card or Tyvar card from your graveyard onto the battlefield.
SVar:DBChangeZone:DB$ ChangeZone | Hidden$ True | ChangeType$ Elf.YouOwn,Tyvar.YouOwn | ChangeNum$ 1 | Origin$ Graveyard | Destination$ Battlefield
SVar:DBPutCounterAll:DB$ PutCounterAll | ValidCards$ Creature.Elf+YouCtrl | CounterType$ P1P1 | CounterNum$ 1 | SpellDescription$ Put a +1/+1 counter on each Elf you control.
SVar:DBEffect:DB$ Effect | Triggers$ TrigAttack | SpellDescription$ Whenever an Elf you control attacks this turn, target creature an opponent controls gets -1/-1 until end of turn.
SVar:TrigAttack:Mode$ Attacks | ValidCard$ Creature.Elf+YouCtrl | Execute$ TrigPump | TriggerZones$ Battlefield | TriggerDescription$ Whenever an Elf you control attacks this turn, target creature an opponent controls gets -1/-1 until end of turn.
SVar:TrigPump:DB$ Pump | ValidTgts$ Creature.OppCtrl | TgtPrompt$ Select target creature | NumAtt$ -1 | NumDef$ -1 | IsCurse$ True
DeckHints:Type$Elf|Tyvar
DeckHas:Ability$Counters
Oracle:(As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.)\nI - Mill three cards. You may put an Elf card or Tyvar card from your graveyard onto the battlefield.\nII - Put a +1/+1 counter on each Elf you control.\nIII - Whenever an Elf you control attacks this turn, target creature an opponent controls gets -1/-1 until end of turn.

View File

@@ -0,0 +1,12 @@
Name:Immersturm Predator
ManaCost:2 B R
Types:Creature Vampire Dragon
PT:3/3
K:Flying
T:Mode$ Taps | ValidCard$ Card.Self | Execute$ TrigExile | TriggerDescription$ Whenever CARDNAME becomes tapped, exile up to one target card from a graveyard and put a +1/+1 counter on CARDNAME.
SVar:TrigExile:DB$ Changezone | ValidTgts$ Card | TargetMin$ 0 | TargetMax$ 1 | Origin$ Graveyard | Destination$ Exile | TgtPrompt$ Choose target card in a graveyard | SubAbility$ DBPutCounter
SVar:DBPutCounter:DB$ PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ 1
A:AB$ Pump | Cost$ Sac<1/Creature.Other/another creature> | Defined$ Self | KW$ Indestructible | SubAbility$ DBTap | SpellDescription$ CARDNAME gains indestructible until end of turn. Tap it.
SVar:DBTap:DB$ Tap | Defined$ Self
DeckHas:Ability$Counters
Oracle:Flying\nWhenever Immersturm Predator becomes tapped, exile up to one target card from a graveyard and put a +1/+1 counter on Immersturm Predator.\nSacrifice another creature: Immersturm Predator gains indestructible until end of turn. Tap it.

View File

@@ -0,0 +1,14 @@
Name:Invasion of the Giants
ManaCost:U R
Types:Enchantment Saga
K:Saga:3:DBScry,DBDraw,DBEffect
SVar:DBScry:DB$ Scry | ScryNum$ 2 | SpellDescription$ Scry 2.
SVar:DBDraw:DB$ Draw | NumCards$ 1 | SubAbility$ DBReveal | SpellDescription$ Draw a card. Then you may reveal a Giant card from your hand. When you do, CARDNAME deals 2 damage to target opponent or planeswalker.
SVar:DBReveal:DB$ ImmediateTrigger | Execute$ TrigDealDamage | UnlessCost$ Reveal<1/Giant> | UnlessPayer$ You | UnlessSwitched$ True | SpellDescription$ You may reveal a Giant card from your hand. When you do, CARDNAME deals 2 damage to target opponent or planeswalker.
SVar:TrigDealDamage:DB$ DealDamage | ValidTgts$ Player.Opponent,Planeswalker | TgtPrompt$ Select target opponent or planeswalker. | NumDmg$ 2
SVar:DBEffect:DB$ Effect | StaticAbilities$ ReduceCost | Triggers$ TrigCastSpell | SVars$ RemoveEffect| SpellDescription$ The next Giant spell you cast this turn costs {2} less to cast.
SVar:ReduceCost:Mode$ ReduceCost | EffectZone$ Command | Type$ Spell | ValidCard$ Giant | Activator$ You | Amount$ 2
SVar:TrigCastSpell:Mode$ SpellCast | ValidCard$ Giant | ValidActivatingPlayer$ You | TriggerZones$ Command | Execute$ RemoveEffect | Static$ True
SVar:RemoveEffect:DB$ ChangeZone | Origin$ Command | Destination$ Exile
DeckHints:Type$Giant
Oracle:(As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.)\nI - Scry 2.\nII - Draw a card. Then you may reveal a Giant card from your hand. When you do, Invasion of the Giants deals 2 damage to target opponent or planeswalker.\nIII - The next Giant spell you cast this turn costs {2} less to cast.

View File

@@ -0,0 +1,6 @@
Name:Iron Verdict
ManaCost:2 W
Types:Instant
A:SP$ DealDamage | Cost$ 2 W | ValidTgts$ Creature.tapped | NumDmg$ 5 | TgtPrompt$ Select target tapped creature | SpellDescription$ CARDNAME deals 5 damage to target tapped creature.
K:Foretell:W
Oracle:Iron Verdict deals 5 damage to target tapped creature.\nForetell {W} (During your turn, you may pay {2} and exile this card from your hand face down. Cast it on a later turn for its foretell cost.)

View File

@@ -0,0 +1,9 @@
Name:Jarl of the Forsaken
ManaCost:3 B
Types:Creature Zombie Cleric
PT:3/2
K:Flash
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigDestroy | TriggerController$ TriggeredCardController | TriggerDescription$ When CARDNAME enters the battlefield, destroy target creature or planeswalker an opponent controls that was dealt damage this turn.
SVar:TrigDestroy:DB$ Destroy | ValidTgts$ Creature.OppCtrl+wasDealtDamageThisTurn,Planeswalker.OppCtrl+wasDealtDamageThisTurn | TgtPrompt$ Select target creature or planeswalker an opponent controls that was dealt damage this turn.
K:Foretell:1 B
Oracle:Flash\nWhen Jarl of the Forsaken enters the battlefield, destroy target creature or planeswalker an opponent controls that was dealt damage this turn.\nForetell {1}{B} (During your turn, you may pay {2} and exile this card from your hand face down. Cast it on a later turn for its foretell cost.)

View File

@@ -0,0 +1,11 @@
Name:Kardur, Doomscourge
ManaCost:2 B R
Types:Legendary Creature Demon Berserker
PT:4/3
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigGoad | TriggerDescription$ When CARDNAME enters the battlefield, until your next turn, creatures your opponents control attack each combat if able and attack a player other than you if able.
SVar:TrigGoad:DB$ Goad | Defined$ Valid Creature.YouDontCtrl
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Creature.attackingLKI | Execute$ TrigDrain | TriggerZones$ Battlefield | TriggerDescription$ Whenever an attacking creature dies, each opponent loses 1 life and you gain 1 life.
SVar:TrigDrain:DB$ LoseLife | Defined$ Player.Opponent | LifeAmount$ 1 | SubAbility$ DBGainOneLife
SVar:DBGainOneLife:DB$ GainLife | Defined$ You | LifeAmount$ 1
DeckHas:Ability$LifeGain
Oracle:When Kardur Doomscourge enters the battlefield, until your next turn, creatures your opponents control attack each combat if able and attack a player other than you if able.\nWhenever an attacking creature dies, each opponent loses 1 life and you gain 1 life.

View File

@@ -0,0 +1,13 @@
Name:Kardur's Vicious Return
ManaCost:2 B R
Types:Enchantment Saga
K:Saga:3:DBSacrifice,DBDiscard,DBReturn
SVar:DBSacrifice:DB$ ImmediateTrigger | Execute$ TrigDealDamage | UnlessCost$ Sac<1/Creature> | UnlessPayer$ You | UnlessSwitched$ True | SpellDescription$ You may sacrifice a creature. When you do, CARDNAME deals 3 damage to any target.
SVar:TrigDealDamage:DB$ DealDamage | ValidTgts$ Creature,Player,Planeswalker | TgtPrompt$ Select any target. | NumDmg$ 3
SVar:DBDiscard:DB$ Discard | Defined$ Player | NumCards$ 1 | Mode$ TgtChoose | SpellDescription$ Each player discards a card.
SVar:DBReturn:DB$ ChangeZone | Origin$ Graveyard | Destination$ Battlefield | TgtPrompt$ Choose target creature card in your graveyard | ValidTgts$ Creature.YouCtrl | RememberChanged$ True | SubAbility$ DBPutCounter | SpellDescription$ Return target creature card from your graveyard to the battlefield. Put a +1/+1 counter on it. It gains haste until your next turn.
SVar:DBPutCounter:DB$PutCounter | CounterType$ P1P1 | CounterNum$ 1 | Defined$ Remembered | SubAbility$ DBPump
SVar:DBPump:DB$ Pump | Defined$ Remembered | KW$ Haste | UntilYourNextTurn$ True | SubAbility$ DBCleanup
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
DeckHas:Ability$Counters
Oracle:(As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.)\nI - You may sacrifice a creature. When you do, Kardur's Vicious Return deals 3 damage to any target.\nII - Each player discards a card.\nIII - Return target creature card from your graveyard to the battlefield. Put a +1/+1 counter on it. It gains haste until your next turn.

View File

@@ -0,0 +1,8 @@
Name:Karfell Harbinger
ManaCost:1 U
Types:Creature Zombie Wizard
PT:1/3
A:AB$ Mana | Cost$ T | Produced$ U | RestrictValid$ Static.Foretelling,Spell.Instant,Spell.Sorcery | SpellDescription$ Add {U}. Spend this mana only to foretell a card from your hand or cast an instant or sorcery spell.
DeckHints:Type$Instant|Sorcery
Oracle:{T}: Add {U}. Spend this mana only to foretell a card from your hand or cast an instant or sorcery spell.

View File

@@ -0,0 +1,6 @@
Name:Kaya's Onslaught
ManaCost:2 W
Types:Instant
A:SP$ Pump | Cost$ 2 W | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumAtt$ 1 | NumDef$ 1 | KW$ Double Strike | SpellDescription$ Target creature gets +1/+1 and gains double strike until end of turn. | StackDescription$ SpellDescription
K:Foretell:W
Oracle:Target creature gets +1/+1 and gains double strike until end of turn.\nForetell {W} (During your turn, you may pay {2} and exile this card from your hand face down. Cast it on a later turn for its foretell cost.)

View File

@@ -0,0 +1,18 @@
Name:Kolvori, God of Kinship
ManaCost:2 G G
Types:Legendary Creature God
PT:2/2
S:Mode$ Continuous | Affected$ Card.Self | AddPower$ 4 | AddToughness$ 2 | AddKeyword$ Vigilance | IsPresent$ Creature.Legendary+YouCtrl | PresentCompare$ GE3 | Description$ As long as you control three or more legendary creatures, CARDNAME gets +4/+2 and has vigilance.
A:AB$ Dig | Cost$ 1 G T | DigNum$ 6 | ChangeNum$ 1 | ChangeValid$ Creature.Legendary | Optional$ True | RestRandomOrder$ True | SpellDescription$ Look at the top six cards of your library. You may reveal a legendary creature card from among them and put it into your hand. Put the rest on the bottom of your library in a random order.
AlternateMode:Modal
Oracle:As long as you control three or more legendary creatures, Kolvori gets +4/+2 and has vigilance.\n{1}{G}, {T}: Look at the top six cards of your library. You may reveal a legendary creature card from among them and put it into your hand. Put the rest on the bottom of your library in a random order.
ALTERNATE
Name:The Ringhart Crest
ManaCost:1 G
Types:Legendary Artifact
K:ETBReplacement:Other:ChooseCT
SVar:ChooseCT:DB$ ChooseType | Defined$ You | Type$ Creature | AILogic$ MostProminentInComputerDeck | SpellDescription$ As CARDNAME enters the battlefield, choose a creature type.
A:AB$ Mana | Cost$ T | Produced$ G | RestrictValid$ Creature.ChosenType,Creature.Legendary | SpellDescription$ {T}: Add {G}. Spend this mana only to cast a creature spell of the chosen type or a legendary creature spell.
Oracle:As The Ringhart Crest enters the battlefield, choose a creature type.\n{T}: Add {G}. Spend this mana only to cast a creature spell of the chosen type or a legendary creature spell.

View File

@@ -0,0 +1,6 @@
Name:Mammoth Growth
ManaCost:2 G
Types:Instant
A:SP$ Pump | Cost$ 2 G | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumAtt$ +4 | NumDef$ +4 | SpellDescription$ Target creature gets +4/+4 until end of turn.
K:Foretell:G
Oracle:Target creature gets +4/+4 until end of turn.\nForetell {G} (During your turn, you may pay {2} and exile this card from your hand face down. Cast it on a later turn for its foretell cost.)

View File

@@ -0,0 +1,10 @@
Name:Niko Defies Destiny
ManaCost:1 W U
Types:Enchantment Saga
K:Saga:3:DBGainLife,DBMana,DBChangeZone
SVar:DBGainLife:DB$ GainLife | LifeAmount$ X | References$ X | SpellDescription$ You gain 2 life for each foretold card you own in exile.
SVar:X:Count$ValidExile Card.foretold/Times.2
SVar:DBMana:DB$ Mana | Produced$ W U | RestrictValid$ Static.Foretelling,Card.withForetell | SpellDescription$ Add {W}{U}. Spend this mana only to foretell cards or cast spells that have foretell.
SVar:DBChangeZone:DB$ChangeZone | Origin$ Graveyard | Destination$ Hand | ValidTgts$ Card.YouCtrl+withForetell | SpellDescription$ Return target card with foretell from your graveyard to your hand.
DeckHas:Ability$Graveyard & Ability$GainLife
Oracle:(As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.)\nI — You gain 2 life for each foretold card you own in exile.\nII — Add {W}{U}. Spend this mana only to foretell cards or cast spells that have foretell.\nIII — Return target card with foretell from your graveyard to your hand.

View File

@@ -0,0 +1,14 @@
Name:Old-Growth Troll
ManaCost:G G G
Types:Creature Troll Warrior
PT:4/4
K:Trample
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self+Creature | TriggerController$ TriggeredCardController | Execute$ DBReturn | TriggerDescription$ When CARDNAME dies, if it was a creature. return it to the battlefield. It's an Aura enchantment with enchant Forest you control and “Enchanted Forest has {T}: Add {G}{G} and {1}, {T}, Sacrifice this land: Create a tapped 4/4 green Troll Warrior creature token with trample.’”
SVar:DBReturn:DB$ ChangeZone | Defined$ TriggeredNewCardLKICopy | Origin$ Graveyard | Destination$ Battlefield | AnimateSubAbility$ DBAnimate
SVar:DBAnimate:DB$ Animate | Defined$ Remembered | Types$ Enchantment,Aura | RemoveCardTypes$ True | RemoveAllAbilities$ True | Keywords$ Enchant Forest you control | Abilities$ SPAttach | staticAbilities$ STAura | Permanent$ True
SVar:STAura:Mode$ Continuous | Affected$ Land.EnchantedBy | AddAbility$ ABMana & ABToken | Description$ Enchanted Forest has {T}: Add {G}{G} and {1}, {T}, Sacrifice this land: Create a tapped 4/4 green Troll Warrior creature token with trample.
SVar:SPAttach:SP$ Attach | Cost$ 0 | ValidTgts$ Forest.YouCtrl | AILogic$ Pump
SVar:ABMana:AB$ Mana | Cost$ T | Produced$ G | Amount$ 2 | SpellDescription$ Add {G}{G}.
SVar:ABToken:AB$ Token | Cost$ 1 T Sac<1/CARDNAME> | TokenAmount$1 | TokenScript$ g_4_4_troll_warrior_trample | TokenOwner$ You | LegacyImage$ g 4 4 troll warrior trample khm | TokenTapped$ True | SpellDescription$ Create a tapped 4/4 green Troll Warrior creature token with trample.
DeckHas:Ability$Token
Oracle:Trample\nWhen Old-Growth Troll dies, if it was a creature, return it to the battlefield. Its an Aura enchantment with enchant Forest you control and “Enchanted Forest has {T}: Add {G}{G} and {1}, {T}, Sacrifice this land: Create a tapped 4/4 green Troll Warrior creature token with trample.’”

View File

@@ -0,0 +1,8 @@
Name:Poison the Cup
ManaCost:1 B B
Types:Instant
A:SP$ Destroy | Cost$ 1 B B | ValidTgts$ Creature | TgtPrompt$ Select target creature | SubAbility$ DBScry | SpellDescription$ Destroy target creature. If this spell was foretold, scry 2.
SVar:DBScry:DB$ Scry | ScryNum$ 2 | Condition$ Foretold
K:Foretell:1 B
Oracle:Destroy target creature. If this spell was foretold, scry 2.\nForetell {1}{B} (During your turn, you may pay {2} and exile this card from your hand face down. Cast it on a later turn for its foretell cost.)

View File

@@ -0,0 +1,9 @@
Name:Ravenform
ManaCost:2 U
Types:Sorcery
A:SP$ ChangeZone | Cost$ 2 U | ValidTgts$ Creature,Artifact | TgtPrompt$ Select target artifact or creature | Origin$ Battlefield | Destination$ Exile | SubAbility$ DBToken | AILogic$ Pongify | SpellDescription$ Exile target artifact or creature. Its controller creates a 1/1 Blue bird creature token with flying.
SVar:DBToken:DB$ Token | TokenAmount$ 1 | TokenScript$ u_1_1_bird_flying | TokenOwner$ TargetedController
DeckHas:Ability$Token
K:Foretell:U
DeckHas:Ability$Token
Oracle:Exile target artifact or creature. Its controller creates a 1/1 Blue bird creature token with flying.\nForetell {U} (During your turn, you may pay {2} and exile this card from your hand face down. Cast it on a later turn for its foretell cost.)

View File

@@ -6,9 +6,9 @@ K:Flying
K:Vigilance
R:Event$ Moved | ValidCard$ Land.Snow+OppCtrl | Destination$ Battlefield | ReplaceWith$ ETBTapped | ActiveZones$ Battlefield | Description$ Snow lands your opponents control enter the battlefield tapped.
SVar:ETBTapped:DB$ ChangeZone | Origin$ All | Destination$ Battlefield | Tapped$ True | Defined$ ReplacedCard
S:Mode$ RaiseCost | ValidCard$ Card.cmcGE4 | Type$ Spell | Activator$ Opponent | Amount$ 2 | Description$ Spells your opponents cast with converted mana cost 4 or greater cost {2} more to cast.
S:Mode$ RaiseCost | ValidCard$ Card.nonCreature+cmcGE4 | Type$ Spell | Activator$ Opponent | Amount$ 2 | Description$ Noncreature spells your opponents cast with converted mana cost 4 or greater cost {2} more to cast.
AlternateMode:Modal
Oracle:Flying, vigilance\nSnow lands your opponents control enter the battlefield tapped.\nSpells your opponents cast with converted mana cost 4 or greater cost {2} more to cast.
Oracle:Flying, vigilance\nSnow lands your opponents control enter the battlefield tapped.\nNoncreature spells your opponents cast with converted mana cost 4 or greater cost {2} more to cast.
ALTERNATE

View File

@@ -0,0 +1,9 @@
Name:Return Upon the Tide
ManaCost:4 B
Types:Sorcery
A:SP$ ChangeZone | Cost$ 4 B | Origin$ Graveyard | Destination$ Battlefield | TgtPrompt$ Choose target creature card in your graveyard | ValidTgts$ Creature.YouCtrl | SubAbility$ DBToken | SpellDescription$ Return target creature card from your graveyard to the battlefield. If it's an Elf, create two 1/1 green Elf Warrior creature tokens.
SVar:DBToken:DB$ Token | TokenAmount$ 2 | TokenScript$ g_1_1_elf_warrior | LegacyImage$ g 1 1 elf warrior khm | TokenOwner$ You | ConditionCheckSVar$ X | ConditionSVarCompare$ GE1 | References$ X
SVar:X:Targeted$Valid Elf
K:ForeTell:3 B
DeckHas:Ability$Token
Oracle:Return target creature card from your graveyard to the battlefield. If it's an Elf, create two 1/1 green Elf Warrior creature tokens.\nForetell {3}{B} (During your turn, you may pay {2} and exile this card from your hand face down. Cast it on a later turn for its foretell cost.)

View File

@@ -0,0 +1,8 @@
Name:Rise of the Dread Marn
ManaCost:2 B
Types:Instant
A:SP$ Token | Cost$ 2 B | LegacyImage$ b 2 2 zombie berserker khm | TokenAmount$ X | References$ X | TokenScript$ b_2_2_zombie_berserker | TokenOwner$ You | SpellDescription$ Create X 2/2 black Zombie Berserker creature tokens, where X is the number of nontoken creatures that died this turn.
SVar:X:Count$ThisTurnEntered_Graveyard_from_Battlefield_Creature.nonToken
K:Foretell:B
DeckHas:Ability$Token
Oracle:Create X 2/2 black Zombie Berserker creature tokens, where X is the number of nontoken creatures that died this turn.\nForetell {B} (During your turn, you may pay {2} and exile this card from your hand face down. Cast it on a later turn for its foretell cost.)

Some files were not shown because too many files have changed in this diff Show More