mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-19 04:08:01 +00:00
Merge branch 'master' of https://git.cardforge.org/core-developers/forge.git
This commit is contained in:
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<artifactId>forge</artifactId>
|
||||
<groupId>forge</groupId>
|
||||
<version>1.6.25-SNAPSHOT</version>
|
||||
<version>1.6.26-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>forge-ai</artifactId>
|
||||
|
||||
@@ -191,6 +191,27 @@ public class AiAttackController {
|
||||
return false;
|
||||
}
|
||||
|
||||
// the attacker will die to a triggered ability (e.g. Sarkhan the Masterless)
|
||||
for (Card c : ai.getOpponents().getCardsIn(ZoneType.Battlefield)) {
|
||||
for (Trigger t : c.getTriggers()) {
|
||||
if (t.getMode() == TriggerType.Attacks) {
|
||||
SpellAbility sa = t.getOverridingAbility();
|
||||
if (sa == null && t.hasParam("Execute")) {
|
||||
sa = AbilityFactory.getAbility(c, t.getParam("Execute"));
|
||||
}
|
||||
|
||||
if (sa != null && sa.getApi() == ApiType.EachDamage && "TriggeredAttacker".equals(sa.getParam("DefinedPlayers"))) {
|
||||
List<Card> valid = CardLists.getValidCards(c.getController().getCreaturesInPlay(), sa.getParam("ValidCards"), c.getController(), c, sa);
|
||||
// TODO: this assumes that 1 damage is dealt per creature. Improve this to check the parameter/X to determine
|
||||
// how much damage is dealt by each of the creatures in the valid list.
|
||||
if (attacker.getNetToughness() <= valid.size()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ("TRUE".equals(attacker.getSVar("HasAttackEffect"))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -129,7 +129,10 @@ public enum AiProps { /** */
|
||||
FLASH_USE_BUFF_AURAS_AS_COMBAT_TRICKS("true"),
|
||||
FLASH_BUFF_AURA_CHANCE_TO_CAST_EARLY("1"),
|
||||
FLASH_BUFF_AURA_CHANCE_CAST_AT_EOT("5"),
|
||||
FLASH_BUFF_AURA_CHANCE_TO_RESPOND_TO_STACK("100"); /** */
|
||||
FLASH_BUFF_AURA_CHANCE_TO_RESPOND_TO_STACK("100"),
|
||||
BLINK_RELOAD_PLANESWALKER_CHANCE("30"), /** */
|
||||
BLINK_RELOAD_PLANESWALKER_MAX_LOYALTY("2"), /** */
|
||||
BLINK_RELOAD_PLANESWALKER_LOYALTY_DIFF("2"); /** */
|
||||
// Experimental features, must be promoted or removed after extensive testing and, ideally, defaulting
|
||||
// <-- There are no experimental options here -->
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ import forge.game.spellability.AbilitySub;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.spellability.TargetRestrictions;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.util.MyRandom;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.*;
|
||||
@@ -676,7 +677,8 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
||||
}
|
||||
|
||||
// only use blink or bounce effects
|
||||
if (!(destination.equals(ZoneType.Exile) && (subApi == ApiType.DelayedTrigger || subApi == ApiType.ChangeZone))
|
||||
if (!(destination.equals(ZoneType.Exile)
|
||||
&& (subApi == ApiType.DelayedTrigger || subApi == ApiType.ChangeZone || "DelayedBlink".equals(sa.getParam("AILogic"))))
|
||||
&& !destination.equals(ZoneType.Hand)) {
|
||||
return false;
|
||||
}
|
||||
@@ -936,7 +938,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
||||
|
||||
// if it's blink or bounce, try to save my about to die stuff
|
||||
final boolean blink = (destination.equals(ZoneType.Exile) && (subApi == ApiType.DelayedTrigger
|
||||
|| (subApi == ApiType.ChangeZone && subAffected.equals("Remembered"))));
|
||||
|| "DelayedBlink".equals(sa.getParam("AILogic")) || (subApi == ApiType.ChangeZone && subAffected.equals("Remembered"))));
|
||||
if ((destination.equals(ZoneType.Hand) || blink) && (tgt.getMinTargets(sa.getHostCard(), sa) <= 1)) {
|
||||
// save my about to die stuff
|
||||
Card tobounce = canBouncePermanent(ai, sa, list);
|
||||
@@ -1230,6 +1232,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
||||
// filter out untargetables
|
||||
CardCollectionView aiPermanents = CardLists
|
||||
.filterControlledBy(list, ai);
|
||||
CardCollection aiPlaneswalkers = CardLists.filter(aiPermanents, Presets.PLANESWALKERS);
|
||||
|
||||
// Felidar Guardian + Saheeli Rai combo support
|
||||
if (sa.getHostCard().getName().equals("Felidar Guardian")) {
|
||||
@@ -1273,6 +1276,33 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Reload planeswalkers
|
||||
else if (!aiPlaneswalkers.isEmpty() && (sa.getHostCard().isSorcery() || !game.getPhaseHandler().isPlayerTurn(ai))) {
|
||||
int maxLoyaltyToConsider = 2;
|
||||
int loyaltyDiff = 2;
|
||||
int chance = 30;
|
||||
if (ai.getController().isAI()) {
|
||||
AiController aic = ((PlayerControllerAi) ai.getController()).getAi();
|
||||
maxLoyaltyToConsider = aic.getIntProperty(AiProps.BLINK_RELOAD_PLANESWALKER_MAX_LOYALTY);
|
||||
loyaltyDiff = aic.getIntProperty(AiProps.BLINK_RELOAD_PLANESWALKER_LOYALTY_DIFF);
|
||||
chance = aic.getIntProperty(AiProps.BLINK_RELOAD_PLANESWALKER_CHANCE);
|
||||
}
|
||||
if (MyRandom.percentTrue(chance)) {
|
||||
Collections.sort(aiPlaneswalkers, new Comparator<Card>() {
|
||||
@Override
|
||||
public int compare(final Card a, final Card b) {
|
||||
return a.getCounters(CounterType.LOYALTY) - b.getCounters(CounterType.LOYALTY);
|
||||
}
|
||||
});
|
||||
for (Card pw : aiPlaneswalkers) {
|
||||
int curLoyalty = pw.getCounters(CounterType.LOYALTY);
|
||||
int freshLoyalty = pw.getCurrentState().getBaseLoyalty();
|
||||
if (freshLoyalty - curLoyalty >= loyaltyDiff && curLoyalty <= maxLoyaltyToConsider) {
|
||||
return pw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -75,7 +75,7 @@ public class DamageDealAi extends DamageAiBase {
|
||||
|
||||
// Set PayX here to maximum value.
|
||||
dmg = ComputerUtilMana.determineLeftoverMana(sa, ai);
|
||||
source.setSVar("PayX", Integer.toString(dmg));
|
||||
sa.setSVar("PayX", Integer.toString(dmg));
|
||||
} else if (sa.getSVar(damage).equals("Count$CardsInYourHand") && source.getZone().is(ZoneType.Hand)) {
|
||||
dmg--; // the card will be spent casting the spell, so actual damage is 1 less
|
||||
}
|
||||
@@ -115,7 +115,7 @@ public class DamageDealAi extends DamageAiBase {
|
||||
}
|
||||
|
||||
// Set PayX here to maximum value. It will be adjusted later depending on the target.
|
||||
source.setSVar("PayX", Integer.toString(dmg));
|
||||
sa.setSVar("PayX", Integer.toString(dmg));
|
||||
} else if (sa.getSVar(damage).contains("InYourHand") && source.getZone().is(ZoneType.Hand)) {
|
||||
dmg = CardFactoryUtil.xCount(source, sa.getSVar(damage)) - 1; // the card will be spent casting the spell, so actual damage is 1 less
|
||||
} else if (sa.getSVar(damage).equals("TargetedPlayer$CardsInHand")) {
|
||||
@@ -283,7 +283,7 @@ public class DamageDealAi extends DamageAiBase {
|
||||
if (sourceName.equals("Crater's Claws") && ai.hasFerocious()) {
|
||||
actualPay = actualPay > 2 ? actualPay - 2 : 0;
|
||||
}
|
||||
source.setSVar("PayX", Integer.toString(actualPay));
|
||||
sa.setSVar("PayX", Integer.toString(actualPay));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -291,7 +291,7 @@ public class DamageDealAi extends DamageAiBase {
|
||||
// Check to ensure that we have enough counters to remove per the defined PayX
|
||||
for (CostPart part : sa.getPayCosts().getCostParts()) {
|
||||
if (part instanceof CostRemoveCounter) {
|
||||
if (source.getCounters(((CostRemoveCounter) part).counter) < Integer.valueOf(source.getSVar("PayX"))) {
|
||||
if (source.getCounters(((CostRemoveCounter) part).counter) < Integer.valueOf(sa.getSVar("PayX"))) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
@@ -941,7 +941,7 @@ public class DamageDealAi extends DamageAiBase {
|
||||
if (damage.equals("X") && sa.getSVar(damage).equals("Count$xPaid")) {
|
||||
// Set PayX here to maximum value.
|
||||
dmg = ComputerUtilMana.determineLeftoverMana(sa, ai);
|
||||
source.setSVar("PayX", Integer.toString(dmg));
|
||||
sa.setSVar("PayX", Integer.toString(dmg));
|
||||
}
|
||||
|
||||
final TargetRestrictions tgt = sa.getTargetRestrictions();
|
||||
@@ -971,7 +971,7 @@ public class DamageDealAi extends DamageAiBase {
|
||||
}
|
||||
}
|
||||
|
||||
source.setSVar("PayX", Integer.toString(actualPay));
|
||||
sa.setSVar("PayX", Integer.toString(actualPay));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1031,7 +1031,7 @@ public class DamageDealAi extends DamageAiBase {
|
||||
saTgt.resetTargets();
|
||||
saTgt.getTargets().add(tgtCreature != null && dmg < opponent.getLife() ? tgtCreature : opponent);
|
||||
|
||||
source.setSVar("PayX", Integer.toString(dmg));
|
||||
sa.setSVar("PayX", Integer.toString(dmg));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
package forge.ai.ability;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import forge.ai.*;
|
||||
import forge.game.Game;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.CardCollection;
|
||||
import forge.game.card.CardLists;
|
||||
import forge.game.keyword.Keyword;
|
||||
import forge.game.phase.PhaseType;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.player.PlayerActionConfirmMode;
|
||||
@@ -126,6 +130,25 @@ public class DigAi extends SpellAbilityAi {
|
||||
|
||||
@Override
|
||||
public Card chooseSingleCard(Player ai, SpellAbility sa, Iterable<Card> valid, boolean isOptional, Player relatedPlayer) {
|
||||
if ("DigForCreature".equals(sa.getParam("AILogic"))) {
|
||||
Card bestChoice = ComputerUtilCard.getBestCreatureAI(valid);
|
||||
if (bestChoice == null) {
|
||||
// no creatures, but maybe there's a morphable card that can be played as a creature?
|
||||
CardCollection morphs = CardLists.filter(valid, new Predicate<Card>() {
|
||||
@Override
|
||||
public boolean apply(Card card) {
|
||||
return card.hasKeyword(Keyword.MORPH);
|
||||
}
|
||||
});
|
||||
if (!morphs.isEmpty()) {
|
||||
bestChoice = ComputerUtilCard.getBestAI(morphs);
|
||||
}
|
||||
}
|
||||
|
||||
// still nothing, so return the worst card since it'll be unplayable from exile (e.g. Vivien, Champion of the Wilds)
|
||||
return bestChoice != null ? bestChoice : ComputerUtilCard.getWorstAI(valid);
|
||||
}
|
||||
|
||||
if (sa.getActivatingPlayer().isOpponentOf(ai) && relatedPlayer.isOpponentOf(ai)) {
|
||||
return ComputerUtilCard.getWorstPermanentAI(valid, false, true, false, false);
|
||||
} else {
|
||||
|
||||
@@ -211,9 +211,11 @@ public class DrawAi extends SpellAbilityAi {
|
||||
|
||||
private boolean targetAI(final Player ai, final SpellAbility sa, final boolean mandatory) {
|
||||
final Card source = sa.getHostCard();
|
||||
final boolean drawback = sa.getParent() != null;
|
||||
final Game game = ai.getGame();
|
||||
final String logic = sa.getParamOrDefault("AILogic", "");
|
||||
final boolean considerPrimary = logic.equals("ConsiderPrimary");
|
||||
final boolean drawback = (sa.getParent() != null) && !considerPrimary;
|
||||
boolean assumeSafeX = false; // if true, the AI will assume that the X value has been set to a value that is safe to draw
|
||||
|
||||
int computerHandSize = ai.getCardsIn(ZoneType.Hand).size();
|
||||
final int computerLibrarySize = ai.getCardsIn(ZoneType.Library).size();
|
||||
@@ -241,7 +243,12 @@ public class DrawAi extends SpellAbilityAi {
|
||||
numCards = Integer.parseInt(source.getSVar("PayX"));
|
||||
} else {
|
||||
numCards = ComputerUtilMana.determineLeftoverMana(sa, ai);
|
||||
// try not to overdraw
|
||||
int safeDraw = Math.min(computerMaxHandSize - computerHandSize, computerLibrarySize - 3);
|
||||
if (sa.getHostCard().isInstant() || sa.getHostCard().isSorcery()) { safeDraw++; } // card will be spent
|
||||
numCards = Math.min(numCards, safeDraw);
|
||||
source.setSVar("PayX", Integer.toString(numCards));
|
||||
assumeSafeX = true;
|
||||
}
|
||||
xPaid = true;
|
||||
}
|
||||
@@ -492,7 +499,8 @@ public class DrawAi extends SpellAbilityAi {
|
||||
|
||||
if ((computerHandSize + numCards > computerMaxHandSize)
|
||||
&& game.getPhaseHandler().isPlayerTurn(ai)
|
||||
&& !sa.isTrigger()) {
|
||||
&& !sa.isTrigger()
|
||||
&& !assumeSafeX) {
|
||||
// Don't draw too many cards and then risk discarding cards at
|
||||
// EOT
|
||||
if (!drawback) {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<artifactId>forge</artifactId>
|
||||
<groupId>forge</groupId>
|
||||
<version>1.6.25-SNAPSHOT</version>
|
||||
<version>1.6.26-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>forge-core</artifactId>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<artifactId>forge</artifactId>
|
||||
<groupId>forge</groupId>
|
||||
<version>1.6.25-SNAPSHOT</version>
|
||||
<version>1.6.26-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>forge-game</artifactId>
|
||||
|
||||
@@ -185,8 +185,7 @@ public class GameAction {
|
||||
// all sort of funky shenanigans may happen later (e.g. their ETB replacement effects are set
|
||||
// up on the wrong card state etc.).
|
||||
if (wasFacedown && (fromBattlefield || (toHand && zoneFrom.is(ZoneType.Exile)))) {
|
||||
c.setState(CardStateName.Original, true);
|
||||
c.runFaceupCommands();
|
||||
c.turnFaceUp();
|
||||
}
|
||||
|
||||
if (!c.isToken()) {
|
||||
@@ -445,13 +444,9 @@ public class GameAction {
|
||||
|
||||
// rule 504.6: reveal a face-down card leaving the stack
|
||||
if (zoneFrom != null && zoneTo != null && zoneFrom.is(ZoneType.Stack) && !zoneTo.is(ZoneType.Battlefield) && wasFacedown) {
|
||||
// FIXME: tracker freeze-unfreeze is needed here to avoid a bug with the card staying face down in the View for the reveal
|
||||
boolean trackerFrozen = game.getTracker().isFrozen();
|
||||
game.getTracker().unfreeze();
|
||||
c.setState(CardStateName.Original, true);
|
||||
reveal(new CardCollection(c), c.getOwner(), true, "Face-down card moves from the stack: ");
|
||||
c.setState(CardStateName.FaceDown, true);
|
||||
if (trackerFrozen) { game.getTracker().freeze(); }
|
||||
Card revealLKI = CardUtil.getLKICopy(c);
|
||||
revealLKI.turnFaceUp(true, false);
|
||||
reveal(new CardCollection(revealLKI), revealLKI.getOwner(), true, "Face-down card moves from the stack: ");
|
||||
}
|
||||
|
||||
if (fromBattlefield) {
|
||||
@@ -480,13 +475,11 @@ public class GameAction {
|
||||
}
|
||||
// Reveal if face-down
|
||||
if (wasFacedown) {
|
||||
// FIXME: tracker freeze-unfreeze is needed here to avoid a bug with the card staying face down in the View for the reveal
|
||||
boolean trackerFrozen = game.getTracker().isFrozen();
|
||||
game.getTracker().unfreeze();
|
||||
c.setState(CardStateName.Original, true);
|
||||
reveal(new CardCollection(c), c.getOwner(), true, "Face-down card leaves the battlefield: ");
|
||||
c.setState(CardStateName.FaceDown, true);
|
||||
if (trackerFrozen) { game.getTracker().freeze(); }
|
||||
Card revealLKI = CardUtil.getLKICopy(c);
|
||||
revealLKI.turnFaceUp(true, false);
|
||||
|
||||
reveal(new CardCollection(revealLKI), revealLKI.getOwner(), true, "Face-down card leaves the battlefield: ");
|
||||
|
||||
copied.setState(CardStateName.Original, true);
|
||||
}
|
||||
unattachCardLeavingBattlefield(copied);
|
||||
|
||||
@@ -72,6 +72,17 @@ public final class GameActionUtil {
|
||||
|
||||
if (sa.isSpell()) {
|
||||
boolean lkicheck = false;
|
||||
|
||||
// need to be done before so it works with Vivien and Zoetic Cavern
|
||||
if (source.isFaceDown() && source.isInZone(ZoneType.Exile)) {
|
||||
if (!source.isLKI()) {
|
||||
source = CardUtil.getLKICopy(source);
|
||||
}
|
||||
|
||||
source.turnFaceUp(false, false);
|
||||
lkicheck = true;
|
||||
}
|
||||
|
||||
if (sa.hasParam("Bestow") && !source.isBestowed() && !source.isInZone(ZoneType.Battlefield)) {
|
||||
if (!source.isLKI()) {
|
||||
source = CardUtil.getLKICopy(source);
|
||||
@@ -106,23 +117,16 @@ public final class GameActionUtil {
|
||||
}
|
||||
final Card host = o.getHost();
|
||||
|
||||
final SpellAbility newSA = sa.copy(activator);
|
||||
final SpellAbilityRestriction sar = newSA.getRestrictions();
|
||||
if (o.isWithFlash()) {
|
||||
sar.setInstantSpeed(true);
|
||||
}
|
||||
sar.setZone(null);
|
||||
newSA.setMayPlay(o.getAbility());
|
||||
newSA.setMayPlayOriginal(sa);
|
||||
SpellAbility newSA = null;
|
||||
|
||||
boolean changedManaCost = false;
|
||||
if (o.getPayManaCost() == PayManaCost.NO) {
|
||||
newSA = sa.copyWithNoManaCost(activator);
|
||||
newSA.setBasicSpell(false);
|
||||
newSA.setPayCosts(newSA.getPayCosts().copyWithNoMana());
|
||||
changedManaCost = true;
|
||||
} else if (o.getAltManaCost() != null) {
|
||||
newSA = sa.copyWithManaCostReplaced(activator, o.getAltManaCost());
|
||||
newSA.setBasicSpell(false);
|
||||
newSA.setPayCosts(newSA.getPayCosts().copyWithDefinedMana(o.getAltManaCost()));
|
||||
changedManaCost = true;
|
||||
if (host.hasSVar("AsForetoldSplitCMCHack")) {
|
||||
// TODO: This is a temporary workaround for As Foretold interaction with split cards, better solution needed.
|
||||
@@ -138,7 +142,17 @@ public final class GameActionUtil {
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
newSA = sa.copy(activator);
|
||||
}
|
||||
final SpellAbilityRestriction sar = newSA.getRestrictions();
|
||||
if (o.isWithFlash()) {
|
||||
sar.setInstantSpeed(true);
|
||||
}
|
||||
sar.setZone(null);
|
||||
newSA.setMayPlay(o.getAbility());
|
||||
newSA.setMayPlayOriginal(sa);
|
||||
|
||||
if (changedManaCost) {
|
||||
if ("0".equals(sa.getParam("ActivationLimit")) && sa.getHostCard().getManaCost().isNoCost()) {
|
||||
sar.setLimitToCheck(null);
|
||||
|
||||
@@ -2,7 +2,6 @@ package forge.game.ability.effects;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
import forge.card.CardStateName;
|
||||
import forge.game.Game;
|
||||
import forge.game.GlobalRuleChange;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
@@ -43,7 +42,7 @@ public class ManifestEffect extends SpellAbilityEffect {
|
||||
//check if lki would be a land entering the battlefield
|
||||
if (game.getStaticEffects().getGlobalRuleChange(GlobalRuleChange.noLandBattlefield)) {
|
||||
Card lki = CardUtil.getLKICopy(c);
|
||||
lki.setState(CardStateName.FaceDown, false);
|
||||
lki.turnFaceDownNoUpdate();
|
||||
lki.setManifested(true);
|
||||
lki.setLastKnownZone(p.getZone(ZoneType.Battlefield));
|
||||
CardCollection preList = new CardCollection(lki);
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package forge.game.ability.effects;
|
||||
|
||||
import forge.card.CardStateName;
|
||||
import forge.game.Game;
|
||||
import forge.game.GameLogEntryType;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
@@ -64,7 +63,7 @@ public class MillEffect extends SpellAbilityEffect {
|
||||
for (final Card c : milled) {
|
||||
c.setExiledWith(host);
|
||||
if (facedown) {
|
||||
c.setState(CardStateName.FaceDown, true);
|
||||
c.turnFaceDown(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@ import com.google.common.collect.Lists;
|
||||
import forge.GameCommand;
|
||||
import forge.StaticData;
|
||||
import forge.card.CardRulesPredicates;
|
||||
import forge.card.CardStateName;
|
||||
import forge.game.Game;
|
||||
import forge.game.ability.AbilityFactory;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
@@ -153,7 +152,7 @@ public class PlayEffect extends SpellAbilityEffect {
|
||||
|
||||
final boolean wasFaceDown;
|
||||
if (tgtCard.isFaceDown()) {
|
||||
tgtCard.setState(CardStateName.Original, false);
|
||||
tgtCard.turnFaceUp(false, false);
|
||||
wasFaceDown = true;
|
||||
} else {
|
||||
wasFaceDown = false;
|
||||
@@ -165,7 +164,7 @@ public class PlayEffect extends SpellAbilityEffect {
|
||||
|
||||
if (optional && !controller.getController().confirmAction(sa, null, TextUtil.concatWithSpace("Do you want to play", TextUtil.addSuffix(tgtCard.toString(),"?")))) {
|
||||
if (wasFaceDown) {
|
||||
tgtCard.setState(CardStateName.FaceDown, false);
|
||||
tgtCard.turnFaceDownNoUpdate();
|
||||
}
|
||||
saidNoTo.add(tgtCard);
|
||||
continue;
|
||||
|
||||
@@ -7,6 +7,7 @@ import forge.game.GameLogEntryType;
|
||||
import forge.game.ability.SpellAbilityEffect;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.CardCollection;
|
||||
import forge.game.card.CardUtil;
|
||||
import forge.game.card.CounterType;
|
||||
import forge.game.event.GameEventCardStatsChanged;
|
||||
import forge.game.player.Player;
|
||||
@@ -73,13 +74,9 @@ public class SetStateEffect extends SpellAbilityEffect {
|
||||
// facedown cards that are not Permanent, can't turn faceup there
|
||||
if ("TurnFace".equals(mode) && tgt.isFaceDown() && tgt.isInZone(ZoneType.Battlefield)
|
||||
&& !tgt.getState(CardStateName.Original).getType().isPermanent()) {
|
||||
// need to cache manifest status
|
||||
boolean manifested = tgt.isManifested();
|
||||
// FIXME setState has to many other Consequences, use LKI?
|
||||
tgt.setState(CardStateName.Original, true);
|
||||
game.getAction().reveal(new CardCollection(tgt), tgt.getOwner(), true, "Face-down card can't turn face up");
|
||||
tgt.setState(CardStateName.FaceDown, true);
|
||||
tgt.setManifested(manifested);
|
||||
Card lki = CardUtil.getLKICopy(tgt);
|
||||
lki.turnFaceUp(true, false);
|
||||
game.getAction().reveal(new CardCollection(lki), lki.getOwner(), true, "Face-down card can't turn face up");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -2743,7 +2743,7 @@ public class Card extends GameEntity implements Comparable<Card> {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
public final void setMayPlay(final Player player, final boolean withoutManaCost, final String altManaCost, final boolean withFlash, final boolean grantZonePermissions, final StaticAbility sta) {
|
||||
public final void setMayPlay(final Player player, final boolean withoutManaCost, final Cost altManaCost, final boolean withFlash, final boolean grantZonePermissions, final StaticAbility sta) {
|
||||
this.mayPlay.put(sta, new CardPlayOption(player, sta, withoutManaCost, altManaCost, withFlash, grantZonePermissions));
|
||||
}
|
||||
public final void removeMayPlay(final StaticAbility sta) {
|
||||
@@ -5803,7 +5803,7 @@ public class Card extends GameEntity implements Comparable<Card> {
|
||||
abilities.addAll(GameActionUtil.getAlternativeCosts(sa, player));
|
||||
}
|
||||
|
||||
if (isFaceDown() && isInZone(ZoneType.Exile) && !mayPlay(player).isEmpty()) {
|
||||
if (isFaceDown() && isInZone(ZoneType.Exile)) {
|
||||
for (final SpellAbility sa : getState(CardStateName.Original).getSpellAbilities()) {
|
||||
abilities.addAll(GameActionUtil.getAlternativeCosts(sa, player));
|
||||
}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
package forge.game.card;
|
||||
|
||||
import forge.card.mana.ManaCost;
|
||||
import forge.card.mana.ManaCostParser;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import forge.game.cost.Cost;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.staticability.StaticAbility;
|
||||
|
||||
@@ -20,12 +19,12 @@ public final class CardPlayOption {
|
||||
private final PayManaCost payManaCost;
|
||||
private final boolean withFlash;
|
||||
private final boolean grantsZonePermissions;
|
||||
private final String altManaCost;
|
||||
private final Cost altManaCost;
|
||||
|
||||
public CardPlayOption(final Player player, final StaticAbility sta, final boolean withoutManaCost, final String altManaCost, final boolean withFlash, final boolean grantZonePermissions) {
|
||||
public CardPlayOption(final Player player, final StaticAbility sta, final boolean withoutManaCost, final Cost altManaCost, final boolean withFlash, final boolean grantZonePermissions) {
|
||||
this(player, sta, withoutManaCost ? PayManaCost.NO : PayManaCost.YES, altManaCost, withFlash, grantZonePermissions);
|
||||
}
|
||||
private CardPlayOption(final Player player, final StaticAbility sta, final PayManaCost payManaCost, final String altManaCost, final boolean withFlash,
|
||||
private CardPlayOption(final Player player, final StaticAbility sta, final PayManaCost payManaCost, final Cost altManaCost, final boolean withFlash,
|
||||
final boolean grantZonePermissions) {
|
||||
this.player = player;
|
||||
this.sta = sta;
|
||||
@@ -66,10 +65,10 @@ public final class CardPlayOption {
|
||||
|
||||
public boolean grantsZonePermissions() { return grantsZonePermissions; }
|
||||
|
||||
public String getAltManaCost() { return altManaCost; }
|
||||
public Cost getAltManaCost() { return altManaCost; }
|
||||
|
||||
private String getFormattedAltManaCost() {
|
||||
return new ManaCost(new ManaCostParser(altManaCost)).getSimpleString();
|
||||
return altManaCost.toSimpleString();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -371,13 +371,18 @@ public class CardView extends GameEntityView {
|
||||
switch (zone) {
|
||||
case Ante:
|
||||
case Command:
|
||||
case Exile:
|
||||
case Battlefield:
|
||||
case Graveyard:
|
||||
case Flashback:
|
||||
case Stack:
|
||||
//cards in these zones are visible to all
|
||||
return true;
|
||||
case Exile:
|
||||
//in exile, only face up cards and face down cards you can look at should be shown (since "exile face down" is a thing)
|
||||
if (!isFaceDown()) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case Hand:
|
||||
if (controller.hasKeyword("Play with your hand revealed.")) {
|
||||
return true;
|
||||
@@ -628,6 +633,7 @@ public class CardView extends GameEntityView {
|
||||
set(TrackableProperty.Cloned, c.isCloned());
|
||||
set(TrackableProperty.SplitCard, isSplitCard);
|
||||
set(TrackableProperty.FlipCard, c.isFlipCard());
|
||||
set(TrackableProperty.Facedown, c.isFaceDown());
|
||||
|
||||
final Card cloner = c.getCloner();
|
||||
|
||||
|
||||
@@ -933,6 +933,18 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
||||
return copyWithDefinedCost(new Cost(abCost, isAbility()));
|
||||
}
|
||||
|
||||
public SpellAbility copyWithManaCostReplaced(Player active, Cost abCost) {
|
||||
|
||||
final SpellAbility newSA = copy(active);
|
||||
if (newSA == null) {
|
||||
return null; // the ability was not copyable, e.g. a Suspend SA may get here
|
||||
}
|
||||
final Cost newCost = newSA.getPayCosts().copyWithNoMana();
|
||||
newCost.add(abCost);
|
||||
newSA.setPayCosts(newCost);
|
||||
return newSA;
|
||||
}
|
||||
|
||||
public boolean isTrigger() {
|
||||
return trigger;
|
||||
}
|
||||
|
||||
@@ -737,8 +737,17 @@ public final class StaticAbilityContinuous {
|
||||
}
|
||||
|
||||
if (controllerMayPlay && (mayPlayLimit == null || stAb.getMayPlayTurn() < mayPlayLimit)) {
|
||||
String mayPlayAltCost = mayPlayAltManaCost;
|
||||
|
||||
if (mayPlayAltCost != null && mayPlayAltCost.contains("ConvertedManaCost")) {
|
||||
final String costcmc = Integer.toString(affectedCard.getCMC());
|
||||
mayPlayAltCost = mayPlayAltCost.replace("ConvertedManaCost", costcmc);
|
||||
}
|
||||
|
||||
Player mayPlayController = params.containsKey("MayPlayCardOwner") ? affectedCard.getOwner() : controller;
|
||||
affectedCard.setMayPlay(mayPlayController, mayPlayWithoutManaCost, mayPlayAltManaCost, mayPlayWithFlash, mayPlayGrantZonePermissions, stAb);
|
||||
affectedCard.setMayPlay(mayPlayController, mayPlayWithoutManaCost,
|
||||
mayPlayAltCost != null ? new Cost(mayPlayAltCost, false) : null,
|
||||
mayPlayWithFlash, mayPlayGrantZonePermissions, stAb);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<packaging.type>jar</packaging.type>
|
||||
<build.min.memory>-Xms1024m</build.min.memory>
|
||||
<build.max.memory>-Xmx1536m</build.max.memory>
|
||||
<alpha-version>1.6.24.001</alpha-version>
|
||||
<alpha-version>1.6.25.001</alpha-version>
|
||||
<sign.keystore>keystore</sign.keystore>
|
||||
<sign.alias>alias</sign.alias>
|
||||
<sign.storepass>storepass</sign.storepass>
|
||||
@@ -19,7 +19,7 @@
|
||||
<parent>
|
||||
<artifactId>forge</artifactId>
|
||||
<groupId>forge</groupId>
|
||||
<version>1.6.25-SNAPSHOT</version>
|
||||
<version>1.6.26-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>forge-gui-android</artifactId>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>forge</artifactId>
|
||||
<groupId>forge</groupId>
|
||||
<version>1.6.25-SNAPSHOT</version>
|
||||
<version>1.6.26-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>forge-gui-desktop</artifactId>
|
||||
|
||||
@@ -6,13 +6,13 @@
|
||||
<packaging.type>jar</packaging.type>
|
||||
<build.min.memory>-Xms128m</build.min.memory>
|
||||
<build.max.memory>-Xmx2048m</build.max.memory>
|
||||
<alpha-version>1.6.24.001</alpha-version>
|
||||
<alpha-version>1.6.25.001</alpha-version>
|
||||
</properties>
|
||||
|
||||
<parent>
|
||||
<artifactId>forge</artifactId>
|
||||
<groupId>forge</groupId>
|
||||
<version>1.6.25-SNAPSHOT</version>
|
||||
<version>1.6.26-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>forge-gui-ios</artifactId>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>forge</artifactId>
|
||||
<groupId>forge</groupId>
|
||||
<version>1.6.25-SNAPSHOT</version>
|
||||
<version>1.6.26-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>forge-gui-mobile-dev</artifactId>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>forge</artifactId>
|
||||
<groupId>forge</groupId>
|
||||
<version>1.6.25-SNAPSHOT</version>
|
||||
<version>1.6.26-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>forge-gui-mobile</artifactId>
|
||||
|
||||
@@ -34,7 +34,7 @@ import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
public class Forge implements ApplicationListener {
|
||||
public static final String CURRENT_VERSION = "1.6.24.001";
|
||||
public static final String CURRENT_VERSION = "1.6.25.001";
|
||||
|
||||
private static final ApplicationListener app = new Forge();
|
||||
private static Clipboard clipboard;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>forge</artifactId>
|
||||
<groupId>forge</groupId>
|
||||
<version>1.6.25-SNAPSHOT</version>
|
||||
<version>1.6.26-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>forge-gui</artifactId>
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#Add one announcement per line
|
||||
War for the Spark is here! We're still missing a few cards, but hopefully we'll get those added soon.
|
||||
A very drastic change has happened for tokens and token images. Check out the information here: https://www.slightlymagic.net/forum/viewtopic.php?f=26&t=23317
|
||||
War for the Spark is all added. I'm sure we didn't get all of the bugs fully worked out, so please let us know if you see anything weird.
|
||||
A significant improvement was made to how we cache images which should improve memory usage
|
||||
[b]Forge now requires Java 8 (or newer). You will not be able to start the game if you are not yet running Java 8.[/b]
|
||||
We have a Discord server for hanging out with Forge devs and other Forge fans. Feel free to [url=https://discord.gg/3v9JCVr]jump on in and say hi[/url]!
|
||||
Online Multiplayer is once again functional!
|
||||
@@ -3,6 +3,7 @@ Austinio7116
|
||||
Churrufli
|
||||
DrDev
|
||||
excessum
|
||||
Flair
|
||||
Gos
|
||||
Hanmac
|
||||
Indigo Dragon
|
||||
|
||||
@@ -7,7 +7,7 @@ Some people use the Windows application 7zip. This utility can be found at http:
|
||||
Once the Forge archive has been decompressed you should then be able to launch Forge by using the included launcher. Launching Forge by double clicking on the forge jar file in the past caused a java heap space error. Forge's memory requirements have increased over time and the launchers increase the java heap space available to Forge. Currently you can launch Forge by double clicking on the forge jar file without a java heap space error but this is likely to change as we add in more sounds, icons, etc.
|
||||
|
||||
- The Mac OS application version -
|
||||
We haven't been able to distribute the OS X Application version of Forge in sometime. We've recently automated our release tools, and will continue to look in the viability of creating this file now that things are autoamted.
|
||||
We provide separate macOS builds of desktop and mobile (backported) Forge packaged as native Mac applications. Please check the relevant thread for details and download links.
|
||||
|
||||
|
||||
- Online Multiplayer -
|
||||
|
||||
@@ -252,6 +252,14 @@ BOUNCE_ALL_ELSEWHERE_CREAT_EVAL_DIFF=200
|
||||
BOUNCE_ALL_TO_HAND_NONCREAT_EVAL_DIFF=3
|
||||
BOUNCE_ALL_ELSEWHERE_NONCREAT_EVAL_DIFF=3
|
||||
|
||||
# Use a blink spell to reload a planeswalker's loyalty (e.g. Teferi's Time Twist)
|
||||
# A chance (per check) to activate this ability
|
||||
BLINK_RELOAD_PLANESWALKER_CHANCE=15
|
||||
# Maximum loyalty at which the planeswalker needs to be in order to activate the blink-reload
|
||||
BLINK_RELOAD_PLANESWALKER_MAX_LOYALTY=2
|
||||
# The difference between maximum loyalty and base loyalty of the planeswalker in order to consider blink-reloading it
|
||||
BLINK_RELOAD_PLANESWALKER_LOYALTY_DIFF=2
|
||||
|
||||
# If enabled, the AI will try to pair up cards to present to the opponent so that a specific card may be picked,
|
||||
# it'll also try to grab Accumulated Knowledge and Take Inventory more actively, as well as interact with the Trix
|
||||
# combo deck more appropriately. In Reanimator decks, this logic will make the AI pick the fattest threats in the
|
||||
|
||||
@@ -253,6 +253,14 @@ BOUNCE_ALL_ELSEWHERE_CREAT_EVAL_DIFF=200
|
||||
BOUNCE_ALL_TO_HAND_NONCREAT_EVAL_DIFF=3
|
||||
BOUNCE_ALL_ELSEWHERE_NONCREAT_EVAL_DIFF=3
|
||||
|
||||
# Use a blink spell to reload a planeswalker's loyalty (e.g. Teferi's Time Twist)
|
||||
# A chance (per check) to activate this ability
|
||||
BLINK_RELOAD_PLANESWALKER_CHANCE=30
|
||||
# Maximum loyalty at which the planeswalker needs to be in order to activate the blink-reload
|
||||
BLINK_RELOAD_PLANESWALKER_MAX_LOYALTY=2
|
||||
# The difference between maximum loyalty and base loyalty of the planeswalker in order to consider blink-reloading it
|
||||
BLINK_RELOAD_PLANESWALKER_LOYALTY_DIFF=2
|
||||
|
||||
# If enabled, the AI will try to pair up cards to present to the opponent so that a specific card may be picked,
|
||||
# it'll also try to grab Accumulated Knowledge and Take Inventory more actively, as well as interact with the Trix
|
||||
# combo deck more appropriately. In Reanimator decks, this logic will make the AI pick the fattest threats in the
|
||||
|
||||
@@ -253,6 +253,14 @@ BOUNCE_ALL_ELSEWHERE_CREAT_EVAL_DIFF=400
|
||||
BOUNCE_ALL_TO_HAND_NONCREAT_EVAL_DIFF=5
|
||||
BOUNCE_ALL_ELSEWHERE_NONCREAT_EVAL_DIFF=5
|
||||
|
||||
# Use a blink spell to reload a planeswalker's loyalty (e.g. Teferi's Time Twist)
|
||||
# A chance (per check) to activate this ability
|
||||
BLINK_RELOAD_PLANESWALKER_CHANCE=70
|
||||
# Maximum loyalty at which the planeswalker needs to be in order to activate the blink-reload
|
||||
BLINK_RELOAD_PLANESWALKER_MAX_LOYALTY=2
|
||||
# The difference between maximum loyalty and base loyalty of the planeswalker in order to consider blink-reloading it
|
||||
BLINK_RELOAD_PLANESWALKER_LOYALTY_DIFF=1
|
||||
|
||||
# If enabled, the AI will try to pair up cards to present to the opponent so that a specific card may be picked,
|
||||
# it'll also try to grab Accumulated Knowledge and Take Inventory more actively, as well as interact with the Trix
|
||||
# combo deck more appropriately. In Reanimator decks, this logic will make the AI pick the fattest threats in the
|
||||
|
||||
@@ -253,6 +253,14 @@ BOUNCE_ALL_ELSEWHERE_CREAT_EVAL_DIFF=200
|
||||
BOUNCE_ALL_TO_HAND_NONCREAT_EVAL_DIFF=3
|
||||
BOUNCE_ALL_ELSEWHERE_NONCREAT_EVAL_DIFF=3
|
||||
|
||||
# Use a blink spell to reload a planeswalker's loyalty (e.g. Teferi's Time Twist)
|
||||
# A chance (per check) to activate this ability
|
||||
BLINK_RELOAD_PLANESWALKER_CHANCE=60
|
||||
# Maximum loyalty at which the planeswalker needs to be in order to activate the blink-reload
|
||||
BLINK_RELOAD_PLANESWALKER_MAX_LOYALTY=2
|
||||
# The difference between maximum loyalty and base loyalty of the planeswalker in order to consider blink-reloading it
|
||||
BLINK_RELOAD_PLANESWALKER_LOYALTY_DIFF=1
|
||||
|
||||
# If enabled, the AI will try to pair up cards to present to the opponent so that a specific card may be picked,
|
||||
# it'll also try to grab Accumulated Knowledge and Take Inventory more actively, as well as interact with the Trix
|
||||
# combo deck more appropriately. In Reanimator decks, this logic will make the AI pick the fattest threats in the
|
||||
|
||||
@@ -4,7 +4,7 @@ Types:Creature Human Soldier
|
||||
PT:2/4
|
||||
K:Cycling:2 W
|
||||
T:Mode$ Cycled | ValidCard$ Card.Self | Execute$ TrigToken | OptionalDecider$ You | TriggerDescription$ When you cycle CARDNAME or it dies, you may create a 1/1 white Soldier creature token.
|
||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigToken | OptionalDecider$ You | Secondary$ True | TriggerDescription$ When you cycle CARDNAME or it dies, you may create a 1/1 white Soldier creature token.
|
||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigToken | OptionalDecider$ You | TriggerController$ TriggeredCardController | Secondary$ True | TriggerDescription$ When you cycle CARDNAME or it dies, you may create a 1/1 white Soldier creature token.
|
||||
SVar:TrigToken:DB$ Token | TokenAmount$ 1 | TokenScript$ w_1_1_soldier | TokenOwner$ You | LegacyImage$ w 1 1 soldier arb
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/bant_sojourners.jpg
|
||||
Oracle:When you cycle Bant Sojourners or it dies, you may create a 1/1 white Soldier creature token.\nCycling {2}{W} ({2}{W}, Discard this card: Draw a card.)
|
||||
|
||||
7
forge-gui/res/cardsfolder/b/bolass_citadel.txt
Normal file
7
forge-gui/res/cardsfolder/b/bolass_citadel.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
Name:Bolas's Citadel
|
||||
ManaCost:3 B B B
|
||||
Types:Legendary Artifact
|
||||
S:Mode$ Continuous | Affected$ Card.TopLibrary+YouCtrl | AffectedZone$ Library | MayLookAt$ You | Description$ You may look at the top card of your library any time.
|
||||
S:Mode$ Continuous | Affected$ Card.TopLibrary+YouCtrl | AffectedZone$ Library | MayPlay$ True | MayPlayAltManaCost$ PayLife<ConvertedManaCost> | Description$ You may play the top card of your library. If you cast a spell this way, pay life equal to its converted mana cost rather than pay its mana cost.
|
||||
A:AB$ LoseLife | Cost$ T Sac<10/Permanent.nonLand/nonland permanent> | Defined$ Player.Opponent | LifeAmount$ 10 | SpellDescription$ Each opponent loses 10 life.
|
||||
Oracle:You may look at the top card of your library any time.\nYou may play the top card of your library. If you cast a spell this way, pay life equal to its converted mana cost rather than pay its mana cost.\n{T}, Sacrifice ten nonland permanents: Each opponent loses 10 life.
|
||||
@@ -2,7 +2,7 @@ Name:Finale of Revelation
|
||||
ManaCost:X U U
|
||||
Types:Sorcery
|
||||
A:SP$ ChangeZoneAll | Cost$ X U U | ChangeType$ Card | Origin$ Graveyard | Destination$ Library | Shuffle$ True | Random$ True | SubAbility$ DBDraw | UseAllOriginZones$ True | References$ X | ConditionCheckSVar$ X | ConditionSVarCompare$ GE10 | SpellDescription$ Draw X cards. If X is 10 or more, instead shuffle your graveyard into your library, draw X cards, untap up to five lands, and you have no maximum hand size for the rest of the game.
|
||||
SVar:DBDraw:DB$ Draw | NumCards$ X | References$ X | SubAbility$ DBUntap
|
||||
SVar:DBDraw:DB$ Draw | NumCards$ X | References$ X | SubAbility$ DBUntap | AILogic$ ConsiderPrimary
|
||||
SVar:DBUntap:DB$ Untap | UntapUpTo$ True | UntapType$ Land | Amount$ 5 | SubAbility$ DBEffect | References$ X | ConditionCheckSVar$ X | ConditionSVarCompare$ GE10
|
||||
SVar:DBEffect:DB$ Effect | Name$ Finale of Revelation Effect | StaticAbilities$ STHandSize | Duration$ Permanent | SubAbility$ DBChange | References$ X | ConditionCheckSVar$ X | ConditionSVarCompare$ GE10
|
||||
SVar:STHandSize:Mode$ Continuous | EffectZone$ Command | Affected$ You | SetMaxHandSize$ Unlimited | Description$ You have no maximum hand size.
|
||||
|
||||
@@ -12,4 +12,5 @@ T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$
|
||||
SVar:TrigFromGraveyard:DB$ChangeZone | Defined$ TriggeredCard | Origin$ Graveyard | Destination$ Library | LibraryPosition$ 2
|
||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Exile | ValidCard$ Card.Self | Execute$ TrigFromExile | OptionalDecider$ You | TriggerController$ TriggeredCardController | Secondary$ True | TriggerDescription$ When CARDNAME dies or is put into exile from the battlefield, you may put it into its owner's library third from the top.
|
||||
SVar:TrigFromExile:DB$ChangeZone | Defined$ TriggeredCard | Origin$ Exile | Destination$ Library | LibraryPosition$ 2
|
||||
SVar:PlayMain1:TRUE
|
||||
Oracle:Deathtouch\nWhen God-Eternal Rhonas enters the battlefield, double the power of each other creature you control until end of turn. Those creatures gain vigilance until end of turn.\nWhen God-Eternal Rhonas dies or is put into exile from the battlefield, you may put it into its owner's library third from the top.
|
||||
|
||||
@@ -3,7 +3,7 @@ ManaCost:3 U
|
||||
Types:Legendary Planeswalker Kasmina
|
||||
Loyalty:5
|
||||
S:Mode$ RaiseCost | ValidTarget$ Creature.YouOwn+inZoneBattlefield | Activator$ Player.Opponent | Type$ Spell | Amount$ 2 | Description$ Spells your opponents cast that target a creature or planeswalker you control cost {2} more to cast.
|
||||
A:AB$ Token | Cost$ SubCounter<2/LOYALTY> | Planeswalker$ True | TokenAmount$ 1 | TokenScript$ u_2_2_Wizard | TokenOwner$ You | LegacyImage$ u 2 2 Wizard war | SubAbility$ DBDraw | SpellDescription$ Create a 2/2 blue Wizard creature token. Draw a card, then discard a card.
|
||||
A:AB$ Token | Cost$ SubCounter<2/LOYALTY> | Planeswalker$ True | TokenAmount$ 1 | TokenScript$ u_2_2_wizard | TokenOwner$ You | LegacyImage$ u 2 2 Wizard war | SubAbility$ DBDraw | SpellDescription$ Create a 2/2 blue Wizard creature token. Draw a card, then discard a card.
|
||||
SVar:DBDraw:DB$Draw | NumCards$ 1 | SubAbility$ DBDiscard
|
||||
SVar:DBDiscard:DB$Discard | Defined$ You | Mode$ TgtChoose | NumCards$ 1
|
||||
AI:RemoveDeck:Random
|
||||
|
||||
@@ -6,7 +6,7 @@ S:Mode$ Continuous | Affected$ Creature.YouCtrl,Planeswalker.YouCtrl | AddKeywor
|
||||
SVar:NonStackingEffect:True
|
||||
A:AB$ DealDamage | Cost$ AddCounter<2/LOYALTY> | Planeswalker$ True | ValidTgts$ Player,Planeswalker | TgtPrompt$ Select target player or planeswalker | NumDmg$ 1 | SpellDescription$ CARDNAME deals 1 damage to target player or planeswalker.
|
||||
A:AB$ ChangeZone | Cost$ SubCounter<X/LOYALTY> | Planeswalker$ True | Origin$ Graveyard | Destination$ Battlefield | Announce$ X | References$ X | ValidTgts$ Creature.YouOwn | TgtPrompt$ Select target creature with converted mana cost X from your graveyard | SubAbility$ Animate | SpellDescription$ Return target creature card with converted mana cost X from your graveyard to the battlefield. That creature is a Vampire in addition to its other types.
|
||||
SVar:Animate:DB$Animate | Defined$ Targeted | Types$ Vampire | Keywords$ Animate | Permanent$ True
|
||||
SVar:Animate:DB$ Animate | Defined$ Targeted | Types$ Vampire | Permanent$ True
|
||||
SVar:X:Targeted$CardManaCost
|
||||
AI:RemoveDeck:All
|
||||
Oracle:As long as it's your turn, creatures and planeswalkers you control have lifelink.\n[+2]: Sorin, Vengeful Bloodlord deals 1 damage to target player or planeswalker.\n-X: Return target creature card with converted mana cost X from your graveyard to the battlefield. That creature is a Vampire in addition to its other types.
|
||||
|
||||
@@ -4,7 +4,7 @@ Types:Creature Elemental
|
||||
PT:3/4
|
||||
K:Flying
|
||||
A:AB$ Tap | Cost$ U ExileFromTop<1/Card> | ValidTgts$ Creature.withFlying | TgtPrompt$ Select target creature with flying | SpellDescription$ Tap target creature with flying.
|
||||
A:AB$ Pump | Cost$ U ExileFromTop<1/Card> | Defined$ Self | NumAtt$ +X | NumDef$ +X | SpellDescription$ If the exiled card is a snow land, CARDNAME gets +1/+1 until end of turn.
|
||||
A:AB$ Pump | Cost$ U ExileFromTop<1/Card> | Defined$ Self | NumAtt$ +X | NumDef$ +X | References$ X | SpellDescription$ If the exiled card is a snow land, CARDNAME gets +1/+1 until end of turn.
|
||||
SVar:X:Exiled$Valid Land.Snow
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/storm_elemental.jpg
|
||||
Oracle:Flying\n{U}, Exile the top card of your library: Tap target creature with flying.\n{U}, Exile the top card of your library: If the exiled card is a snow land, Storm Elemental gets +1/+1 until end of turn.
|
||||
|
||||
10
forge-gui/res/cardsfolder/t/teferis_time_twist.txt
Normal file
10
forge-gui/res/cardsfolder/t/teferis_time_twist.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
Name:Teferi's Time Twist
|
||||
ManaCost:1 U
|
||||
Types:Instant
|
||||
A:SP$ ChangeZone | Cost$ 1 U | ValidTgts$ Permanent.YouCtrl | TgtPrompt$ Select target permanent you control | Origin$ Battlefield | Destination$ Exile | RememberChanged$ True | AILogic$ DelayedBlink | SubAbility$ DBAnimate | SpellDescription$ Exile target permanent you control. Return that card to the battlefield under its owner’s control at the beginning of the next end step. If it enters the battlefield as a creature, it enters with an additional +1/+1 counter on it.
|
||||
SVar:DBAnimate:DB$ Animate | Defined$ Remembered | Keywords$ etbCounter:P1P1:1:ValidCard$ Creature.IsRemembered | RememberObjects$ Remembered | SubAbility$ DelTrig | AILogic$ Always
|
||||
SVar:DelTrig:DB$ DelayedTrigger | Mode$ Phase | Phase$ End of Turn | Execute$ TrigBounce | RememberObjects$ Remembered | AILogic$ Always | TriggerDescription$ Return that card to the battlefield under its owner’s control at the beginning of the next end step. If it enters the battlefield as a creature, it enters with an additional +1/+1 counter on it.
|
||||
SVar:TrigBounce:DB$ ChangeZone | Origin$ Exile | Destination$ Battlefield | Defined$ DelayTriggerRemembered
|
||||
SVar:Picture:https://gatherer.wizards.com/Handlers/Image.ashx?multiverseid=460999&type=card
|
||||
DeckHas:Ability$Counters
|
||||
Oracle:Exile target permanent you control. Return that card to the battlefield under its owner's control at the beginning of the next end step. If it enters the battlefield as a creature, it enters with an additional +1/+1 counter on it.
|
||||
16
forge-gui/res/cardsfolder/u/ugin_the_ineffable.txt
Normal file
16
forge-gui/res/cardsfolder/u/ugin_the_ineffable.txt
Normal file
@@ -0,0 +1,16 @@
|
||||
Name:Ugin, the Ineffable
|
||||
ManaCost:6
|
||||
Types:Legendary Planeswalker Ugin
|
||||
Loyalty:4
|
||||
S:Mode$ ReduceCost | ValidCard$ Card.Colorless | Type$ Spell | Activator$ You | Amount$ 2 | Description$ Colorless spells you cast cost {2} less to cast.
|
||||
A:AB$ PeekAndReveal | Cost$ AddCounter<1/LOYALTY> | Planeswalker$ True | PeekAmount$ 1 | NoReveal$ True | SubAbility$ DBMill | StackDescription$ SpellDescription | SpellDescription$ Exile the top card of your library face down and look at it. Create a 2/2 colorless Spirit creature token. When that token leaves the battlefield, put the exiled card into your hand.
|
||||
SVar:DBMill:DB$ Mill | Defined$ You | NumCards$ 1 | Destination$ Exile | RememberMilled$ True | ExileFaceDown$ True | NoReveal$ True | SubAbility$ DBToken
|
||||
SVar:DBToken:DB$ Token | TokenScript$ c_2_2_spirit | ImprintTokens$ True | SubAbility$ DBEffect
|
||||
SVar:DBEffect:DB$ Effect | Triggers$ TrigLeavesBattlefield | SVars$ DBReturn,DBExile | RememberObjects$ Remembered | ImprintCards$ Imprinted | SubAbility$ DBCleanup
|
||||
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True | ClearImprinted$ True
|
||||
SVar:TrigLeavesBattlefield:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Any | ValidCard$ Card.IsImprinted | Execute$ DBReturn | TriggerDescription$ When that token leaves the battlefield, put the exiled card into your hand.
|
||||
SVar:DBReturn:DB$ ChangeZoneAll | Origin$ Exile | Destination$ Hand | ChangeType$ Card.IsRemembered | SubAbility$ DBExile
|
||||
SVar:DBExile:DB$ ChangeZoneAll | Origin$ Command | Destination$ Exile | ChangeType$ Card.Self
|
||||
A:AB$ Destroy | Cost$ SubCounter<3/LOYALTY> | ValidTgts$ Permanent.nonColorless | TgtPrompt$ Select target permanent that's one or more colors | Planeswalker$ True | SpellDescription$ Destroy target permanent that’s one or more colors.
|
||||
DeckHas:Ability$Token
|
||||
Oracle:Colorless spells you cast cost {2} less to cast.\n+1: Exile the top card of your library face down and look at it. Create a 2/2 colorless Spirit creature token. When that token leaves the battlefield, put the exiled card into your hand.\n−3: Destroy target permanent that’s one or more colors.
|
||||
11
forge-gui/res/cardsfolder/upcoming/cabal_therapist.txt
Normal file
11
forge-gui/res/cardsfolder/upcoming/cabal_therapist.txt
Normal file
@@ -0,0 +1,11 @@
|
||||
Name:Cabal Therapist
|
||||
ManaCost:B
|
||||
Types:Creature Horror
|
||||
PT:1/1
|
||||
K:Menace
|
||||
T:Mode$ Phase | Phase$ Main1 | PreCombatMain$ True | ValidPlayer$ You | Execute$ DBImmediateTrigger | TriggerZones$ Battlefield | TriggerDescription$ At the beginning of your precombat main phase, you may sacrifice a creature. When you do, choose a nonland card name, then target player reveals their hand and discards all cards with that name.
|
||||
SVar:DBImmediateTrigger:DB$ ImmediateTrigger | Execute$ NameCard | TriggerDescription$ You may sacrifice a creature. When you do, choose a nonland card name, then target player reveals their hand and discards all cards with that name. | UnlessCost$ Sac<1/Creature> | UnlessPayer$ You | UnlessSwitched$ True
|
||||
SVar:NameCard:DB$ NameCard | Defined$ You | ValidCards$ Card.nonLand | ValidDesc$ nonland | SubAbility$ DBDiscard | SpellDescription$ Choose a nonland card name. Target player reveals their hand and discards all cards with that name.
|
||||
SVar:DBDiscard:DB$ Discard | ValidTgts$ Player | TgtPrompt$ Select target player | Mode$ RevealDiscardAll | DiscardValid$ Card.NamedCard
|
||||
AI:RemoveDeck:All
|
||||
Oracle:Menace\nAt the beginning of your precombat main phase, you may sacrifice a creature. When you do, choose a nonland card name, then target player reveals their hand and discards all cards with that name.
|
||||
11
forge-gui/res/cardsfolder/upcoming/deep_forest_hermit.txt
Normal file
11
forge-gui/res/cardsfolder/upcoming/deep_forest_hermit.txt
Normal file
@@ -0,0 +1,11 @@
|
||||
Name:Deep Forest Hermit
|
||||
ManaCost:3 G G
|
||||
Types:Creature Elf Druid
|
||||
K:Vanishing:3
|
||||
PT:1/1
|
||||
S:Mode$ Continuous | Affected$ Creature.Squirrel+YouCtrl | AddPower$ 1 | AddToughness$ 1 | Description$ Squirrel creatures you control get +1/+1.
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigToken | TriggerDescription$ When CARDNAME enters the battlefield, create four 1/1 green Squirrel creature tokens.
|
||||
SVar:TrigToken:DB$Token | TokenAmount$ 4 | TokenScript$ g_1_1_squirrel | TokenOwner$ You | LegacyImage$ g 1 1 squirrel mh1
|
||||
SVar:PlayMain1:TRUE
|
||||
SVar:Picture:http://mythicspoiler.com/mh1/cards/deepforesthermit.jpg
|
||||
Oracle:Vanishing 3 (This permanent enters the battlefield with three time counters on it. At the beginning of your upkeep, remove a time counter from it. When the last is removed, sacrifice it.)\nWhen Deep Forest Hermit enters the battlefield, create four 1/1 green Squirrel creature tokens.\nSquirrels you control get +1/+1.
|
||||
7
forge-gui/res/cardsfolder/upcoming/force_of_negation.txt
Normal file
7
forge-gui/res/cardsfolder/upcoming/force_of_negation.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
Name:Force of Negation
|
||||
ManaCost:1 U U
|
||||
Types:Instant
|
||||
A:SP$ Counter | Cost$ 1 U U | TargetType$ Spell | TgtPrompt$ Select target nonCreature Spell | ValidTgts$ Card.nonCreature | Destination$ Exile | SpellDescription$ Counter target noncreature spell. If that spell is countered this way, exile it instead of putting it into its owner's graveyayrd.
|
||||
SVar:AltCost:Cost$ ExileFromHand<1/Card.Blue> | OpponentTurn$ True | Description$ If it's not your turn, you may exile a blue card from your hand rather than pay this spell's mana cost.
|
||||
Svar:Picture:http://mythicspoiler.com/mh1/cards/forceofnegation.jpg
|
||||
Oracle:If it's not your turn, you may exile a blue card from your hand rather than pay this spell's mana cost.\nCounter target noncreature spell. If that spell is countered this way, exile it instead of putting it into its owner's graveyayrd.
|
||||
6
forge-gui/res/cardsfolder/upcoming/force_of_vigor.txt
Normal file
6
forge-gui/res/cardsfolder/upcoming/force_of_vigor.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
Name:Force of Vigor
|
||||
ManaCost:2 G G
|
||||
Types:Instant
|
||||
A:SP$ Destroy | Cost$ 2 G G | TargetMin$ 0 | TargetMax$ 2 | ValidTgts$ Artifact,Enchantment | TgtPrompt$ Select target artifact or enchantment | SpellDescription$ Destroy up to two target artifacts and/or enchantments.
|
||||
SVar:AltCost:Cost$ ExileFromHand<1/Card.Green> | OpponentTurn$ True | Description$ If it's not your turn, you may exile a green card from your hand rather than pay this spell's mana cost.
|
||||
Oracle:If it's not your turn, you may exile a green card from your hand rather than pay this spell's mana cost.\nDestroy up to two target artifacts and/or enchantments.
|
||||
8
forge-gui/res/cardsfolder/upcoming/goblin_war_party.txt
Normal file
8
forge-gui/res/cardsfolder/upcoming/goblin_war_party.txt
Normal file
@@ -0,0 +1,8 @@
|
||||
Name:Goblin War Party
|
||||
ManaCost:3 R
|
||||
Types:Sorcery
|
||||
K:Entwine:2 R
|
||||
A:SP$ Charm | Cost$ 3 R | Choices$ DBTokens,DBBuff | Defined$ You | CharmNum$ 1
|
||||
SVar:DBTokens:DB$ Token | TokenAmount$ 3 | TokenScript$ r_1_1_goblin | TokenOwner$ You | LegacyImage$ r 1 1 goblin mh1 | SpellDescription$ Create three 1/1 red Goblin creature tokens.
|
||||
SVar:DBBuff:DB$ PumpAll | NumAtt$ 1 | NumDef$ 1 | ValidCards$ Creature.YouCtrl | KW$ Haste | SpellDescription$ Creatures you control get +1/+1 and gain haste until end of turn.
|
||||
Oracle:Choose one —\n• Create three 1/1 red Goblin creature tokens.\n• Creatures you control get +1/+1 and gain haste until end of turn. \nEntwine {2}{R}(Choose both if you pay the entwine cost.)
|
||||
8
forge-gui/res/cardsfolder/upcoming/headless_specter.txt
Normal file
8
forge-gui/res/cardsfolder/upcoming/headless_specter.txt
Normal file
@@ -0,0 +1,8 @@
|
||||
Name:Headless Specter
|
||||
ManaCost:1 B B
|
||||
Types:Creature Specter
|
||||
PT:2/2
|
||||
K:Flying
|
||||
T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | CombatDamage$ True | Hellbent$ True | Execute$ TrigDiscard | TriggerZones$ Battlefield | TriggerDescription$ Hellbent Whenever CARDNAME deals combat damage to a player, if you have no cards in hand, that player discards a card at random.
|
||||
SVar:TrigDiscard:DB$ Discard | Defined$ TriggeredTarget | NumCards$ 1 | Mode$ Random
|
||||
Oracle:Flying\nHellbent — Whenever Hellbent Specter deals combat damage to a player, if you have no cards in hand, that player discards a card at random.
|
||||
12
forge-gui/res/cardsfolder/upcoming/ice_fang_coatl.txt
Normal file
12
forge-gui/res/cardsfolder/upcoming/ice_fang_coatl.txt
Normal file
@@ -0,0 +1,12 @@
|
||||
Name:Ice-Fang Coatl
|
||||
ManaCost:G U
|
||||
Types:Snow Creature Snake
|
||||
PT:1/1
|
||||
K:Flash
|
||||
K:Flying
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigDraw | TriggerDescription$ When CARDNAME enters the battlefield, draw a card.
|
||||
SVar:TrigDraw:DB$Draw | Defined$ You | NumCards$ 1
|
||||
S:Mode$ Continuous | Affected$ Card.Self | AddKeyword$ Deathtouch | CheckSVar$ X | SVarCompare$ GE3 | Description$ CARDNAME has deathtouch as long as you control at least three other snow permanents.
|
||||
SVar:X:Count$Valid Permanent.Snow+Other
|
||||
SVar:BuffedBy:Permanent.Snow
|
||||
Oracle:Flash\nFlying\nWhen Ice-Fang Coatl enters the battlefield, draw a card.\nIce-Fang Coatl has deathtouch as long as you control at least three other snow permanents.
|
||||
@@ -0,0 +1,6 @@
|
||||
Name:Impostor of the Sixth Pride
|
||||
ManaCost:1 W
|
||||
Types:Creature Shapeshifter
|
||||
PT:3/1
|
||||
K:Changeling
|
||||
Oracle:Changeling (This card is every creature type.)
|
||||
@@ -0,0 +1,16 @@
|
||||
Name:Morophon, the Boundless
|
||||
ManaCost:7
|
||||
Types:Legendary Creature Shapeshifter
|
||||
PT:6/6
|
||||
K:Changeling
|
||||
K:ETBReplacement:Other:ChooseCT
|
||||
SVar:ChooseCT:DB$ ChooseType | Defined$ You | Type$ Creature | SpellDescription$ As CARDNAME enters the battlefield, choose a creature type. | StackDescription$ SpellDescription
|
||||
AI:RemoveDeck:Random
|
||||
S:Mode$ ReduceCost | ValidCard$ Card.ChosenType | Type$ Spell | Activator$ You | Amount$ 1 | Color$ W | Description$ Spells you cast of the chosen type cost {W}{U}{B}{R}{G} less to cast. This effect reduces only the amount of colored mana you pay.
|
||||
S:Mode$ ReduceCost | ValidCard$ Card.ChosenType | Type$ Spell | Activator$ You | Amount$ 1 | Color$ B
|
||||
S:Mode$ ReduceCost | ValidCard$ Card.ChosenType | Type$ Spell | Activator$ You | Amount$ 1 | Color$ U
|
||||
S:Mode$ ReduceCost | ValidCard$ Card.ChosenType | Type$ Spell | Activator$ You | Amount$ 1 | Color$ R
|
||||
S:Mode$ ReduceCost | ValidCard$ Card.ChosenType | Type$ Spell | Activator$ You | Amount$ 1 | Color$ G
|
||||
S:Mode$ Continuous | Affected$ Creature.ChosenType+Other+YouCtrl | AddPower$ 1 | AddToughness$ 1 | Description$ Other creatures you control of the chosen type get +1/+1.
|
||||
SVar:PlayMain1:TRUE
|
||||
Oracle:Changeling (This card is every creature type.)\nAs Morophon, the Boundless enters the battlefield, choose a creature type.\nSpells you cast of the chosen type cost {W}{U}{B}{R}{G} less to cast. This effect reduces only the amount of colored mana you pay.\nOther creatures you control of the chosen type get +1/+1.
|
||||
5
forge-gui/res/cardsfolder/upcoming/prismatic_vista.txt
Normal file
5
forge-gui/res/cardsfolder/upcoming/prismatic_vista.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
Name:Prismatic Vista
|
||||
ManaCost:
|
||||
Types:Land
|
||||
A:AB$ ChangeZone | Cost$ T PayLife<1> Sac<1/CARDNAME> | Origin$ Library | Destination$ Battlefield | ChangeType$ Land.Basic | ChangeNum$ 1 | SpellDescription$ Search your library for a basic land card, put it onto the battlefield, then shuffle your library.
|
||||
Oracle:{T}, Pay 1 life, Sacrifice Prismatic View: Search your library for a basic land card, put it onto the battlefield, then shuffle your library.
|
||||
6
forge-gui/res/cardsfolder/upcoming/savage_swipe.txt
Normal file
6
forge-gui/res/cardsfolder/upcoming/savage_swipe.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
Name:Savage Swipe
|
||||
ManaCost:G
|
||||
Types:Sorcery
|
||||
A:SP$ Pump | Cost$ G | ValidTgts$ Creature.YouCtrl | AILogic$ Fight | AITgts$ Creature.YouCtrl+powerEQ2 | TgtPrompt$ Select target creature you control | SubAbility$ DBFight | NumAtt$ +2 | NumDef$ +2 | ConditionDefined$ Targeted | ConditionPresent$ Creature.powerEQ2 | SpellDescription$ Target creature you control gets +2/+2 until end of turn. It fights target creature you don't control.
|
||||
SVar:DBFight:DB$ Fight | Defined$ ParentTarget | ValidTgts$ Creature.YouDontCtrl | TgtPrompt$ Select target creature you don't control
|
||||
Oracle:Target creature you control gets +2/+2 until end of turn if its power is 2. Then it fights target creature you don't control. (Each deals damage equal to its power to the other.)
|
||||
11
forge-gui/res/cardsfolder/upcoming/serra_the_benevolent.txt
Normal file
11
forge-gui/res/cardsfolder/upcoming/serra_the_benevolent.txt
Normal file
@@ -0,0 +1,11 @@
|
||||
Name:Serra the Benevolent
|
||||
ManaCost:2 W W
|
||||
Types:Legendary Planeswalker Serra
|
||||
Loyalty:4
|
||||
A:AB$ PumpAll | Cost$ AddCounter<2/LOYALTY> | Planeswalker$ True | ValidCards$ Creature.withFlying+YouCtrl | NumAtt$ +1 | NumDef$ +1 | SpellDescription$ Creatures you control with flying get +1/+1 until end of turn.
|
||||
A:AB$ Token | Cost$ SubCounter<3/LOYALTY> | Planeswalker$ True | TokenScript$ w_4_4_angel_flying_vigilance | TokenOwner$ You | LegacyImage$ w 4 4 angel flying vigilance mh1 | SpellDescription$ Create a 4/4 white Angel creature token with flying and vigilance.
|
||||
A:AB$ Effect | Cost$ SubCounter<6/LOYALTY> | Name$ Emblem - Serra the Benevolent | Image$ emblem_serra_the_benevolent | StaticAbilities$ STWorship | Planeswalker$ True | Ultimate$ True | Stackable$ False | Duration$ Permanent | AILogic$ Always | SpellDescription$ You get an emblem with "If you control a creature, damage that would reduce your life total to less than 1 reduces it to 1 instead."
|
||||
SVar:STWorship:Mode$ Continuous | EffectZone$ Command | Affected$ You | AddKeyword$ DamageLifeThreshold:1 | IsPresent$ Creature.YouCtrl | Description$ If you control a creature, damage that would reduce your life total to less than 1 reduces it to 1 instead.
|
||||
DeckHas:Ability$Token
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/serra_the_benevolent.jpg
|
||||
Oracle:[+2]: Creatures you control with flying get +1/+1 until end of turn.\n[-3]: Create a 4/4 white Angel creature token with flying and vigilance.\n[-6]: You get an emblem with "If you control a creature, damage that would reduce your life total to less than 1 reduces it to 1 instead."
|
||||
7
forge-gui/res/cardsfolder/upcoming/stream_of_thought.txt
Normal file
7
forge-gui/res/cardsfolder/upcoming/stream_of_thought.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
Name:Stream of Thought
|
||||
ManaCost:U
|
||||
Types:Sorcery
|
||||
A:SP$ Mill | Cost$ U | NumCards$ 4 | ValidTgts$ Player | TgtPrompt$ Choose a player | RememberMilled$ True | SubAbility$ DBChangeZone | SpellDescription$ Target player puts the top four cards of their library into their graveyard. You shuffle up to four cards from your graveyard into your library.
|
||||
SVar:DBChangeZone:DB$ ChangeZone | Origin$ Graveyard | Destination$ Library | DefinedPlayer$ You | Hidden$ True | ChangeNum$ 4 | ChangeType$ Card.YouOwn | Shuffle$ True
|
||||
K:Replicate:2 U U
|
||||
Oracle:Target player puts the top four cards of their library into their graveyard. You shuffle up to four cards from your graveyard into your library.\nReplicate {2}{U}{U} (When you cast this spell, copy it for each time you paid the replicate cost. You may choose new targets for the copies.)
|
||||
9
forge-gui/res/cardsfolder/upcoming/undead_augur.txt
Normal file
9
forge-gui/res/cardsfolder/upcoming/undead_augur.txt
Normal file
@@ -0,0 +1,9 @@
|
||||
Name:Undead Augur
|
||||
ManaCost:B B
|
||||
Types:Creature Zombie Wizard
|
||||
PT:2/2
|
||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | TriggerController$ TriggeredCardController | Execute$ TrigDraw | TriggerDescription$ Whenever CARDNAME or another Zombie you control dies, you draw a card and you lose 1 life.
|
||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Zombie.Other+YouCtrl | TriggerZones$ Battlefield | TriggerController$ TriggeredCardController | Secondary$ True | Execute$ TrigDraw | TriggerDescription$ Whenever CARDNAME or another Zombie you control dies, you draw a card and you lose 1 life.
|
||||
SVar:TrigDraw:DB$ Draw | Defined$ You | NumCards$ 1 | SubAbility$ DBLoseLife
|
||||
SVar:DBLoseLife:DB$ LoseLife | LifeAmount$ 1
|
||||
Oracle:Whenever Undead Augur or another Zombie you control dies, you draw a card and you lose 1 life.
|
||||
12
forge-gui/res/cardsfolder/v/vivien_champion_of_the_wilds.txt
Normal file
12
forge-gui/res/cardsfolder/v/vivien_champion_of_the_wilds.txt
Normal file
@@ -0,0 +1,12 @@
|
||||
Name:Vivien, Champion of the Wilds
|
||||
ManaCost:2 G
|
||||
Types:Legendary Planeswalker Vivien
|
||||
Loyalty:4
|
||||
S:Mode$ Continuous | Affected$ Creature | WithFlash$ You | AffectedZone$ Exile,Graveyard,Hand,Library,Command | Description$ You may cast creature spells as though they had flash.
|
||||
A:AB$ Pump | Cost$ AddCounter<1/LOYALTY> | Planeswalker$ True | ValidTgts$ Creature | TargetMin$ 0 | TargetMax$ 1 | TgtPrompt$ Select target creature | KW$ Vigilance & Reach | UntilYourNextTurn$ True | SpellDescription$ Until your next turn, up to one target creature gains vigilance and reach.
|
||||
A:AB$ Dig | Cost$ SubCounter<2/LOYALTY> | Planeswalker$ True | Defined$ You | DigNum$ 3 | DestinationZone$ Exile | ExileFaceDown$ True | RememberChanged$ True | SubAbility$ DBEffect | AILogic$ DigForCreature | SpellDescription$ Look at the top three cards of your library. Exile one face down and put the rest on the bottom of your library in any order. For as long as it remains exiled, you may look at that card and you may cast it if it's a creature card.
|
||||
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 and you may cast it if it's a creature.
|
||||
SVar:STPlay2:Mode$ Continuous | MayPlay$ True | EffectZone$ Command | Affected$ Creature.IsRemembered | AffectedZone$ Exile | Secondary$ True
|
||||
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||
Oracle:You may cast creature spells as though they had flash.\n[+1]: Until your next turn, up to one target creature gains vigilance and reach.\n[−2]: Look at the top three cards of your library. Exile one face down and put the rest on the bottom of your library in any order. For as long as it remains exiled, you may look at that card and you may cast it if it's a creature card.
|
||||
Binary file not shown.
Binary file not shown.
46
forge-gui/res/editions/Modern Horizons.txt
Normal file
46
forge-gui/res/editions/Modern Horizons.txt
Normal file
@@ -0,0 +1,46 @@
|
||||
[metadata]
|
||||
Code=MH1
|
||||
Date=2019-6-14
|
||||
Name=Modern Horizons
|
||||
Code2=MH1
|
||||
MciCode=mh1
|
||||
Type=Other
|
||||
|
||||
[cards]
|
||||
1 M Morophon, the Boundless
|
||||
14 C Impostor of the Sixth Pride
|
||||
19 C Martyr's Soul
|
||||
26 M Serra the Benevolent
|
||||
36 C Wall of One Thousand Cuts
|
||||
38 U Wing Shards
|
||||
44 C Choking Tethers
|
||||
50 U Fact or Fiction
|
||||
52 R Force of Negation
|
||||
64 C Prohibit
|
||||
71 C Stream of Thought
|
||||
80 R Cabal Therapist
|
||||
95 C Headless Specter
|
||||
114 C Venomous Changling
|
||||
122 U Firebolt
|
||||
129 U Goblin Matron
|
||||
131 C Goblin War Party
|
||||
134 C Lava Dart
|
||||
145 M Seasoned Pyromancer
|
||||
161 R Deep Forest Hermit
|
||||
162 C Elvish Fury
|
||||
164 R Force of Vigor
|
||||
178 C Savage Swipe
|
||||
203 R Ice-Fang Coatl
|
||||
244 R Prismatic Vista
|
||||
250 L Snow-Covered Plains
|
||||
251 L Snow-Covered Island
|
||||
252 L Snow-Covered Swamp
|
||||
253 L Snow-Covered Mountain
|
||||
254 L Snow-Covered Forest
|
||||
255 R Flusterstorm
|
||||
|
||||
|
||||
[tokens]
|
||||
w_4_4_angel_flying_vigilance
|
||||
g_1_1_squirrel
|
||||
r_1_1_goblin
|
||||
@@ -316,8 +316,20 @@ public abstract class InputPayMana extends InputSyncronizedBase {
|
||||
} else {
|
||||
chosen = chosenAbility;
|
||||
}
|
||||
|
||||
ColorSet colors = ColorSet.fromMask(0 == colorNeeded ? colorCanUse : colorNeeded);
|
||||
chosen.getManaPartRecursive().setExpressChoice(colors);
|
||||
|
||||
// Filter the colors for the express choice so that only actually producible colors can be chosen
|
||||
int producedColorMask = 0;
|
||||
for (final byte color : ManaAtom.MANATYPES) {
|
||||
if (chosen.getManaPartRecursive().getOrigProduced().contains(MagicColor.toShortString(color))
|
||||
&& colors.hasAnyColor(color)) {
|
||||
producedColorMask |= color;
|
||||
}
|
||||
}
|
||||
ColorSet producedAndNeededColors = ColorSet.fromMask(producedColorMask);
|
||||
|
||||
chosen.getManaPartRecursive().setExpressChoice(producedAndNeededColors);
|
||||
|
||||
// System.out.println("Chosen sa=" + chosen + " of " + chosen.getHostCard() + " to pay mana");
|
||||
|
||||
|
||||
2
pom.xml
2
pom.xml
@@ -5,7 +5,7 @@
|
||||
<artifactId>forge</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<name>Forge Parent</name>
|
||||
<version>1.6.25-SNAPSHOT</version>
|
||||
<version>1.6.26-SNAPSHOT</version>
|
||||
|
||||
<description>
|
||||
Forge lets you play the card game Magic: The Gathering against a computer opponent using all of the rules.
|
||||
|
||||
Reference in New Issue
Block a user