Merge master

This commit is contained in:
Lyu Zong-Hong
2021-02-09 17:15:06 +09:00
345 changed files with 340 additions and 174 deletions

View File

@@ -108,9 +108,6 @@ public class ComputerUtil {
if (chooseTargets != null) {
chooseTargets.run();
}
if (sa.isBestow()) {
sa.getHostCard().animateBestow();
}
final Cost cost = sa.getPayCosts();
// TODO: update mana color conversion for Daxos of Meletis

View File

@@ -1,6 +1,9 @@
package forge.ai.ability;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import forge.ai.*;
import forge.card.CardStateName;
import forge.card.CardTypeView;
@@ -14,11 +17,13 @@ import forge.game.player.Player;
import forge.game.player.PlayerActionConfirmMode;
import forge.game.spellability.Spell;
import forge.game.spellability.SpellAbility;
import forge.game.spellability.SpellAbilityPredicates;
import forge.game.spellability.SpellPermanent;
import forge.game.spellability.TargetRestrictions;
import forge.game.zone.ZoneType;
import forge.util.MyRandom;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -55,6 +60,21 @@ public class PlayAi extends SpellAbilityAi {
}
}
if (sa.hasParam("ValidSA")) {
final String valid[] = {sa.getParam("ValidSA")};
final Iterator<Card> itr = cards.iterator();
while (itr.hasNext()) {
final Card c = itr.next();
final List<SpellAbility> validSA = Lists.newArrayList(Iterables.filter(AbilityUtils.getBasicSpellsFromPlayEffect(c, ai), SpellAbilityPredicates.isValid(valid, ai , c, sa)));
if (validSA.size() == 0) {
itr.remove();
}
}
if (cards.isEmpty()) {
return false;
}
}
if (game.getRules().hasAppliedVariant(GameType.MoJhoSto) && source.getName().equals("Jhoira of the Ghitu Avatar")) {
// Additional logic for MoJhoSto:
// Do not activate Jhoira too early, usually there are few good targets

View File

@@ -8,6 +8,7 @@ import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import forge.util.CardTranslation;
import forge.util.ComparableOp;
import forge.util.PredicateString;
@@ -352,16 +353,16 @@ public final class CardRulesPredicates {
case NAME:
boolean otherName = false;
if (card.getOtherPart() != null) {
otherName = op(card.getOtherPart().getName(), this.operand);
otherName = (op(CardTranslation.getTranslatedName(card.getOtherPart().getName()), this.operand) || op(card.getOtherPart().getName(), this.operand));
}
return otherName || op(card.getName(), this.operand);
return otherName || (op(CardTranslation.getTranslatedName(card.getName()), this.operand) || op(card.getName(), this.operand));
case SUBTYPE:
shouldContain = (this.getOperator() == StringOp.CONTAINS) || (this.getOperator() == StringOp.EQUALS);
return shouldContain == card.getType().hasSubtype(this.operand);
case ORACLE_TEXT:
return op(card.getOracleText(), operand);
return (op(CardTranslation.getTranslatedOracle(card.getName()), operand) || op(card.getOracleText(), this.operand));
case JOINED_TYPE:
return op(card.getType().toString(), operand);
return (op(CardTranslation.getTranslatedType(card.getName(), card.getType().toString()), operand) || op(card.getType().toString(), operand));
case COST:
final String cost = card.getManaCost().toString();
return op(cost, operand);

View File

@@ -28,6 +28,7 @@ import forge.StaticData;
import forge.card.CardDb;
import forge.card.CardRarity;
import forge.card.CardRules;
import forge.util.CardTranslation;
import forge.util.Localizer;
import forge.util.TextUtil;
@@ -187,7 +188,7 @@ public final class PaperCard implements Comparable<IPaperCard>, InventoryItemFro
*/
@Override
public String toString() {
return name;
return CardTranslation.getTranslatedName(name);
// cannot still decide, if this "name|set" format is needed anymore
// return String.format("%s|%s", name, cardSet);
}

View File

@@ -177,6 +177,12 @@ public class ForgeScript {
return sa.getActivatingPlayer().equals(sourceController);
} else if (property.equals("OppCtrl")) {
return sa.getActivatingPlayer().isOpponentOf(sourceController);
} else if (property.startsWith("cmc")) {
int y = sa.getPayCosts().getTotalMana().getCMC();
int x = AbilityUtils.calculateAmount(spellAbility.getHostCard(), property.substring(5), spellAbility);
if (!Expressions.compare(y, property, x)) {
return false;
}
} else if (sa.getHostCard() != null) {
return sa.getHostCard().hasProperty(property, sourceController, source, spellAbility);
}

View File

@@ -106,6 +106,14 @@ public class GameAction {
}
private Card changeZoneWrapped(final Zone zoneFrom, Zone zoneTo, final Card c, Integer position, SpellAbility cause, Map<AbilityKey, Object> params) {
// 111.11. A copy of a permanent spell becomes a token as it resolves.
// The token has the characteristics of the spell that became that token.
// The token is not “created” for the purposes of any replacement effects or triggered abilities that refer to creating a token.
if (c.isCopiedSpell() && zoneTo.is(ZoneType.Battlefield) && c.isPermanent() && cause != null && cause.isSpell() && c.equals(cause.getHostCard())) {
c.setCopiedSpell(false);
c.setToken(true);
}
if (c.isCopiedSpell() || (c.isImmutable() && zoneTo.is(ZoneType.Exile))) {
// Remove Effect from command immediately, this is essential when some replacement
// effects happen during the resolving of a spellability ("the next time ..." effect)
@@ -637,8 +645,11 @@ public class GameAction {
}
public final Card moveToStack(final Card c, SpellAbility cause, Map<AbilityKey, Object> params) {
final Zone stack = game.getStackZone();
return moveTo(stack, c, cause, params);
Card result = moveTo(game.getStackZone(), c, cause, params);
if (cause != null && cause.isSpell() && result.equals(cause.getHostCard())) {
result.setSplitStateToPlayAbility(cause);
}
return result;
}
public final Card moveToGraveyard(final Card c, SpellAbility cause) {

View File

@@ -3,7 +3,10 @@ package forge.game.ability;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import forge.card.CardStateName;
import forge.card.CardType;
import forge.card.ColorSet;
import forge.card.MagicColor;
@@ -1820,7 +1823,11 @@ public class AbilityUtils {
public static final List<SpellAbility> getBasicSpellsFromPlayEffect(final Card tgtCard, final Player controller) {
List<SpellAbility> sas = new ArrayList<>();
for (SpellAbility s : tgtCard.getBasicSpells()) {
List<SpellAbility> list = Lists.newArrayList(tgtCard.getBasicSpells());
if (tgtCard.isModal()) {
list.addAll(Lists.newArrayList(tgtCard.getBasicSpells(tgtCard.getState(CardStateName.Modal))));
}
for (SpellAbility s : list) {
final Spell newSA = (Spell) s.copy();
newSA.setActivatingPlayer(controller);
SpellAbilityRestriction res = new SpellAbilityRestriction();

View File

@@ -10,6 +10,7 @@ import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
import forge.game.card.CardLists;
import forge.game.card.CardZoneTable;
import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
import forge.game.spellability.TargetRestrictions;
@@ -25,27 +26,27 @@ public class AttachEffect extends SpellAbilityEffect {
@Override
public void resolve(SpellAbility sa) {
final Card host = sa.getHostCard();
final Game game = host.getGame();
if (host.isAura() && sa.isSpell()) {
final Player ap = sa.getActivatingPlayer();
CardZoneTable table = new CardZoneTable();
host.setController(sa.getActivatingPlayer(), 0);
ZoneType previousZone = host.getZone().getZoneType();
// The Spell_Permanent (Auras) version of this AF needs to
// move the card into play before Attaching
host.setController(ap, 0);
// 111.11. A copy of a permanent spell becomes a token as it resolves.
// The token has the characteristics of the spell that became that token.
// The token is not “created” for the purposes of any replacement effects or triggered abilities that refer to creating a token.
if (host.isCopiedSpell()) {
host.setCopiedSpell(false);
host.setToken(true);
}
final Card c = ap.getGame().getAction().moveToPlay(host, ap, sa);
final Card c = game.getAction().moveToPlay(host, sa);
sa.setHostCard(c);
ZoneType newZone = c.getZone().getZoneType();
if (newZone != previousZone) {
table.put(previousZone, newZone, c);
}
table.triggerChangesZoneAll(game);
}
final Card source = sa.getHostCard();
final Game game = source.getGame();
CardCollection attachments;
final List<GameObject> targets = getDefinedOrTargeted(sa, "Defined");

View File

@@ -2,10 +2,12 @@ package forge.game.ability.effects;
import com.google.common.collect.Lists;
import forge.game.Game;
import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card;
import forge.game.player.Player;
import forge.game.card.CardZoneTable;
import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType;
public class PermanentEffect extends SpellAbilityEffect {
@@ -18,25 +20,26 @@ public class PermanentEffect extends SpellAbilityEffect {
*/
@Override
public void resolve(SpellAbility sa) {
Player p = sa.getActivatingPlayer();
sa.getHostCard().setController(p, 0);
final Card host = sa.getHostCard();
final Game game = host.getGame();
CardZoneTable table = new CardZoneTable();
ZoneType previousZone = host.getZone().getZoneType();
// 111.11. A copy of a permanent spell becomes a token as it resolves.
// The token has the characteristics of the spell that became that token.
// The token is not “created” for the purposes of any replacement effects or triggered abilities that refer to creating a token.
if (host.isCopiedSpell()) {
host.setCopiedSpell(false);
host.setToken(true);
}
host.setController(sa.getActivatingPlayer(), 0);
final Card c = p.getGame().getAction().moveToPlay(host, p, sa);
final Card c = game.getAction().moveToPlay(host, sa);
sa.setHostCard(c);
// some extra for Dashing
if (sa.isDash()) {
if (sa.isDash() && c.isInPlay()) {
c.setSVar("EndOfTurnLeavePlay", "Dash");
registerDelayedTrigger(sa, "Hand", Lists.newArrayList(c));
}
ZoneType newZone = c.getZone().getZoneType();
if (newZone != previousZone) {
table.put(previousZone, newZone, c);
}
table.triggerChangesZoneAll(game);
}
}

View File

@@ -1,6 +1,7 @@
package forge.game.ability.effects;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
@@ -28,6 +29,7 @@ import forge.game.replacement.ReplacementHandler;
import forge.game.replacement.ReplacementLayer;
import forge.game.spellability.AlternativeCost;
import forge.game.spellability.SpellAbility;
import forge.game.spellability.SpellAbilityPredicates;
import forge.game.trigger.TriggerType;
import forge.game.zone.Zone;
import forge.game.zone.ZoneType;
@@ -82,7 +84,7 @@ public class PlayEffect extends SpellAbilityEffect {
tgtCards = new CardCollection(
AbilityUtils.filterListByType(game.getCardsIn(zones), sa.getParam("Valid"), sa)
);
if ( sa.hasParam("ShowCards") ) {
if (sa.hasParam("ShowCards")) {
showCards = new CardCollection(AbilityUtils.filterListByType(game.getCardsIn(zones), sa.getParam("ShowCards"), sa));
}
}
@@ -102,7 +104,7 @@ public class PlayEffect extends SpellAbilityEffect {
final CardCollection choice = new CardCollection();
final String num = sa.hasParam("RandomNum") ? sa.getParam("RandomNum") : "1";
int ncopied = AbilityUtils.calculateAmount(source, num, sa);
while(ncopied > 0) {
while (ncopied > 0) {
final PaperCard cp = Aggregates.random(copysource);
final Card possibleCard = Card.fromPaperCard(cp, sa.getActivatingPlayer());
// Need to temporarily set the Owner so the Game is set
@@ -145,6 +147,21 @@ public class PlayEffect extends SpellAbilityEffect {
return;
}
if (sa.hasParam("ValidSA")) {
final String valid[] = {sa.getParam("ValidSA")};
final Iterator<Card> itr = tgtCards.iterator();
while (itr.hasNext()) {
final Card c = itr.next();
final List<SpellAbility> validSA = Lists.newArrayList(Iterables.filter(AbilityUtils.getBasicSpellsFromPlayEffect(c, controller), SpellAbilityPredicates.isValid(valid, controller , c, sa)));
if (validSA.size() == 0) {
itr.remove();
}
}
if (tgtCards.isEmpty()) {
return;
}
}
if (sa.hasParam("Amount") && sa.getParam("Amount").equals("All")) {
amount = tgtCards.size();
}
@@ -214,7 +231,12 @@ public class PlayEffect extends SpellAbilityEffect {
}
// get basic spells (no flashback, etc.)
final List<SpellAbility> sas = AbilityUtils.getBasicSpellsFromPlayEffect(tgtCard, controller);
List<SpellAbility> sas = AbilityUtils.getBasicSpellsFromPlayEffect(tgtCard, controller);
if (sa.hasParam("ValidSA")) {
final String valid[] = {sa.getParam("ValidSA")};
sas = Lists.newArrayList(Iterables.filter(sas, SpellAbilityPredicates.isValid(valid, controller , source, sa)));
}
if (sas.isEmpty()) {
continue;
}
@@ -233,6 +255,10 @@ public class PlayEffect extends SpellAbilityEffect {
// For Illusionary Mask effect
tgtSA = CardFactoryUtil.abilityMorphDown(tgtCard);
}
// in case player canceled from choice dialog
if (tgtSA == null) {
continue;
}
final boolean noManaCost = sa.hasParam("WithoutManaCost");
if (noManaCost) {

View File

@@ -3,24 +3,40 @@ package forge.game.card;
import java.io.Serializable;
public class CardFaceView implements Serializable, Comparable<CardFaceView> {
private String name;
/**
*
*/
private static final long serialVersionUID = 1874016432028306386L;
private String displayName;
private String oracleName;
public CardFaceView(String faceName) {
this.name = faceName;
public CardFaceView(String displayName) {
this(displayName, displayName);
}
public String getName() { return name;}
public CardFaceView(String displayFaceName, String oracleFaceName ) {
this.displayName = displayFaceName;
this.oracleName = oracleFaceName;
}
public String getName() { return displayName;}
public void setName(String name) {
this.name = name;
this.displayName = name;
}
public String getOracleName() { return oracleName; }
public void setOracleName(String name) {
this.oracleName = name;
}
public String toString() {
return name;
return displayName;
}
@Override
public int compareTo(CardFaceView o) {
return this.getName().compareTo(o.getName());
return this.getOracleName().compareTo(o.getOracleName());
}
}

View File

@@ -651,24 +651,28 @@ public class CardProperty {
if ((property.endsWith("Source") || property.equals("DamagedBy")) &&
!card.getReceivedDamageFromThisTurn().containsKey(source)) {
return false;
} else if (property.endsWith("Remembered")) {
boolean matched = false;
for (final Object obj : source.getRemembered()) {
if (!(obj instanceof Card)) {
continue;
} else {
String prop = property.substring("DamagedBy".length());
boolean found = false;
for (Card d : card.getReceivedDamageFromThisTurn().keySet()) {
if (d.isValid(prop, sourceController, source, spellAbility)) {
found = true;
break;
}
matched |= card.getReceivedDamageFromThisTurn().containsKey(obj);
}
if (!matched)
return false;
} else if (property.endsWith("Equipped")) {
final Card equipee = source.getEquipping();
if (equipee == null || !card.getReceivedDamageFromThisTurn().containsKey(equipee))
return false;
} else if (property.endsWith("Enchanted")) {
final Card equipee = source.getEnchantingCard();
if (equipee == null || !card.getReceivedDamageFromThisTurn().containsKey(equipee))
if (!found) {
for (Card d : AbilityUtils.getDefinedCards(source, prop, spellAbility)) {
if (card.getReceivedDamageFromThisTurn().containsKey(d)) {
found = true;
break;
}
}
}
if (!found) {
return false;
}
}
} else if (property.startsWith("Damaged")) {
if (!card.getDealtDamageToThisTurn().containsKey(source)) {
@@ -1035,17 +1039,21 @@ public class CardProperty {
}
}
return false;
} else if (property.startsWith("ThisTurnEntered")) {
final String restrictions = property.split("ThisTurnEntered_")[1];
final String[] res = restrictions.split("_");
final ZoneType destination = ZoneType.smartValueOf(res[0]);
ZoneType origin = null;
if (res.length > 1 && res[1].equals("from")) {
origin = ZoneType.smartValueOf(res[2]);
} else if (property.equals("ThisTurnEntered")) {
// only check if it entered the Zone this turn
if (card.getTurnInZone() != game.getPhaseHandler().getTurn()) {
return false;
}
List<Card> cards = CardUtil.getThisTurnEntered(destination,
origin, "Card", source);
if (!cards.contains(card)) {
} else if (property.startsWith("ThisTurnEnteredFrom")) {
final String restrictions = property.split("ThisTurnEnteredFrom_")[1];
final String[] res = restrictions.split("_");
final ZoneType origin = ZoneType.smartValueOf(res[0]);
if (card.getTurnInZone() != game.getPhaseHandler().getTurn()) {
return false;
}
if (!card.getZone().isCardAddedThisTurn(card, origin)) {
return false;
}
} else if (property.equals("DiscardedThisTurn")) {

View File

@@ -25,6 +25,7 @@ import forge.util.Lang;
import forge.util.Localizer;
import forge.util.TextUtil;
import forge.util.collect.FCollectionView;
import forge.util.CardTranslation;
import org.apache.commons.lang3.StringUtils;
import java.util.EnumSet;
@@ -933,7 +934,7 @@ public class CardView extends GameEntityView {
}
}
}
return (zone + ' ' + name + " (" + getId() + ")").trim();
return (zone + ' ' + CardTranslation.getTranslatedName(name) + " (" + getId() + ")").trim();
}
public class CardStateView extends TrackableObject {

View File

@@ -211,6 +211,13 @@ public class Zone implements java.io.Serializable, Iterable<Card> {
return getCardsAdded(cardsAddedLastTurn, origin);
}
public final boolean isCardAddedThisTurn(final Card card, final ZoneType origin) {
if (!cardsAddedThisTurn.containsKey(origin)) {
return false;
}
return cardsAddedThisTurn.get(origin).contains(card);
}
private static List<Card> getCardsAdded(final MapOfLists<ZoneType, Card> cardsAdded, final ZoneType origin) {
if (origin != null) {
final Collection<Card> cards = cardsAdded.get(origin);

View File

@@ -167,7 +167,7 @@ public class GuiChoose {
if (sel instanceof ICardFace) {
faceName = ((ICardFace) sel).getName();
} else {
faceName = ((CardFaceView) sel).getName();
faceName = ((CardFaceView) sel).getOracleName();
}
PaperCard paper = FModel.getMagicDb().getCommonCards().getUniqueByName(faceName);
if (paper == null) {

View File

@@ -1,6 +1,5 @@
#Add one announcement per line
Keyboard shortcut change: to help improve accessibility, the arrow key shortcuts to move between deck editor tables now require control or Command, depending on which platform you're on.
Jumpstart sealed!
Double Masters (including double pick)
Lots of art updates and fixes
Sorry for the long wait between releases. Pandemic + Technology issues caused some issues we couldn't hurdle.
Get in the discord if you aren't yet.
Lots of new cards including Kaldheim.
No update on Mutate yet. Trust us, you'll know when it's here.

View File

@@ -0,0 +1,8 @@
Name:Aegar, the Freezing Flame
ManaCost:1 U R
Types:Legendary Creature Giant Wizard
PT:3/3
T:Mode$ ExcessDamage | ValidTarget$ Creature.OppCtrl+DamagedByGiant.YouCtrl,Creature.OppCtrl+DamagedByWizard.YouCtrl,Creature.OppCtrl+DamagedBySpell.YouCtrl,Planeswalker.OppCtrl+DamagedByGiant.YouCtrl,Planeswalker.OppCtrl+DamagedByWizard.YouCtrl,Planeswalker.OppCtrl+DamagedBySpell.YouCtrl | TriggerZones$ Battlefield | Execute$ TrigDraw | TriggerDescription$ Whenever a creature or planeswalker an opponent controls is dealt excess damage, if a Giant, Wizard, or spell you controlled dealt damage to it this turn, draw a card.
SVar:TrigDraw:DB$ Draw | Defined$ You | NumCards$ 1
Oracle:Whenever a creature or planeswalker an opponent controls is dealt excess damage, if a Giant, Wizard, or spell you controlled dealt damage to it this turn, draw a card.

View File

@@ -2,7 +2,7 @@ Name:Bag of Holding
ManaCost:1
Types:Artifact
T:Mode$ Discarded | ValidCard$ Card.YouCtrl | TriggerZones$ Battlefield | Execute$ TrigExile | TriggerDescription$ Whenever you discard a card, exile that card from your graveyard.
SVar:TrigExile:DB$ ChangeZone | Defined$ TriggeredCardLKICopy | Origin$ Graveyard | Destination$ Exile
SVar:TrigExile:DB$ ChangeZone | Defined$ TriggeredCard | Origin$ Graveyard | Destination$ Exile
A:AB$ Draw | Cost$ 2 T | NumCards$ 1 | SpellDescription$ Draw a card, then discard a card. | SubAbility$ DBDiscard
SVar:DBDiscard:DB$Discard | Defined$ You | NumCards$ 1 | Mode$ TgtChoose
AI:RemoveDeck:All

View File

@@ -1,7 +1,7 @@
Name:Baral's Expertise
ManaCost:3 U U
Types:Sorcery
A:SP$ ChangeZone | Cost$ 3 U U | TargetMin$ 0 | TargetMax$ 3 | ValidTgts$ Artifact,Creature | TgtPrompt$ Select target artifact or creature | Origin$ Battlefield | Destination$ Hand | SubAbility$ DBPlay | SpellDescription$ Return up to three target artifacts and/or creatures to their owners' hands. You may cast a card with converted mana cost 4 or less from your hand without paying its mana cost.
SVar:DBPlay:DB$ Play | Valid$ Card.nonLand+YouOwn+cmcLE4 | ValidZone$ Hand | WithoutManaCost$ True | Amount$ 1 | Controller$ You | Optional$ True
A:SP$ ChangeZone | Cost$ 3 U U | TargetMin$ 0 | TargetMax$ 3 | ValidTgts$ Artifact,Creature | TgtPrompt$ Select target artifact or creature | Origin$ Battlefield | Destination$ Hand | SubAbility$ DBPlay | SpellDescription$ Return up to three target artifacts and/or creatures to their owners' hands. You may cast a spell with converted mana cost 4 or less from your hand without paying its mana cost.
SVar:DBPlay:DB$ Play | Valid$ Card.nonLand+YouOwn | ValidSA$ Spell.cmcLE4 | ValidZone$ Hand | WithoutManaCost$ True | Amount$ 1 | Controller$ You | Optional$ True
SVar:Picture:http://www.wizards.com/global/images/magic/general/barals_expertise.jpg
Oracle:Return up to three target artifacts and/or creatures to their owners' hands.\nYou may cast a card with converted mana cost 4 or less from your hand without paying its mana cost.
Oracle:Return up to three target artifacts and/or creatures to their owners' hands.\nYou may cast a spell with converted mana cost 4 or less from your hand without paying its mana cost.

View File

@@ -1,5 +1,5 @@
Name:Brought Back
ManaCost:W W
Types:Instant
A:SP$ ChangeZone | Cost$ W W | ValidTgts$ Permanent.YouOwn+ThisTurnEntered_Graveyard_from_Battlefield | TgtPrompt$ Select up to two target permanent cards in your graveyard that were put there from the battlefield this turn | TargetMin$ 0 | TargetMax$ 2 | Origin$ Graveyard | Destination$ Battlefield | Tapped$ True | SpellDescription$ Choose up to two target permanent cards in your graveyard that were put there from the battlefield this turn. Return them to the battlefield tapped.
A:SP$ ChangeZone | Cost$ W W | ValidTgts$ Permanent.YouOwn+ThisTurnEnteredFrom_Battlefield | TgtPrompt$ Select up to two target permanent cards in your graveyard that were put there from the battlefield this turn | TargetMin$ 0 | TargetMax$ 2 | Origin$ Graveyard | Destination$ Battlefield | Tapped$ True | SpellDescription$ Choose up to two target permanent cards in your graveyard that were put there from the battlefield this turn. Return them to the battlefield tapped.
Oracle:Choose up to two target permanent cards in your graveyard that were put there from the battlefield this turn. Return them to the battlefield tapped.

View File

@@ -4,7 +4,7 @@ Types:Sorcery
S:Mode$ ReduceCost | ValidCard$ Card.Self | Type$ Spell | Amount$ X | EffectZone$ All | References$ X | Description$ This spell costs {1} less to cast for each creature in your party.
SVar:X:Count$Party
A:SP$ ChangeZone | Cost$ 4 B | Origin$ Library | Destination$ Hand | ChangeType$ Card | ChangeNum$ 1 | Mandatory$ True | SubAbility$ DBPlay | StackDescription$ SpellDescription | SpellDescription$ Search your library for a card, put it into your hand, then shuffle your library. If you have a full party, you may cast a spell with converted mana cost 4 or less from your hand without paying its mana cost.
SVar:DBPlay:DB$ Play | ConditionCheckSVar$ X | ConditionSVarCompare$ EQ4 | References$ X | Optional$ True | Valid$ Card.nonLand+YouOwn+cmcLE4 | ValidZone$ Hand | WithoutManaCost$ True | Amount$ 1 | StackDescription$ None
SVar:DBPlay:DB$ Play | ConditionCheckSVar$ X | ConditionSVarCompare$ EQ4 | References$ X | Optional$ True | Valid$ Card.nonLand+YouOwn | ValidSA$ Spell.cmcLE4 | ValidZone$ Hand | WithoutManaCost$ True | Amount$ 1 | StackDescription$ None
DeckHas:Ability$Party
DeckHints:Type$Cleric|Rogue|Warrior|Wizard
Oracle:This spell costs {1} less to cast for each creature in your party. (Your party consists of up to one each of Cleric, Rogue, Warrior, and Wizard.)\nSearch your library for a card, put it into your hand, then shuffle your library. If you have a full party, you may cast a spell with converted mana cost 4 or less from your hand without paying its mana cost.

View File

@@ -2,5 +2,5 @@ Name:Cry of the Carnarium
ManaCost:1 B B
Types:Sorcery
A:SP$ PumpAll | Cost$ 1 B B | ValidCards$ Creature | NumAtt$ -2 | NumDef$ -2 | IsCurse$ True | ReplaceDyingValid$ Creature | SubAbility$ ExileSomeCreatures | SpellDescription$ All creatures get -2/-2 until end of turn. Exile all creature cards in all graveyards that were put there from the battlefield this turn. If a creature would die this turn, exile it instead.
SVar:ExileSomeCreatures:DB$ ChangeZone | Defined$ ThisTurnEntered_Graveyard_from_Battlefield_Creature.nonToken | Origin$ Graveyard | Destination$ Exile | SpellDescription$ Exile all creature cards in all graveyards that were put there from the battlefield this turn.
SVar:ExileSomeCreatures:DB$ ChangeZone | Defined$ ValidGraveyard Creature.nonToken+ThisTurnEnteredFrom_Battlefield | Origin$ Graveyard | Destination$ Exile | SpellDescription$ Exile all creature cards in all graveyards that were put there from the battlefield this turn.
Oracle:All creatures get -2/-2 until end of turn. Exile all creature cards in all graveyards that were put there from the battlefield this turn. If a creature would die this turn, exile it instead.

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