Merge pull request #3018 from tool4ever/battlefix

Fix some crashes with Battles
This commit is contained in:
Anthony Calosa
2023-04-27 10:00:24 +08:00
committed by GitHub
30 changed files with 105 additions and 75 deletions

View File

@@ -722,6 +722,11 @@ public class AiAttackController {
return pwNearUlti != null ? pwNearUlti : ComputerUtilCard.getBestPlaneswalkerAI(pwDefending);
}
List<Card> battleDefending = c.getDefendingBattles();
if (!battleDefending.isEmpty()) {
// TODO filter for team ones
}
return prefDefender;
}

View File

@@ -2059,31 +2059,23 @@ public class ComputerUtilCombat {
if (block.size() == 1) {
final Card blocker = block.getFirst();
int dmgToBlocker = dmgCanDeal;
if (hasTrample) {
int dmgToKill = getEnoughDamageToKill(blocker, dmgCanDeal, attacker, true);
if (hasTrample && isAttacking) { // otherwise no entity to deliver damage via trample
dmgToBlocker = getEnoughDamageToKill(blocker, dmgCanDeal, attacker, true);
if (dmgCanDeal < dmgToKill) {
dmgToKill = Math.min(blocker.getLethalDamage(), dmgCanDeal);
} else {
dmgToKill = Math.max(blocker.getLethalDamage(), dmgToKill);
if (dmgCanDeal < dmgToBlocker) {
// can't kill so just put the lowest legal amount
dmgToBlocker = Math.min(blocker.getLethalDamage(), dmgCanDeal);
}
if (!isAttacking) { // no entity to deliver damage via trample
dmgToKill = dmgCanDeal;
}
final int remainingDmg = dmgCanDeal - dmgToKill;
final int remainingDmg = dmgCanDeal - dmgToBlocker;
// If Extra trample damage, assign to defending player/planeswalker (when there is one)
if (remainingDmg > 0) {
damageMap.put(null, remainingDmg);
}
damageMap.put(blocker, dmgToKill);
} else {
damageMap.put(blocker, dmgCanDeal);
}
damageMap.put(blocker, dmgToBlocker);
} // 1 blocker
else {
// Does the attacker deal lethal damage to all blockers
@@ -2478,10 +2470,15 @@ public class ComputerUtilCombat {
public static GameEntity addAttackerToCombat(SpellAbility sa, Card attacker, Iterable<? extends GameEntity> defenders) {
Combat combat = sa.getHostCard().getGame().getCombat();
if (combat != null) {
// 1. If the card that spawned the attacker was sent at a planeswalker, attack the same. Consider improving.
GameEntity def = combat.getDefenderByAttacker(sa.getHostCard());
if (def instanceof Card && ((Card)def).isPlaneswalker() && Iterables.contains(defenders, def)) {
return def;
// 1. If the card that spawned the attacker was sent at a card, attack the same. Consider improving.
if (def instanceof Card && Iterables.contains(defenders, def)) {
if (((Card)def).isPlaneswalker()) {
return def;
}
if (((Card)def).isBattle()) {
return def;
}
}
// 2. Otherwise, go through the list of options one by one, choose the first one that can't be blocked profitably.
for (GameEntity p : defenders) {

View File

@@ -314,21 +314,21 @@ public abstract class SpellAbilityAi {
public <T extends GameEntity> T chooseSingleEntity(Player ai, SpellAbility sa, Collection<T> options, boolean isOptional, Player targetedPlayer, Map<String, Object> params) {
boolean hasPlayer = false;
boolean hasCard = false;
boolean hasPlaneswalker = false;
boolean hasAttackableCard = false;
for (T ent : options) {
if (ent instanceof Player) {
hasPlayer = true;
} else if (ent instanceof Card) {
hasCard = true;
if (((Card)ent).isPlaneswalker()) {
hasPlaneswalker = true;
if (((Card)ent).isPlaneswalker() || ((Card)ent).isBattle()) {
hasAttackableCard = true;
}
}
}
if (hasPlayer && hasPlaneswalker) {
return (T) chooseSinglePlayerOrPlaneswalker(ai, sa, (Collection<GameEntity>) options, params);
if (hasPlayer && hasAttackableCard) {
return (T) chooseSingleAttackableEntity(ai, sa, (Collection<GameEntity>) options, params);
} else if (hasCard) {
return (T) chooseSingleCard(ai, sa, (Collection<Card>) options, isOptional, targetedPlayer, params);
} else if (hasPlayer) {
@@ -353,7 +353,7 @@ public abstract class SpellAbilityAi {
return Iterables.getFirst(options, null);
}
protected GameEntity chooseSinglePlayerOrPlaneswalker(Player ai, SpellAbility sa, Iterable<GameEntity> options, Map<String, Object> params) {
protected GameEntity chooseSingleAttackableEntity(Player ai, SpellAbility sa, Iterable<GameEntity> options, Map<String, Object> params) {
System.err.println("Warning: default (ie. inherited from base class) implementation of chooseSinglePlayerOrPlaneswalker is used for " + this.getClass().getName() + ". Consider declaring an overloaded method");
return Iterables.getFirst(options, null);
}

View File

@@ -1760,12 +1760,12 @@ public class ChangeZoneAi extends SpellAbilityAi {
}
@Override
protected GameEntity chooseSinglePlayerOrPlaneswalker(Player ai, SpellAbility sa, Iterable<GameEntity> options, Map<String, Object> params) {
protected GameEntity chooseSingleAttackableEntity(Player ai, SpellAbility sa, Iterable<GameEntity> options, Map<String, Object> params) {
if (params != null && params.containsKey("Attacker")) {
return ComputerUtilCombat.addAttackerToCombat(sa, (Card) params.get("Attacker"), options);
}
// should not be reached
return super.chooseSinglePlayerOrPlaneswalker(ai, sa, options, params);
return super.chooseSingleAttackableEntity(ai, sa, options, params);
}
private boolean doSacAndReturnFromGraveLogic(final Player ai, final SpellAbility sa) {

View File

@@ -9,6 +9,8 @@ import com.google.common.collect.Lists;
import forge.ai.ComputerUtil;
import forge.ai.SpellAbilityAi;
import forge.game.player.Player;
import forge.game.player.PlayerCollection;
import forge.game.player.PlayerPredicates;
import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType;
@@ -31,7 +33,10 @@ public class ChoosePlayerAi extends SpellAbilityAi {
@Override
public Player chooseSinglePlayer(Player ai, SpellAbility sa, Iterable<Player> choices, Map<String, Object> params) {
Player chosen = null;
if ("Curse".equals(sa.getParam("AILogic"))) {
if (sa.hasParam("Protect")) {
chosen = new PlayerCollection(choices).min(PlayerPredicates.compareByLife());
}
else if ("Curse".equals(sa.getParam("AILogic"))) {
for (Player pc : choices) {
if (pc.isOpponentOf(ai)) {
chosen = pc;

View File

@@ -261,12 +261,12 @@ public class CopyPermanentAi extends SpellAbilityAi {
}
@Override
protected GameEntity chooseSinglePlayerOrPlaneswalker(Player ai, SpellAbility sa, Iterable<GameEntity> options, Map<String, Object> params) {
protected GameEntity chooseSingleAttackableEntity(Player ai, SpellAbility sa, Iterable<GameEntity> options, Map<String, Object> params) {
if (params != null && params.containsKey("Attacker")) {
return ComputerUtilCombat.addAttackerToCombat(sa, (Card) params.get("Attacker"), options);
}
// should not be reached
return super.chooseSinglePlayerOrPlaneswalker(ai, sa, options, params);
return super.chooseSingleAttackableEntity(ai, sa, options, params);
}
}

View File

@@ -196,12 +196,12 @@ public class DigAi extends SpellAbilityAi {
}
@Override
protected GameEntity chooseSinglePlayerOrPlaneswalker(Player ai, SpellAbility sa, Iterable<GameEntity> options, Map<String, Object> params) {
protected GameEntity chooseSingleAttackableEntity(Player ai, SpellAbility sa, Iterable<GameEntity> options, Map<String, Object> params) {
if (params != null && params.containsKey("Attacker")) {
return ComputerUtilCombat.addAttackerToCombat(sa, (Card) params.get("Attacker"), options);
}
// should not be reached
return super.chooseSinglePlayerOrPlaneswalker(ai, sa, options, params);
return super.chooseSingleAttackableEntity(ai, sa, options, params);
}
/* (non-Javadoc)

View File

@@ -326,12 +326,12 @@ public class TokenAi extends SpellAbilityAi {
* @see forge.card.ability.SpellAbilityAi#chooseSinglePlayerOrPlaneswalker(forge.game.player.Player, forge.card.spellability.SpellAbility, Iterable<forge.game.GameEntity> options)
*/
@Override
protected GameEntity chooseSinglePlayerOrPlaneswalker(Player ai, SpellAbility sa, Iterable<GameEntity> options, Map<String, Object> params) {
protected GameEntity chooseSingleAttackableEntity(Player ai, SpellAbility sa, Iterable<GameEntity> options, Map<String, Object> params) {
if (params != null && params.containsKey("Attacker")) {
return ComputerUtilCombat.addAttackerToCombat(sa, (Card) params.get("Attacker"), options);
}
// should not be reached
return super.chooseSinglePlayerOrPlaneswalker(ai, sa, options, params);
return super.chooseSingleAttackableEntity(ai, sa, options, params);
}
/**

View File

@@ -1448,7 +1448,9 @@ public class GameAction {
if (game.getCombat() != null) {
game.getCombat().removeAbsentCombatants();
}
table.triggerChangesZoneAll(game, null);
if (!checkAgain) {
break; // do not continue the loop
}

View File

@@ -1,6 +1,7 @@
package forge.game.ability.effects;
import java.util.Collection;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
@@ -54,6 +55,24 @@ public class ManaReflectedEffect extends SpellAbilityEffect {
private static String generatedReflectedMana(final SpellAbility sa, final Collection<String> colors, final Player player) {
// Calculate generated mana here for stack description and resolving
final int amount = sa.hasParam("Amount") ? AbilityUtils.calculateAmount(sa.getHostCard(), sa.getParam("Amount"), sa) : 1;
final StringBuilder sb = new StringBuilder();
if (sa.getManaPart().isComboMana()) {
Map<Byte, Integer> choices = player.getController().specifyManaCombo(sa, ColorSet.fromNames(colors), amount, false);
for (Map.Entry<Byte, Integer> e : choices.entrySet()) {
Byte chosenColor = e.getKey();
String choice = MagicColor.toShortString(chosenColor);
Integer count = e.getValue();
while (count > 0) {
if (sb.length() > 0) {
sb.append(" ");
}
sb.append(choice);
--count;
}
}
return sb.toString();
}
String baseMana;
@@ -93,7 +112,6 @@ public class ManaReflectedEffect extends SpellAbilityEffect {
}
}
final StringBuilder sb = new StringBuilder();
if (amount == 0) {
sb.append("0");
} else {

View File

@@ -25,6 +25,7 @@ import forge.game.ability.AbilityUtils;
import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
import forge.game.card.CardFactoryUtil;
import forge.game.card.CardZoneTable;
import forge.game.cost.Cost;
@@ -109,13 +110,13 @@ public class PlayEffect extends SpellAbilityEffect {
}
CardCollection tgtCards;
CardCollection showCards = new CardCollection();
CardCollectionView showCards = new CardCollection();
if (sa.hasParam("Valid")) {
List<ZoneType> zones = sa.hasParam("ValidZone") ? ZoneType.listValueOf(sa.getParam("ValidZone")) : ImmutableList.of(ZoneType.Hand);
tgtCards = new CardCollection(AbilityUtils.filterListByType(game.getCardsIn(zones), sa.getParam("Valid"), sa));
if (sa.hasParam("ShowCards")) {
showCards = new CardCollection(AbilityUtils.filterListByType(game.getCardsIn(zones), sa.getParam("ShowCards"), sa));
showCards = AbilityUtils.filterListByType(game.getCardsIn(zones), sa.getParam("ShowCards"), sa);
}
} else if (sa.hasParam("AnySupportedCard")) {
final String valid = sa.getParam("AnySupportedCard");

View File

@@ -3180,7 +3180,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
// no Ability for this type yet, make a new one
if (sa == null) {
sa = CardFactoryUtil.buildBasicLandAbility(state, c);
sa = CardFactory.buildBasicLandAbility(state, c);
basicLandAbilities[i] = sa;
}

View File

@@ -380,6 +380,15 @@ public class CardFactory {
}
}
public static SpellAbility buildBasicLandAbility(final CardState state, byte color) {
String strcolor = MagicColor.toShortString(color);
String abString = "AB$ Mana | Cost$ T | Produced$ " + strcolor +
" | Secondary$ True | SpellDescription$ Add {" + strcolor + "}.";
SpellAbility sa = AbilityFactory.getAbility(abString, state);
sa.setIntrinsic(true); // always intrisic
return sa;
}
private static Card readCard(final CardRules rules, final IPaperCard paperCard, int cardId, Game game) {
final Card card = new Card(cardId, paperCard, game);

View File

@@ -89,15 +89,6 @@ import io.sentry.Sentry;
*/
public class CardFactoryUtil {
public static SpellAbility buildBasicLandAbility(final CardState state, byte color) {
String strcolor = MagicColor.toShortString(color);
String abString = "AB$ Mana | Cost$ T | Produced$ " + strcolor +
" | Secondary$ True | SpellDescription$ Add {" + strcolor + "}.";
SpellAbility sa = AbilityFactory.getAbility(abString, state);
sa.setIntrinsic(true); // always intrisic
return sa;
}
/**
* <p>
* abilityMorphDown.
@@ -3932,7 +3923,7 @@ public class CardFactoryUtil {
StringBuilder chooseSB = new StringBuilder();
chooseSB.append("Event$ Moved | ValidCard$ Card.Self | Destination$ Battlefield | ReplacementResult$ Updated");
chooseSB.append(" | Description$ (As a Siege enters the battlefield, choose an opponent to protect it. You and others can attack it. When it's defeated, exile it, then cast it transformed.)");
String chooseProtector = "DB$ ChoosePlayer | Defined$ You | Choices$ Opponent | Protect$ True | ChoiceTitle$ Choose an opponent to protect this battle | AILogic$ Curse";
String chooseProtector = "DB$ ChoosePlayer | Defined$ You | Choices$ Opponent | Protect$ True | ChoiceTitle$ Choose an opponent to protect this battle";
ReplacementEffect re = ReplacementHandler.parseReplacement(chooseSB.toString(), card, true);
re.setOverridingAbility(AbilityFactory.getAbility(chooseProtector, card));

View File

@@ -203,7 +203,7 @@ public final class CardUtil {
newCopy.getCurrentState().copyFrom(in.getState(in.getFaceupCardStateName()), true);
if (in.isFaceDown()) {
newCopy.turnFaceDownNoUpdate();
newCopy.setType(new CardType(in.getCurrentState().getType()));
newCopy.setType(new CardType(in.getFaceDownState().getType()));
// prevent StackDescription from revealing face
newCopy.updateStateForView();
}

View File

@@ -47,6 +47,8 @@ import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
import forge.game.card.CardDamageMap;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.card.CardUtil;
import forge.game.keyword.Keyword;
import forge.game.player.Player;
@@ -231,7 +233,11 @@ public class Combat {
}
public final CardCollection getDefendingPlaneswalkers() {
return new CardCollection(Iterables.filter(attackableEntries, Card.class));
return CardLists.filter(Iterables.filter(attackableEntries, Card.class), CardPredicates.isType("Planeswalker"));
}
public final CardCollection getDefendingBattles() {
return CardLists.filter(Iterables.filter(attackableEntries, Card.class), CardPredicates.isType("Battle"));
}
public final Map<Card, GameEntity> getAttackersAndDefenders() {
@@ -619,17 +625,17 @@ public class Combat {
}
}
for (Card pw : getDefendingPlaneswalkers()) {
if (pw.equals(c)) {
for (Card battleOrPW : Iterables.filter(attackableEntries, Card.class)) {
if (battleOrPW.equals(c)) {
Multimap<GameEntity, AttackingBand> attackerBuffer = ArrayListMultimap.create();
Collection<AttackingBand> bands = attackedByBands.get(c);
for (AttackingBand abPW : bands) {
unregisterDefender(c, abPW);
for (AttackingBand abDef : bands) {
unregisterDefender(c, abDef);
// Rule 506.4c workaround to keep creatures in combat
Card fake = new Card(-1, c.getGame());
fake.setName("<Nothing>");
fake.setController(c.getController(), 0);
attackerBuffer.put(fake, abPW);
attackerBuffer.put(fake, abDef);
}
bands.clear();
attackedByBands.putAll(attackerBuffer);

View File

@@ -5,7 +5,7 @@ A:AB$ Mana | Cost$ T | Produced$ Any | Amount$ 1 | SpellDescription$ Add one man
A:AB$ PutCounter | Cost$ T | CounterType$ CHARGE | CounterNum$ 1 | SpellDescription$ Put a charge counter on CARDNAME.
T:Mode$ Phase | PreCombatMain$ True | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigRemove | TriggerDescription$ At the beginning of your precombat main phase, remove all charge counters from CARDNAME. Add one mana of any color for each charge counter removed this way.
SVar:TrigRemove:DB$ RemoveCounter | CounterType$ CHARGE | CounterNum$ All | RememberRemoved$ True | SubAbility$ TrigGetMana
SVar:TrigGetMana:DB$ Mana | Produced$ Combo Any | Amount$ NumRemoved | AILogic$ MostProminentInComputerHand | SubAbility$ DBCleanup
SVar:TrigGetMana:DB$ Mana | Produced$ Combo Any | Amount$ NumRemoved | SubAbility$ DBCleanup
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
SVar:NumRemoved:Count$RememberedSize
Oracle:{T}: Add one mana of any color.\n{T}: Put a charge counter on Coalition Relic.\nAt the beginning of your precombat main phase, remove all charge counters from Coalition Relic. Add one mana of any color for each charge counter removed this way.

View File

@@ -3,7 +3,7 @@ ManaCost:BG
Types:Creature Elf Shaman
PT:1/2
A:AB$ ChangeZone | Cost$ T | Origin$ Graveyard | Destination$ Exile | ValidTgts$ Land | TgtPrompt$ Select target land card in a graveyard | SubAbility$ DBMana | SpellDescription$ Exile target land card from a graveyard. Add one mana of any color.
SVar:DBMana:DB$ Mana | Produced$ Any | Amount$ 1 | AILogic$ MostProminentInComputerHand
SVar:DBMana:DB$ Mana | Produced$ Any | Amount$ 1
A:AB$ ChangeZone | Cost$ B T | Origin$ Graveyard | Destination$ Exile | ValidTgts$ Instant,Sorcery | TgtPrompt$ Select target instant or sorcery card in a graveyard | SubAbility$ DBLoseLife | AITgtOwnCards$ True | SpellDescription$ Exile target instant or sorcery card from a graveyard. Each opponent loses 2 life.
SVar:DBLoseLife:DB$ LoseLife | Defined$ Player.Opponent | LifeAmount$ 2
A:AB$ ChangeZone | Cost$ G T | Origin$ Graveyard | Destination$ Exile | ValidTgts$ Creature | TgtPrompt$ Select target creature card in a graveyard | SubAbility$ DBGainLife | AITgtOwnCards$ True | SpellDescription$ Exile target creature card from a graveyard. You gain 2 life.

View File

@@ -3,7 +3,7 @@ ManaCost:4 U/B U/B
Types:Legendary Creature Demon Kraken
PT:6/6
K:Companion:Card.cmcM20:Your starting deck contains only cards with even mana value. (If this card is your chosen companion, you may cast it once from outside the game.)
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigMill | TriggerDescription$ When CARDNAME enters the battlefield, each player mills four cards. Put a creature card with an even mana value from those cards onto the battlefield under your control.
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigMill | TriggerDescription$ When NICKNAME enters the battlefield, each player mills four cards. Put a creature card with an even mana value from those cards onto the battlefield under your control.
SVar:TrigMill:DB$ Mill | NumCards$ 4 | Defined$ Player | RememberMilled$ True | SubAbility$ DBChangeZone
SVar:DBChangeZone:DB$ ChangeZone | Origin$ Graveyard,Exile | Destination$ Battlefield | GainControl$ True | Mandatory$ True | Hidden$ True | ChangeNum$ 1 | ChangeType$ Card.Creature+IsRemembered+cmcM20 | SubAbility$ DBCleanup
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True

View File

@@ -1,7 +1,7 @@
Name:Manamorphose
ManaCost:1 RG
Types:Instant
A:SP$ Mana | Cost$ 1 RG | Produced$ Combo Any | Amount$ 2 | AILogic$ MostProminentInComputerHand | SubAbility$ DBDraw | SpellDescription$ Add two mana in any combination of colors. Draw a card.
A:SP$ Mana | Cost$ 1 RG | Produced$ Combo Any | Amount$ 2 | SubAbility$ DBDraw | SpellDescription$ Add two mana in any combination of colors. Draw a card.
SVar:DBDraw:DB$ Draw | Defined$ You | NumCards$ 1
AI:RemoveDeck:All
Oracle:Add two mana in any combination of colors.\nDraw a card.

View File

@@ -4,6 +4,6 @@ Types:Instant
A:SP$ Counter | Cost$ G G U U | TargetType$ Spell | RememberCounteredCMC$ True | ValidTgts$ Card | SubAbility$ DBDelTrig | SpellDescription$ Counter target spell. At the beginning of your next precombat main phase, add X mana in any combination of colors, where X is that spell's mana value.
SVar:DBDelTrig:DB$ DelayedTrigger | Mode$ Phase | PreCombatMain$ True | ValidPlayer$ You | Execute$ AddMana | TriggerDescription$ At the beginning of your next precombat main phase, add X mana in any combination of colors, where X is that spell's mana value. | RememberNumber$ True | SubAbility$ DBCleanup
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
SVar:AddMana:DB$ Mana | Produced$ Combo Any | Amount$ X | AILogic$ MostProminentInComputerHand
SVar:AddMana:DB$ Mana | Produced$ Combo Any | Amount$ X
SVar:X:Count$TriggerRememberAmount
Oracle:Counter target spell. At the beginning of your next precombat main phase, add X mana in any combination of colors, where X is that spell's mana value.

View File

@@ -6,5 +6,5 @@ K:Trample
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigMonarch | TriggerDescription$ When CARDNAME enters the battlefield, you become the monarch.
SVar:TrigMonarch:DB$ BecomeMonarch | Defined$ You
T:Mode$ TapsForMana | ValidCard$ Land | Activator$ You | CheckDefinedPlayer$ You.isMonarch | Execute$ TrigMana | TriggerZones$ Battlefield | Static$ True | TriggerDescription$ Whenever you tap a land for mana while you're the monarch, add an additional one mana of any color.
SVar:TrigMana:DB$ Mana | Produced$ Combo Any | Amount$ 1 | AILogic$ MostProminentInComputerHand
SVar:TrigMana:DB$ Mana | Produced$ Combo Any | Amount$ 1
Oracle:Trample\nWhen Regal Behemoth enters the battlefield, you become the monarch.\nWhenever you tap a land for mana while you're the monarch, add an additional one mana of any color.

View File

@@ -3,9 +3,7 @@ ManaCost:B R G
Types:Instant
A:SP$ Charm | Choices$ DBSac,DBExilePlay,DBExileGrave
SVar:DBSac:DB$ Sacrifice | ValidTgts$ Opponent | TgtPrompt$ Choose target opponent | SacValid$ Creature.cmcEQX,Planeswalker.cmcEQX | SacMessage$ creature or planeswalker they control with the highest mana value among creatures and planeswalkers they control | SpellDescription$ Target opponent sacrifices a creature or planeswalker they control with the highest mana value among creatures and planeswalkers they control.
SVar:X:SVar$Y/LimitMin.Z
SVar:Y:Count$Valid Creature.TargetedPlayerCtrl$GreatestCMC
SVar:Z:Count$Valid Planeswalker.TargetedPlayerCtrl$GreatestCMC
SVar:X:Count$Valid Creature.TargetedPlayerCtrl,Planeswalker.TargetedPlayerCtrl$GreatestCMC
SVar:DBExilePlay:DB$ Dig | Defined$ You | DigNum$ 3 | ChangeNum$ All | DestinationZone$ Exile | RememberChanged$ True | SubAbility$ DBEffect | SpellDescription$ Exile the top three cards of your library. Until your next end step, you may play those cards.
SVar:DBEffect:DB$ Effect | RememberObjects$ RememberedCard | StaticAbilities$ STPlay | SubAbility$ DBCleanup | ForgetOnMoved$ Exile | Duration$ UntilYourNextEndStep
SVar:STPlay:Mode$ Continuous | MayPlay$ True | EffectZone$ Command | Affected$ Card.IsRemembered | AffectedZone$ Exile | Description$ Until your next end step, you may play those cards.

View File

@@ -3,7 +3,7 @@ ManaCost:2 G U R
Types:Legendary Planeswalker Sarkhan
Loyalty:4
A:AB$ Draw | Cost$ AddCounter<1/LOYALTY> | Defined$ You | SubAbility$ DBMana | Planeswalker$ True | SpellDescription$ Draw a card, then add one mana of any color.
SVar:DBMana:DB$ Mana | Produced$ Any | AILogic$ MostProminentInComputerHand
SVar:DBMana:DB$ Mana | Produced$ Any
A:AB$ Token | Cost$ SubCounter<2/LOYALTY> | TokenAmount$ 1 | TokenScript$ r_4_4_dragon_flying | TokenOwner$ You | Planeswalker$ True | SpellDescription$ Create a 4/4 red Dragon creature token with flying.
A:AB$ ChangeZone | Cost$ SubCounter<8/LOYALTY> | Origin$ Library | Destination$ Battlefield | ChangeType$ Creature.Dragon | ChangeNum$ XFetch | Planeswalker$ True | Ultimate$ True | StackDescription$ SpellDescription | SpellDescription$ Search your library for any number of Dragon creature cards, put them onto the battlefield, then shuffle.
SVar:XFetch:Count$TypeInYourLibrary.Dragon

View File

@@ -2,6 +2,6 @@ Name:Smokebraider
ManaCost:1 R
Types:Creature Elemental Shaman
PT:1/1
A:AB$ Mana | Cost$ T | Produced$ Combo Any | Amount$ 2 | RestrictValid$ Spell.Elemental,Activated.Elemental+inZoneBattlefield | AILogic$ MostProminentInComputerHand | SpellDescription$ Add two mana in any combination of colors. Spend this mana only to cast Elemental spells or activate abilities of Elementals.
A:AB$ Mana | Cost$ T | Produced$ Combo Any | Amount$ 2 | RestrictValid$ Spell.Elemental,Activated.Elemental+inZoneBattlefield | SpellDescription$ Add two mana in any combination of colors. Spend this mana only to cast Elemental spells or activate abilities of Elementals.
AI:RemoveDeck:Random
Oracle:{T}: Add two mana in any combination of colors. Spend this mana only to cast Elemental spells or activate abilities of Elementals.

View File

@@ -5,7 +5,5 @@ A:SP$ RepeatEach | RepeatPlayers$ Player.Opponent | RepeatSubAbility$ DBChoose |
SVar:DBChoose:DB$ ChooseCard | Defined$ Player.IsRemembered | Choices$ Creature.RememberedPlayerCtrl+cmcEQX,Planeswalker.RememberedPlayerCtrl+cmcEQX | ChoiceTitle$ Choose a creature or planeswalker with the highest mana value to sacrifice | Mandatory$ True | RememberChosen$ True
SVar:DBSac:DB$ SacrificeAll | ValidCards$ Card.IsRemembered | SubAbility$ DBCleanup | StackDescription$ sacrifices a creature or planeswalker with the highest mana value among creatures and planeswalkers they control.
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
SVar:X:SVar$Y/LimitMin.Z
SVar:Y:Count$Valid Creature.RememberedPlayerCtrl$GreatestCMC
SVar:Z:Count$Valid Planeswalker.RememberedPlayerCtrl$GreatestCMC
SVar:X:Count$Valid Creature.RememberedPlayerCtrl,Planeswalker.RememberedPlayerCtrl$GreatestCMC
Oracle:Each opponent sacrifices a creature or planeswalker with the highest mana value among creatures and planeswalkers they control.

View File

@@ -1,7 +1,7 @@
Name:Terrarion
ManaCost:1
Types:Artifact
A:AB$ Mana | Cost$ 2 T Sac<1/CARDNAME> | Produced$ Combo Any | Amount$ 2 | AILogic$ MostProminentInComputerHand | SpellDescription$ Add two mana in any combination of colors.
A:AB$ Mana | Cost$ 2 T Sac<1/CARDNAME> | Produced$ Combo Any | Amount$ 2 | SpellDescription$ Add two mana in any combination of colors.
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigDraw | TriggerDescription$ When CARDNAME is put into a graveyard from the battlefield, draw a card.
SVar:TrigDraw:DB$ Draw | Defined$ TriggeredCardController | NumCards$ 1
K:CARDNAME enters the battlefield tapped.

View File

@@ -23,7 +23,7 @@ SVar:Exile11:DB$ ChangeZone | ValidTgts$ Player | TgtPrompt$ Select target playe
SVar:Dig12:DB$ Dig | DigNum$ 1 | Reveal$ True | ChangeNum$ All | ChangeValid$ Land | DestinationZone$ Battlefield | DestinationZone2$ Hand | SpellDescription$ Reveal the top card of your library. If it's a land card, put it onto the battlefield. Otherwise, put it into your hand.
SVar:Animate13:DB$ Animate | ValidTgts$ Land.YouCtrl | TgtPrompt$ Select target land you control | Power$ 4 | Toughness$ 4 | Types$ Creature,Elemental | Duration$ Permanent | Keywords$ Trample | SpellDescription$ Target land you control becomes a 4/4 Elemental creature with trample. It's still a land.
SVar:Draw14:DB$ Draw | Defined$ You | SubAbility$ DBMana14 | SpellDescription$ Draw a card, then add one mana of any color.
SVar:DBMana14:DB$ Mana | Produced$ Any | AILogic$ MostProminentInComputerHand
SVar:DBMana14:DB$ Mana | Produced$ Any
SVar:Animate15:DB$ Animate | Power$ 4 | Toughness$ 4 | Types$ Creature,Legendary,Dragon | Colors$ Red | OverwriteColors$ True | RemoveCardTypes$ True | Keywords$ Flying & Indestructible & Haste | SpellDescription$ Until end of turn, NICKNAME becomes a legendary 4/4 red Dragon creature with flying, indestructible, and haste. (He doesn't lose loyalty while he's not a planeswalker.)
SVar:PumpAll16:DB$ PumpAll | ValidCards$ Creature.YouCtrl | NumAtt$ +1 | KW$ Lifelink | Duration$ UntilYourNextTurn | SpellDescription$ Until your next turn, creatures you control get +1/+0 and gain lifelink.
SVar:Dig17:DB$ Dig | DigNum$ 5 | ChangeNum$ 1 | Optional$ True | ChangeValid$ Artifact | SpellDescription$ Look at the top five cards of your library. You may reveal an artifact card from among them and put it into your hand. Put the rest on the bottom of your library in any order.

View File

@@ -4,11 +4,11 @@ Types:Legendary Creature Phyrexian Elemental
PT:4/4
R:Event$ LoseMana | ValidPlayer$ You | ReplacementResult$ Replaced | ReplaceWith$ ConvertMana | ActiveZones$ Battlefield | Description$ If you would lose unspent mana, that mana becomes black instead.
SVar:ConvertMana:DB$ ReplaceMana | ReplaceType$ Black
T:Mode$ Phase | ValidPlayer$ You | Phase$ Main1 | TriggerZones$ Battlefield | Execute$ TrigPeek | TriggerDescription$ At the beginning of your precombat main phase, look at the top card of your library. You may reveal that card if it has three or more colored mana symbols in its mana cost. If you do, add three mana in any combination of colors and put it into your hand. If you don't reveal it, put it into your hand.
T:Mode$ Phase | ValidPlayer$ You | Phase$ Main1 | TriggerZones$ Battlefield | Execute$ TrigPeek | TriggerDescription$ At the beginning of your precombat main phase, look at the top card of your library. You may reveal that card if it has three or more colored mana symbols in its mana cost. If you do, add three mana in any combination of its colors and put it into your hand. If you don't reveal it, put it into your hand.
SVar:TrigPeek:DB$ PeekAndReveal | Defined$ You | NoReveal$ True | RememberPeeked$ True | SubAbility$ DBReveal
SVar:DBReveal:DB$ PeekAndReveal | Defined$ You | NoPeek$ True | RevealOptional$ True | ImprintRevealed$ True | ConditionCheckSVar$ ColorAmount | ConditionSVarCompare$ GE3 | SubAbility$ DBMana
SVar:DBMana:DB$ Mana | Produced$ Combo Any | Amount$ 3 | ConditionDefined$ Imprinted | ConditionPresent$ Card | SubAbility$ DBMove
SVar:DBMana:DB$ ManaReflected | Produced$ Combo | ReflectProperty$ Is | ColorOrType$ Color | Amount$ 3 | Valid$ Defined.Imprinted | ConditionDefined$ Imprinted | ConditionPresent$ Card | SubAbility$ DBMove
SVar:DBMove:DB$ ChangeZone | Origin$ Library | Destination$ Hand | Defined$ Remembered | SubAbility$ DBCleanup
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True | ClearImprinted$ True
SVar:ColorAmount:Remembered$ChromaSource
Oracle:If you would lose unspent mana, that mana becomes black instead.\nAt the beginning of your precombat main phase, look at the top card of your library. You may reveal that card if it has three or more colored mana symbols in its mana cost. If you do, add three mana in any combination of colors and put it into your hand. If you don't reveal it, put it into your hand.
Oracle:If you would lose unspent mana, that mana becomes black instead.\nAt the beginning of your precombat main phase, look at the top card of your library. You may reveal that card if it has three or more colored mana symbols in its mana cost. If you do, add three mana in any combination of its colors and put it into your hand. If you don't reveal it, put it into your hand.

View File

@@ -6,7 +6,7 @@ S:Mode$ Continuous | Affected$ Land.YouCtrl | AddAbility$ AnyMana | Description$
SVar:AnyMana:AB$ Mana | Cost$ T | Produced$ Any | Amount$ 1 | SpellDescription$ Add one mana of any color.
A:AB$ Animate | Cost$ AddCounter<1/LOYALTY> | Planeswalker$ True | ValidTgts$ Land.YouCtrl | TargetMin$ 0 | TargetMax$ 1 | TgtPrompt$ Select up to one target land you control | Power$ 3 | Toughness$ 3 | Types$ Creature,Elemental | Keywords$ Vigilance & Hexproof & Haste | Duration$ UntilYourNextTurn | SpellDescription$ Up to one target land you control becomes a 3/3 Elemental creature with vigilance, hexproof, and haste until your next turn. It's still a land.
A:AB$ Mill | Cost$ SubCounter<2/LOYALTY> | Planeswalker$ True | NumCards$ 3 | RememberMilled$ True | SubAbility$ DBChangeZone | SpellDescription$ Mill three cards. You may put a permanent card from among the milled cards into your hand.
SVar:DBChangeZone:DB$ ChangeZone | Origin$ Graveyard | Destination$ Hand | Hidden$ True | ChangeNum$ 1 | ChangeType$ Card.Permanent+IsRemembered | SubAbility$ DBCleanup
SVar:DBChangeZone:DB$ ChangeZone | Origin$ Graveyard,Exile | Destination$ Hand | Hidden$ True | ChangeNum$ 1 | ChangeType$ Card.Permanent+IsRemembered | SubAbility$ DBCleanup
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
A:AB$ Effect | Cost$ SubCounter<7/LOYALTY> | Planeswalker$ True | Ultimate$ True | Name$ Emblem - Wrenn and Realmbreaker | Image$ emblem_wrenn_and_realmbreaker | StaticAbilities$ PermanentRecycle | Stackable$ False | Duration$ Permanent | AILogic$ Always | SpellDescription$ You get an emblem with "You may play lands and cast permanent spells from your graveyard."
SVar:PermanentRecycle:Mode$ Continuous | EffectZone$ Command | Affected$ Card.Permanent+YouOwn | MayPlay$ True | AffectedZone$ Graveyard | Description$ You may play lands and cast permanent spells from your graveyard.