Compare commits

...

18 Commits

Author SHA1 Message Date
aryst0krat
e70aa429b6 #9136 formatting fix 2025-11-11 16:02:07 +01:00
Paul Hammerton
355722516f Add variant names for OM1 2025-11-11 15:47:15 +01:00
Paul Hammerton
f08d3f6447 Fix audit finding unimplemented funny cards (#9138) 2025-11-11 14:07:31 +01:00
Fulgur14
d7a69b72e4 Watery Grasp (TLA) (#9140) 2025-11-11 12:36:04 +00:00
Hans Mackowiak
bce5466c62 Trigger: reuse Execute for multiple Trigger (#9094)
* Trigger: reuse Execute for multiple Trigger

* Update CardState.java

copy abilityForTrigger

* Update CardState.java

* Update Trigger.java

* Update CardState.java

* Fix Multi Trigger with Idris

* Fix Oasis of Renewal ActivationLimit

* fix storedAbilityForTrigger

* remove hasAbilityForTrigger

* Update script

---------

Co-authored-by: tool4EvEr <tool4EvEr@>
2025-11-11 08:46:53 +01:00
Paul Hammerton
c90ddd1bac Merge pull request #9134 from paulsnoops/edition-updates
Edition updates: TLA, TLE
2025-11-10 19:14:02 +00:00
Paul Hammerton
f12fbb1774 Edition updates: TLA, TLE 2025-11-10 19:11:29 +00:00
Paul Hammerton
c3c74efbe0 Merge pull request #9133 from paulsnoops/bar-10-nov-2025
Banned and Restricted Announcement for November 10, 2025
2025-11-10 18:43:40 +00:00
Paul Hammerton
5fd44c4788 Banned and Restricted Announcement for November 10, 2025 2025-11-10 18:26:12 +00:00
Jetz72
539bea6b11 Merge pull request #9096 from Jetz72/fixes20251106
Minor Adventure Updates
2025-11-10 12:17:36 -06:00
Fulgur14
40e9480c2c Apostrophes correction (#9130)
* Update ruinous_waterbending.txt

* Update waterbenders_restoration.txt
2025-11-10 14:33:39 +01:00
tool4ever
3db276f323 Secret of Bloodbending and support (#9129) 2025-11-10 12:18:53 +00:00
Chris H
c9a5fe9135 Initial checkin for Waterbending (#9120) 2025-11-10 10:27:44 +00:00
Jetz
d9e356e20c Add some extra checks for safety. 2025-11-06 09:34:56 -05:00
Jetz
843f2de272 Remove some redundant imports. 2025-11-06 09:30:44 -05:00
Jetz
f27eb1042f Expand anti-cheese. 2025-11-06 09:30:27 -05:00
Jetz
48be3406c7 Reduce bias towards standard in event selection.
Make allowedEvents override other filters.
Ensure set pool filter can't filter out every event.
2025-11-06 08:50:00 -05:00
Jetz
50a98238d1 Add allowedEvents support for adventure configs 2025-11-06 08:29:55 -05:00
215 changed files with 633 additions and 134 deletions

View File

@@ -1345,9 +1345,7 @@ public class ComputerUtilMana {
}
}
if (!effect) {
CostAdjustment.adjust(manaCost, sa, null, test);
}
CostAdjustment.adjust(manaCost, sa, null, test, effect);
if ("NumTimes".equals(sa.getParam("Announce"))) { // e.g. the Adversary cycle
ManaCost mkCost = sa.getPayCosts().getTotalMana();
@@ -1773,15 +1771,18 @@ public class ComputerUtilMana {
/**
* Matches list of creatures to shards in mana cost for convoking.
* @param cost cost of convoked ability
* @param list creatures to be evaluated
* @param improvise
*
* @param cost cost of convoked ability
* @param list creatures to be evaluated
* @param artifacts
* @param creatures
* @return map between creatures and shards to convoke
*/
public static Map<Card, ManaCostShard> getConvokeOrImproviseFromList(final ManaCost cost, List<Card> list, boolean improvise) {
public static Map<Card, ManaCostShard> getConvokeOrImproviseFromList(final ManaCost cost, List<Card> list, boolean artifacts, boolean creatures) {
final Map<Card, ManaCostShard> convoke = new HashMap<>();
Card convoked = null;
if (!improvise) {
if (creatures && !artifacts) {
// Run for convoke but not improvise or waterbending
for (ManaCostShard toPay : cost) {
if (toPay.isSnow() || toPay.isColorless()) {
continue;

View File

@@ -1382,7 +1382,7 @@ public class PlayerControllerAi extends PlayerController {
}
@Override
public Map<Card, ManaCostShard> chooseCardsForConvokeOrImprovise(SpellAbility sa, ManaCost manaCost, CardCollectionView untappedCards, boolean improvise) {
public Map<Card, ManaCostShard> chooseCardsForConvokeOrImprovise(SpellAbility sa, ManaCost manaCost, CardCollectionView untappedCards, boolean artifacts, boolean creatures, Integer maxReduction) {
final Player ai = sa.getActivatingPlayer();
final PhaseHandler ph = ai.getGame().getPhaseHandler();
//Filter out mana sources that will interfere with payManaCost()
@@ -1390,9 +1390,10 @@ public class PlayerControllerAi extends PlayerController {
// Filter out creatures if AI hasn't attacked yet
if (ph.isPlayerTurn(ai) && ph.getPhase().isBefore(PhaseType.COMBAT_DECLARE_ATTACKERS)) {
if (improvise) {
if (!creatures) {
untapped = CardLists.filter(untapped, c -> !c.isCreature());
} else {
// TODO AI needs to learn how to use Convoke or Waterbend
return new HashMap<>();
}
}
@@ -1406,13 +1407,16 @@ public class PlayerControllerAi extends PlayerController {
if (!ai.getGame().getStack().isEmpty()) {
final List<GameObject> objects = ComputerUtil.predictThreatenedObjects(sa.getActivatingPlayer(), null);
for (Card c : blockers) {
if (objects.contains(c) && (!improvise || c.isArtifact())) {
if (objects.contains(c) && (creatures || c.isArtifact())) {
untapped.add(c);
}
if (maxReduction != null && untapped.size() >= maxReduction) {
break;
}
}
}
}
return ComputerUtilMana.getConvokeOrImproviseFromList(manaCost, untapped, improvise);
return ComputerUtilMana.getConvokeOrImproviseFromList(manaCost, untapped, artifacts, creatures);
}
@Override

View File

@@ -1,7 +1,5 @@
package forge.ai.ability;
import forge.ai.AiAbilityDecision;
import forge.ai.AiPlayDecision;
import forge.ai.*;
import forge.game.Game;
import forge.game.ability.AbilityUtils;

View File

@@ -776,7 +776,7 @@ public class StaticData {
Queue<String> TOKEN_Q = new ConcurrentLinkedQueue<>();
boolean nifHeader = false;
boolean cniHeader = false;
final Pattern funnyCardCollectorNumberPattern = Pattern.compile("^F\\d+");
final Pattern funnyCardCollectorNumberPattern = Pattern.compile("^F★?\\d+★?");
for (CardEdition e : editions) {
if (CardEdition.Type.FUNNY.equals(e.getType()))
continue;

View File

@@ -75,11 +75,13 @@ public class Game {
private List<Card> activePlanes = null;
public final Phase cleanup;
public final Phase endOfCombat;
public final Phase endOfTurn;
public final Untap untap;
public final Phase upkeep;
public final Phase beginOfCombat;
public final Phase endOfCombat;
public final Phase endOfTurn;
public final Phase cleanup;
// to execute commands for "current" phase each time state based action is checked
public final List<GameCommand> sbaCheckedCommandList;
public final MagicStack stack;
@@ -363,9 +365,10 @@ public class Game {
untap = new Untap(this);
upkeep = new Phase(PhaseType.UPKEEP);
cleanup = new Phase(PhaseType.CLEANUP);
beginOfCombat = new Phase(PhaseType.COMBAT_BEGIN);
endOfCombat = new Phase(PhaseType.COMBAT_END);
endOfTurn = new Phase(PhaseType.END_OF_TURN);
cleanup = new Phase(PhaseType.CLEANUP);
sbaCheckedCommandList = new ArrayList<>();
@@ -428,6 +431,9 @@ public class Game {
public final Phase getUpkeep() {
return upkeep;
}
public final Phase getBeginOfCombat() {
return beginOfCombat;
}
public final Phase getEndOfCombat() {
return endOfCombat;
}

View File

@@ -15,6 +15,7 @@ import forge.game.*;
import forge.game.ability.AbilityFactory.AbilityRecordType;
import forge.game.card.*;
import forge.game.cost.Cost;
import forge.game.cost.CostAdjustment;
import forge.game.cost.IndividualCostPaymentInstance;
import forge.game.keyword.Keyword;
import forge.game.keyword.KeywordInterface;
@@ -1527,6 +1528,7 @@ public class AbilityUtils {
else {
cost = new Cost(unlessCost, true);
}
cost = CostAdjustment.adjust(cost, sa, true);
return cost;
}

View File

@@ -23,7 +23,7 @@ public class ChooseSourceEffect extends SpellAbilityEffect {
sb.append(Lang.joinHomogenous(getTargetPlayers(sa)));
sb.append("chooses a source.");
sb.append(" chooses a source.");
return sb.toString();
}

View File

@@ -2,7 +2,6 @@ package forge.game.ability.effects;
import java.util.List;
import forge.GameCommand;
import forge.game.Game;
import forge.game.ability.AbilityUtils;
import forge.game.ability.SpellAbilityEffect;
@@ -28,10 +27,11 @@ public class ControlPlayerEffect extends SpellAbilityEffect {
public void resolve(SpellAbility sa) {
final Player controller = AbilityUtils.getDefinedPlayers(sa.getHostCard(), sa.getParam("Controller"), sa).get(0);
final Game game = controller.getGame();
final boolean combat = sa.hasParam("Combat");
for (final Player pTarget: getTargetPlayers(sa)) {
// before next untap gain control
game.getCleanup().addUntil(pTarget, (GameCommand) () -> {
(combat ? game.getBeginOfCombat() : game.getCleanup()).addUntil(pTarget, () -> {
// CR 800.4b
if (!controller.isInGame()) {
return;
@@ -41,7 +41,7 @@ public class ControlPlayerEffect extends SpellAbilityEffect {
pTarget.addController(ts, controller);
// after following cleanup release control
game.getCleanup().addUntil((GameCommand) () -> pTarget.removeController(ts));
(combat ? game.getEndOfCombat() : game.getCleanup()).addUntil(() -> pTarget.removeController(ts));
});
}
}

View File

@@ -140,6 +140,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
// stores the card traits created by static abilities
private final Table<StaticAbility, String, SpellAbility> storedSpellAbility = TreeBasedTable.create();
private final Table<StaticAbility, String, Trigger> storedTrigger = TreeBasedTable.create();
private final Table<StaticAbility, SpellAbility, SpellAbility> storedAbilityForTrigger = HashBasedTable.create();
private final Table<StaticAbility, String, ReplacementEffect> storedReplacementEffect = TreeBasedTable.create();
private final Table<StaticAbility, String, StaticAbility> storedStaticAbility = TreeBasedTable.create();
@@ -4974,7 +4975,15 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
String str = trig.toString() + trig.getId();
Trigger result = storedTrigger.get(stAb, str);
if (result == null) {
result = trig.copy(this, false);
SpellAbility ab = null;
if (trig.hasParam("Execute") && trig.getOverridingAbility() != null) {
ab = storedAbilityForTrigger.get(stAb, trig.getOverridingAbility());
if (ab == null) {
ab = trig.getOverridingAbility().copy(this, false);
storedAbilityForTrigger.put(stAb, trig.getOverridingAbility(), ab);
}
}
result = trig.copy(this, false, false, ab);
storedTrigger.put(stAb, str, result);
}
return result;

View File

@@ -79,6 +79,7 @@ public class CardState implements GameObject, IHasSVars, ITranslatable {
private FCollection<StaticAbility> staticAbilities = new FCollection<>();
private String imageKey = "";
private Map<String, String> sVars = Maps.newTreeMap();
private Map<String, SpellAbility> abilityForTrigger = Maps.newHashMap();
private KeywordCollection cachedKeywords = new KeywordCollection();
@@ -732,6 +733,11 @@ public class CardState implements GameObject, IHasSVars, ITranslatable {
setFlavorName(source.getFlavorName());
setSVars(source.getSVars());
abilityForTrigger.clear();
for (Map.Entry<String, SpellAbility> e : source.abilityForTrigger.entrySet()) {
abilityForTrigger.put(e.getKey(), e.getValue().copy(card, lki));
}
abilities.clear();
for (SpellAbility sa : source.abilities) {
if (sa.isIntrinsic()) {
@@ -758,7 +764,7 @@ public class CardState implements GameObject, IHasSVars, ITranslatable {
continue;
}
if (tr.isIntrinsic()) {
triggers.add(tr.copy(card, lki));
triggers.add(tr.copy(card, lki, false, tr.hasParam("Execute") ? abilityForTrigger.get(tr.getParam("Execute")) : null));
}
}
ReplacementEffect runRE = null;
@@ -951,6 +957,10 @@ public class CardState implements GameObject, IHasSVars, ITranslatable {
return cloakUp;
}
public SpellAbility getAbilityForTrigger(String svar) {
return abilityForTrigger.computeIfAbsent(svar, s -> AbilityFactory.getAbility(getCard(), s, this));
}
@Override
public String getTranslationKey() {
String displayName = flavorName == null ? name : flavorName;

View File

@@ -188,6 +188,15 @@ public class Cost implements Serializable {
return this.isAbility;
}
public final String getMaxWaterbend() {
for (CostPart cp : this.costParts) {
if (cp instanceof CostPartMana) {
return ((CostPartMana) cp).getMaxWaterbend();
}
}
return null;
}
private Cost() {
}
@@ -564,6 +573,11 @@ public class Cost implements Serializable {
return new CostRevealChosen(splitStr[0], splitStr.length > 1 ? splitStr[1] : null);
}
if (parse.startsWith("Waterbend<")) {
final String[] splitStr = abCostParse(parse, 1);
return new CostWaterbend(splitStr[0]);
}
if (parse.equals("Forage")) {
return new CostForage();
}
@@ -973,6 +987,7 @@ public class Cost implements Serializable {
} else {
costParts.add(0, new CostPartMana(manaCost.toManaCost(), null));
}
getCostMana().setMaxWaterbend(mPart.getMaxWaterbend());
} else if (part instanceof CostPutCounter || (mergeAdditional && // below usually not desired because they're from different causes
(part instanceof CostDiscard || part instanceof CostDraw ||
part instanceof CostAddMana || part instanceof CostPayLife ||

View File

@@ -31,11 +31,13 @@ import org.apache.commons.lang3.StringUtils;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.function.Predicate;
public class CostAdjustment {
public static Cost adjust(final Cost cost, final SpellAbility sa, boolean effect) {
if (sa.isTrigger() || cost == null || effect) {
sa.setMaxWaterbend(cost);
return cost;
}
@@ -99,6 +101,9 @@ public class CostAdjustment {
host.setState(CardStateName.Original, false);
host.setFaceDown(false);
}
sa.setMaxWaterbend(result);
return result;
}
@@ -171,21 +176,22 @@ public class CostAdjustment {
// If cardsToDelveOut is null, will immediately exile the delved cards and remember them on the host card.
// Otherwise, will return them in cardsToDelveOut and the caller is responsible for doing the above.
public static boolean adjust(ManaCostBeingPaid cost, final SpellAbility sa, CardCollection cardsToDelveOut, boolean test) {
if (sa.isTrigger() || sa.isReplacementAbility()) {
public static boolean adjust(ManaCostBeingPaid cost, final SpellAbility sa, CardCollection cardsToDelveOut, boolean test, boolean effect) {
if (effect) {
adjustCostByWaterbend(cost, sa, test);
}
if (effect || sa.isTrigger() || sa.isReplacementAbility()) {
return true;
}
final Game game = sa.getActivatingPlayer().getGame();
final Card originalCard = sa.getHostCard();
boolean isStateChangeToFaceDown = false;
if (sa.isSpell()) {
if (sa.isCastFaceDown() && !originalCard.isFaceDown()) {
// Turn face down to apply cost modifiers correctly
originalCard.turnFaceDownNoUpdate();
isStateChangeToFaceDown = true;
}
boolean isStateChangeToFaceDown = false;
if (sa.isSpell() && sa.isCastFaceDown() && !originalCard.isFaceDown()) {
// Turn face down to apply cost modifiers correctly
originalCard.turnFaceDownNoUpdate();
isStateChangeToFaceDown = true;
}
CardCollection cardsOnBattlefield = new CardCollection(game.getCardsIn(ZoneType.Battlefield));
@@ -278,17 +284,19 @@ public class CostAdjustment {
table.triggerChangesZoneAll(game, sa);
}
if (sa.getHostCard().hasKeyword(Keyword.CONVOKE)) {
adjustCostByConvokeOrImprovise(cost, sa, false, test);
adjustCostByConvokeOrImprovise(cost, sa, false, true, test);
}
if (sa.getHostCard().hasKeyword(Keyword.IMPROVISE)) {
adjustCostByConvokeOrImprovise(cost, sa, true, test);
adjustCostByConvokeOrImprovise(cost, sa, true, false, test);
}
} // isSpell
if (sa.hasParam("TapCreaturesForMana")) {
adjustCostByConvokeOrImprovise(cost, sa, false, test);
adjustCostByConvokeOrImprovise(cost, sa, false, true, test);
}
adjustCostByWaterbend(cost, sa, test);
// Reset card state (if changed)
if (isStateChangeToFaceDown) {
originalCard.setFaceDown(false);
@@ -299,6 +307,13 @@ public class CostAdjustment {
}
// GetSpellCostChange
private static void adjustCostByWaterbend(ManaCostBeingPaid cost, SpellAbility sa, boolean test) {
Integer maxWaterbend = sa.getMaxWaterbend();
if (maxWaterbend != null && maxWaterbend > 0) {
adjustCostByConvokeOrImprovise(cost, sa, true, true, test);
}
}
private static boolean adjustCostByAssist(ManaCostBeingPaid cost, final SpellAbility sa, boolean test) {
// 702.132a Assist is a static ability that modifies the rules of paying for the spell with assist (see rules 601.2g-h).
// If the total cost to cast a spell with assist includes a generic mana component, before you activate mana abilities while casting it, you may choose another player.
@@ -321,27 +336,33 @@ public class CostAdjustment {
return assistant.getController().helpPayForAssistSpell(cost, sa, genericLeft, requestedAmount);
}
private static void adjustCostByConvokeOrImprovise(ManaCostBeingPaid cost, final SpellAbility sa, boolean improvise, boolean test) {
if (!improvise) {
private static void adjustCostByConvokeOrImprovise(ManaCostBeingPaid cost, final SpellAbility sa, boolean artifacts, boolean creatures, boolean test) {
if (creatures && !artifacts) {
sa.clearTappedForConvoke();
}
final Player activator = sa.getActivatingPlayer();
CardCollectionView untappedCards = CardLists.filter(activator.getCardsIn(ZoneType.Battlefield),
CardPredicates.CAN_TAP);
if (improvise) {
Integer maxReduction = null;
if (artifacts && creatures) {
maxReduction = sa.getMaxWaterbend();
Predicate <Card> isArtifactOrCreature = card -> card.isArtifact() || card.isCreature();
untappedCards = CardLists.filter(untappedCards, isArtifactOrCreature);
} else if (artifacts) {
untappedCards = CardLists.filter(untappedCards, CardPredicates.ARTIFACTS);
} else {
untappedCards = CardLists.filter(untappedCards, CardPredicates.CREATURES);
}
Map<Card, ManaCostShard> convokedCards = activator.getController().chooseCardsForConvokeOrImprovise(sa,
cost.toManaCost(), untappedCards, improvise);
cost.toManaCost(), untappedCards, artifacts, creatures, maxReduction);
CardCollection tapped = new CardCollection();
for (final Entry<Card, ManaCostShard> conv : convokedCards.entrySet()) {
Card c = conv.getKey();
if (!improvise) {
if (creatures && !artifacts) {
sa.addTappedForConvoke(c);
}
cost.decreaseShard(conv.getValue(), 1);

View File

@@ -39,6 +39,8 @@ public class CostPartMana extends CostPart {
private boolean isEnchantedCreatureCost = false;
private boolean isCostPayAnyNumberOfTimes = false;
protected String maxWaterbend;
public int paymentOrder() { return shouldPayLast() ? 200 : 0; }
public boolean shouldPayLast() {
@@ -63,6 +65,13 @@ public class CostPartMana extends CostPart {
this.isEnchantedCreatureCost = enchantedCreatureCost;
}
public String getMaxWaterbend() {
return maxWaterbend;
}
public void setMaxWaterbend(String max) {
maxWaterbend = max;
}
/**
* Gets the mana.
*
@@ -101,7 +110,7 @@ public class CostPartMana extends CostPart {
public boolean isUndoable() { return true; }
@Override
public final String toString() {
public String toString() {
return cost.toString();
}

View File

@@ -0,0 +1,18 @@
package forge.game.cost;
import forge.card.mana.ManaCost;
import forge.card.mana.ManaCostParser;
public class CostWaterbend extends CostPartMana {
public CostWaterbend(final String mana) {
super(new ManaCost(new ManaCostParser(mana)), null);
maxWaterbend = mana;
}
@Override
public final String toString() {
return "Waterbend " + getMana().toString();
}
}

View File

@@ -297,6 +297,7 @@ public class PhaseHandler implements java.io.Serializable {
case COMBAT_BEGIN:
nCombatsThisTurn++;
combat = new Combat(playerTurn);
game.getBeginOfCombat().executeUntil(playerTurn);
//PhaseUtil.verifyCombat();
break;
@@ -756,7 +757,6 @@ public class PhaseHandler implements java.io.Serializable {
}
}
}
// fire blockers declared trigger
final Map<AbilityKey, Object> bdRunParams = AbilityKey.newMap();
bdRunParams.put(AbilityKey.Blockers, declaredBlockers);
bdRunParams.put(AbilityKey.Attackers, blockedAttackers);
@@ -768,7 +768,6 @@ public class PhaseHandler implements java.io.Serializable {
continue;
}
// Run triggers
final Map<AbilityKey, Object> runParams = AbilityKey.newMap();
runParams.put(AbilityKey.Blocker, c1);
runParams.put(AbilityKey.Attackers, combat.getAttackersBlockedBy(c1));

View File

@@ -202,7 +202,7 @@ public abstract class PlayerController {
public abstract CardCollection chooseCardsToDiscardToMaximumHandSize(int numDiscard);
public abstract CardCollectionView chooseCardsToDelve(int genericAmount, CardCollection grave);
public abstract Map<Card, ManaCostShard> chooseCardsForConvokeOrImprovise(SpellAbility sa, ManaCost manaCost, CardCollectionView untappedCards, boolean improvise);
public abstract Map<Card, ManaCostShard> chooseCardsForConvokeOrImprovise(SpellAbility sa, ManaCost manaCost, CardCollectionView untappedCards, boolean artifacts, boolean creatures, Integer maxReduction);
public abstract List<Card> chooseCardsForSplice(SpellAbility sa, List<Card> cards);
public abstract CardCollectionView chooseCardsToRevealFromHand(int min, int max, CardCollectionView valid);

View File

@@ -144,6 +144,7 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
private final Supplier<CardCollection> tappedForConvoke = Suppliers.memoize(CardCollection::new);
private Card sacrificedAsOffering;
private Card sacrificedAsEmerge;
private Integer maxWaterbend;
private AbilityManaPart manaPart;
@@ -2692,4 +2693,14 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
public void setName(String name) {
this.name = name;
}
public Integer getMaxWaterbend() {
return maxWaterbend;
}
public void setMaxWaterbend(Cost cost) {
if (cost == null || cost.getMaxWaterbend() == null) {
return;
}
maxWaterbend = AbilityUtils.calculateAmount(getHostCard(), cost.getMaxWaterbend(), this);
}
}

View File

@@ -544,14 +544,19 @@ public abstract class Trigger extends TriggerReplacementBase {
}
public final Trigger copy(Card newHost, boolean lki) {
return copy(newHost, lki, false);
return copy(newHost, lki, false, null);
}
public final Trigger copy(Card newHost, boolean lki, boolean keepTextChanges) {
return copy(newHost, lki, keepTextChanges, null);
}
public final Trigger copy(Card newHost, boolean lki, boolean keepTextChanges, SpellAbility spellAbility) {
final Trigger copy = (Trigger) clone();
copyHelper(copy, newHost, lki || keepTextChanges);
if (getOverridingAbility() != null) {
if (spellAbility != null) {
copy.setOverridingAbility(spellAbility);
} else if (getOverridingAbility() != null) {
copy.setOverridingAbility(getOverridingAbility().copy(newHost, lki));
}
@@ -611,7 +616,11 @@ public abstract class Trigger extends TriggerReplacementBase {
public SpellAbility ensureAbility(final IHasSVars sVarHolder) {
SpellAbility sa = getOverridingAbility();
if (sa == null && hasParam("Execute")) {
sa = AbilityFactory.getAbility(getHostCard(), getParam("Execute"), sVarHolder);
if (this.isIntrinsic() && sVarHolder instanceof CardState state) {
sa = state.getAbilityForTrigger(getParam("Execute"));
} else {
sa = AbilityFactory.getAbility(getHostCard(), getParam("Execute"), sVarHolder);
}
setOverridingAbility(sa);
}
return sa;

View File

@@ -428,6 +428,10 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
game.getTriggerHandler().runTrigger(TriggerType.AbilityCast, runParams, true);
}
if (sp.getMaxWaterbend() != null) {
activator.triggerElementalBend(TriggerType.Waterbend);
}
// Run Cycled triggers
if (sp.isCycling()) {
activator.addCycled(sp);

View File

@@ -690,7 +690,7 @@ public class PlayerControllerForTests extends PlayerController {
@Override
public Map<Card, ManaCostShard> chooseCardsForConvokeOrImprovise(SpellAbility sa, ManaCost manaCost,
CardCollectionView untappedCards, boolean improvise) {
CardCollectionView untappedCards, boolean artifacts, boolean creatures, Integer maxReduction) {
// TODO: AI to choose a creature to tap would go here
// Probably along with deciding how many creatures to tap
return new HashMap<>();

View File

@@ -450,7 +450,9 @@ public class EnemySprite extends CharacterSprite implements Steerable<Vector2> {
.filter(paperCard -> !paperCard.isVeryBasicLand())
.collect(Collectors.toList());
if (paperCardList.size() < 6) {
int uniqueRules = paperCardList.stream().map(PaperCard::getRules).collect(Collectors.toSet()).size();
if (uniqueRules < 4 || paperCardList.size() < 10) {
// Player trying to cheese doppleganger and farm cards. Sorry, the fun police have arrived
// Static rewards of 199 GP, 9 Shards, and 1 Cheese Stands Alone
rewards.add(new Reward(199));
@@ -466,7 +468,7 @@ public class EnemySprite extends CharacterSprite implements Steerable<Vector2> {
if (AdventurePlayer.current().isFantasyMode()) {
//random uncommons from deck
List<PaperCard> uncommonCards = paperCardList.stream()
.filter(paperCard -> CardRarity.Uncommon.equals(paperCard.getRarity()) || CardRarity.Special.equals(paperCard.getRarity()))
.filter(paperCard -> paperCard.getRarity() == CardRarity.Uncommon || paperCard.getRarity() == CardRarity.Special)
.collect(Collectors.toList());
if (!uncommonCards.isEmpty()) {
rewards.add(new Reward(Aggregates.random(uncommonCards)));
@@ -474,7 +476,7 @@ public class EnemySprite extends CharacterSprite implements Steerable<Vector2> {
}
//random commons from deck
List<PaperCard> commmonCards = paperCardList.stream()
.filter(paperCard -> CardRarity.Common.equals(paperCard.getRarity()))
.filter(paperCard -> paperCard.getRarity() == CardRarity.Common)
.collect(Collectors.toList());
if (!commmonCards.isEmpty()) {
rewards.add(new Reward(Aggregates.random(commmonCards)));
@@ -483,7 +485,7 @@ public class EnemySprite extends CharacterSprite implements Steerable<Vector2> {
}
//random rare from deck
List<PaperCard> rareCards = paperCardList.stream()
.filter(paperCard -> CardRarity.Rare.equals(paperCard.getRarity()) || CardRarity.MythicRare.equals(paperCard.getRarity()))
.filter(paperCard -> paperCard.getRarity() == CardRarity.Rare || paperCard.getRarity() == CardRarity.MythicRare)
.collect(Collectors.toList());
if (!rareCards.isEmpty()) {
rewards.add(new Reward(Aggregates.random(rareCards)));

View File

@@ -175,17 +175,17 @@ public class AdventureEventData implements Serializable {
private static final Predicate<CardEdition> filterStandard = FModel.getFormats().getStandard().editionLegalPredicate;
public static Predicate<CardEdition> selectSetPool() {
// Should we negate any of these to avoid overlap?
final int rollD100 = MyRandom.getRandom().nextInt(100);
Predicate<CardEdition> rolledFilter;
if (rollD100 < 30) {
rolledFilter = filterStandard;
} else if (rollD100 < 60) {
rolledFilter = filterPioneer;
// Remove standard from older pools because its representation is already inflated.
rolledFilter = filterPioneer.and(filterStandard.negate());
} else if (rollD100 < 80) {
rolledFilter = filterModern;
rolledFilter = filterModern.and(filterStandard.negate());
} else {
rolledFilter = filterVintage;
rolledFilter = filterVintage.and(filterStandard.negate());
}
return rolledFilter;
}
@@ -195,21 +195,33 @@ public class AdventureEventData implements Serializable {
private static CardBlock pickWeightedCardBlock() {
CardEdition.Collection editions = FModel.getMagicDb().getEditions();
ConfigData configData = Config.instance().getConfigData();
Predicate<CardEdition> filter = CardEdition.Predicates.CAN_MAKE_BOOSTER.and(selectSetPool());
Predicate<CardEdition> filter = CardEdition.Predicates.CAN_MAKE_BOOSTER;
if(configData.restrictedEvents != null) {
//Temporary restriction until rewards are more diverse - don't want to award restricted cards so these editions need different rewards added.
//Also includes sets that use conspiracy or commander drafts.
Set<String> restrictedEvents = Set.of(configData.restrictedEvents);
filter = filter.and((q) -> !restrictedEvents.contains(q.getCode()));
if(configData.allowedEvents != null && configData.allowedEvents.length > 0) {
Set<String> allowedEvents = Set.of(configData.allowedEvents);
filter = filter.and(q -> allowedEvents.contains(q.getCode()));
}
if (configData.allowedEditions != null) {
Set<String> allowed = Set.of(configData.allowedEditions);
filter = filter.and(q -> allowed.contains(q.getCode()));
} else {
List<String> restrictedList = Arrays.asList(configData.restrictedEditions);
Set<String> restricted = new HashSet<>(restrictedList); //Would use Set.of but that throws an error if there's any duplicates, and users edit these lists all the time.
filter = filter.and(q -> !restricted.contains(q.getCode()));
else
{
//The whitelist beats all other filters.
if(configData.restrictedEvents != null) {
//Temporary restriction until rewards are more diverse - don't want to award restricted cards so these editions need different rewards added.
//Also includes sets that use conspiracy or commander drafts.
Set<String> restrictedEvents = Set.of(configData.restrictedEvents);
filter = filter.and((q) -> !restrictedEvents.contains(q.getCode()));
}
if (configData.allowedEditions != null && configData.allowedEditions.length > 0) {
Set<String> allowed = Set.of(configData.allowedEditions);
filter = filter.and(q -> allowed.contains(q.getCode()));
} else if(configData.restrictedEditions != null) {
List<String> restrictedList = Arrays.asList(configData.restrictedEditions);
Set<String> restricted = new HashSet<>(restrictedList); //Would use Set.of but that throws an error if there's any duplicates, and users edit these lists all the time.
filter = filter.and(q -> !restricted.contains(q.getCode()));
}
Predicate<CardEdition> setPoolFilter = selectSetPool();
if(editions.stream().anyMatch(setPoolFilter))
filter = filter.and(setPoolFilter);
}
List<CardEdition> allEditions = new ArrayList<>();

View File

@@ -24,5 +24,6 @@ public class ConfigData {
public String[] restrictedEditions;
public String[] allowedEditions;
public String[] restrictedEvents;
public String[] allowedEvents;
public String[] allowedJumpstart;
}

View File

@@ -1,4 +1,5 @@
Name:Agent Venom
Variant:UniversesWithin:FlavorName:Rhilex the Accursed
ManaCost:2 B
Types:Legendary Creature Symbiote Soldier Hero
PT:2/3

View File

@@ -1,4 +1,5 @@
Name:Alien Symbiosis
Variant:UniversesWithin:FlavorName:Aggressive Symbiosis
ManaCost:1 B
Types:Enchantment Aura
K:Enchant:Creature

View File

@@ -1,4 +1,5 @@
Name:Amazing Acrobatics
Variant:UniversesWithin:FlavorName:Drix Interception
ManaCost:1 U U
Types:Instant
A:SP$ Charm | MinCharmNum$ 1 | CharmNum$ 2 | Choices$ DBCounter,DBTap

View File

@@ -1,4 +1,5 @@
Name:Angry Rabble
Variant:UniversesWithin:FlavorName:Galvanized Workforce
ManaCost:1 R
Types:Creature Human Citizen
PT:2/2

View File

@@ -1,4 +1,5 @@
Name:Anti-Venom, Horrifying Healer
Variant:UniversesWithin:FlavorName:Verilax the Havenskin
ManaCost:W W W W W
Types:Legendary Creature Symbiote Hero
PT:5/5

View File

@@ -3,7 +3,7 @@ ManaCost:U
Types:Enchantment Aura
K:Enchant:Creature
SVar:AttachAILogic:Curse
R:Event$ Untap | ActiveZones$ Battlefield | ValidCard$ Creature.EnchantedBy | ValidStepTurnToController$ You | Layer$ CantHappen | Description$ Enchanted creature doesn't untap during its controller's untap step. At the beginning of the upkeep of enchanted creature's controller, that player may discard a card at random. If the player does, untap that creature.
R:Event$ Untap | ActiveZones$ Battlefield | ValidCard$ Creature.EnchantedBy | ValidStepTurnToController$ You | Layer$ CantHappen | Description$ Enchanted creature doesn't untap during its controller's untap step.
T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ Player.EnchantedController | TriggerZones$ Battlefield | OptionalDecider$ EnchantedController | Execute$ ApathyDiscard | TriggerDescription$ At the beginning of the upkeep of enchanted creature's controller, that player may discard a card at random. If the player does, untap that creature.
SVar:ApathyDiscard:DB$ Discard | Defined$ TriggeredPlayer | Mode$ Random | RememberDiscarded$ True | SubAbility$ ApathyUntap
SVar:ApathyUntap:DB$ Untap | Defined$ Enchanted | SpellDescription$ Untap enchanted creature | ConditionCheckSVar$ X | ConditionSVarCompare$ EQ1 | SubAbility$ DBCleanup

View File

@@ -1,4 +1,5 @@
Name:Arachne, Psionic Weaver
Variant:UniversesWithin:FlavorName:Yera and Oski, Weaver and Guide
ManaCost:2 W
Types:Legendary Creature Spider Human Hero
PT:3/3

View File

@@ -1,4 +1,5 @@
Name:Araña, Heart of the Spider
Variant:UniversesWithin:FlavorName:Gloria, the Great Armorer
ManaCost:1 R W
Types:Legendary Creature Spider Human Hero
PT:3/3

View File

@@ -1,4 +1,5 @@
Name:Aunt May
Variant:UniversesWithin:FlavorName:Zora, Spider Fancier
ManaCost:W
Types:Legendary Creature Human Citizen
PT:0/2

View File

@@ -1,4 +1,5 @@
Name:Bagel and Schmear
Variant:UniversesWithin:FlavorName:Perfected Pastry
ManaCost:1
Types:Artifact Food
A:AB$ PutCounter | PrecostDesc$ Share — | Cost$ W T Sac<1/CARDNAME> | TargetMin$ 0 | TargetMax$ 1 | ValidTgts$ Creature | TgtPrompt$ Select target creature | CounterType$ P1P1 | CounterNum$ 1 | SubAbility$ DBDraw | SorcerySpeed$ True | SpellDescription$ Put a +1/+1 counter on up to one target creature. Draw a card. Activate only as a sorcery.

View File

@@ -1,4 +1,5 @@
Name:Beetle, Legacy Criminal
Variant:UniversesWithin:FlavorName:Arala, Hedron Scaler
ManaCost:3 U
Types:Legendary Creature Human Rogue Villain
PT:3/3

View File

@@ -1,4 +1,5 @@
Name:Behold the Sinister Six!
Variant:UniversesWithin:FlavorName:Hex of Undeath
ManaCost:6 B
Types:Sorcery
A:SP$ ChangeZone | Origin$ Graveyard | Destination$ Battlefield | TgtPrompt$ Choose up to six target creature cards with different names in your graveyard | ValidTgts$ Creature.YouOwn | TargetsWithDifferentNames$ True | TargetMin$ 0 | TargetMax$ 6 | SpellDescription$ Return up to six target creature cards with different names from your graveyard to the battlefield.

View File

@@ -1,4 +1,5 @@
Name:Biorganic Carapace
Variant:UniversesWithin:FlavorName:Angler's Shield
ManaCost:2 W U
Types:Artifact Equipment
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigAttach | TriggerDescription$ When this Equipment enters, attach it to target creature you control.

View File

@@ -1,4 +1,5 @@
Name:Black Cat, Cunning Thief
Variant:UniversesWithin:FlavorName:Wrench, Speedway Saboteur
ManaCost:3 B B
Types:Legendary Creature Human Rogue Villain
PT:2/3

View File

@@ -1,4 +1,5 @@
Name:Carnage, Crimson Chaos
Variant:UniversesWithin:FlavorName:Desecrex, Gift of Servitude
ManaCost:2 B R
Types:Legendary Creature Symbiote Villain
PT:4/3

View File

@@ -1,4 +1,5 @@
Name:Chameleon, Master of Disguise
Variant:UniversesWithin:FlavorName:Vazin, Two-Faced Trickster
ManaCost:3 U
Types:Legendary Creature Human Shapeshifter Villain
PT:2/3

View File

@@ -3,6 +3,6 @@ ManaCost:1 G
Types:Sorcery
A:SP$ Pump | ValidTgts$ Creature.YouCtrl | TgtPrompt$ Select target creature you control | SubAbility$ DBDamage | AILogic$ PowerDmg | StackDescription$ {c:ThisTargetedCard} | SpellDescription$ Target creature you control
SVar:DBDamage:DB$ DealDamage | ValidTgts$ Creature | TgtPrompt$ Select another target creature | TargetUnique$ True | AILogic$ PowerDmg | NumDmg$ X | DamageSource$ ParentTarget | ExcessSVar$ Excess | SubAbility$ DBDiscover | StackDescription$ REP another target creature_{c:ThisTargetedCard} | SpellDescription$ deals damage equal to its power to another target creature.
SVar:DBDiscover:DB$ Discover | Num$ Excess | StackDescription$ SpellDescription | SpellDescription$ If excess damage was dealt this way, discover X, where X is that excess damage. (Exile cards from the top of your library until you exile a nonland card with that mana value or less. Cast it without paying its mana cost or put it into your hand. Put the rest on the bottom in a random order.)
SVar:DBDiscover:DB$ Discover | Num$ Excess | ConditionCheckSVar$ Excess | StackDescription$ SpellDescription | SpellDescription$ If excess damage was dealt this way, discover X, where X is that excess damage. (Exile cards from the top of your library until you exile a nonland card with that mana value or less. Cast it without paying its mana cost or put it into your hand. Put the rest on the bottom in a random order.)
SVar:X:ParentTargeted$CardPower
Oracle:Target creature you control deals damage equal to its power to another target creature. If excess damage was dealt this way, discover X, where X is that excess damage. (Exile cards from the top of your library until you exile a nonland card with that mana value or less. Cast it without paying its mana cost or put it into your hand. Put the rest on the bottom in a random order.)

View File

@@ -3,12 +3,8 @@ ManaCost:4 U
Types:Enchantment
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigIncubate | TriggerDescription$ When CARDNAME enters, incubate 4. (Create an Incubator token with four +1/+1 counters on it and "{2}: Transform this artifact." It transforms into a 0/0 Phyrexian artifact creature.)
SVar:TrigIncubate:DB$ Incubate | Amount$ 4
T:Mode$ Transformed | ValidCard$ Permanent.YouCtrl+inZoneBattlefield | Execute$ TrigDraw | TriggerZones$ Battlefield | OptionalDecider$ You | CheckSVar$ X | SVarCompare$ LT1 | TriggerDescription$ Whenever a permanent you control transforms or a permanent you control enters transformed, you may draw a card. Do this only once each turn.
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Permanent.Transformed+YouCtrl | OptionalDecider$ You | TriggerZones$ Battlefield | Execute$ TrigDraw | Secondary$ True | CheckSVar$ X | SVarCompare$ LT1 | TriggerDescription$ Whenever a permanent you control transforms or a permanent you control enters transformed, you may draw a card. Do this only once each turn.
SVar:TrigDraw:DB$ Draw | SubAbility$ DBLog
SVar:DBLog:DB$ StoreSVar | SVar$ X | Type$ Number | Expression$ 1
SVar:X:Number$0
T:Mode$ Phase | Phase$ Cleanup | TriggerZones$ Battlefield | Execute$ DBCleanup | Static$ True
SVar:DBCleanup:DB$ StoreSVar | SVar$ X | Type$ Number | Expression$ 0
T:Mode$ Transformed | ValidCard$ Permanent.YouCtrl+inZoneBattlefield | Execute$ TrigDraw | TriggerZones$ Battlefield | OptionalDecider$ You | ResolvedLimit$ 1 | TriggerDescription$ Whenever a permanent you control transforms or a permanent you control enters transformed, you may draw a card. Do this only once each turn.
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Permanent.Transformed+YouCtrl | OptionalDecider$ You | TriggerZones$ Battlefield | Execute$ TrigDraw | Secondary$ True | ResolvedLimit$ 1 | TriggerDescription$ Whenever a permanent you control transforms or a permanent you control enters transformed, you may draw a card. Do this only once each turn.
SVar:TrigDraw:DB$ Draw
DeckHas:Ability$Counters|Token & Type$Incubator|Artifact|Phyrexian
Oracle:When Corruption of Towashi enters, incubate 4. (Create an Incubator token with four +1/+1 counters on it and "{2}: Transform this artifact." It transforms into a 0/0 Phyrexian artifact creature.)\nWhenever a permanent you control transforms or a permanent you control enters transformed, you may draw a card. Do this only once each turn.

View File

@@ -1,4 +1,5 @@
Name:Cosmic Spider-Man
Variant:UniversesWithin:FlavorName:Scions of the Ur-Spider
ManaCost:W U B R G
Types:Legendary Creature Spider Human Hero
PT:5/5

View File

@@ -1,4 +1,5 @@
Name:Daily Bugle Building
Variant:UniversesWithin:FlavorName:Fearsome Ridgeline
ManaCost:no cost
Types:Land
A:AB$ Mana | Cost$ T | Produced$ C | SpellDescription$ Add {C}.

View File

@@ -1,4 +1,5 @@
Name:Daily Bugle Reporters
Variant:UniversesWithin:FlavorName:Principled Referee
ManaCost:3 W
Types:Creature Human Citizen
PT:2/3

View File

@@ -1,4 +1,5 @@
Name:Damage Control Crew
Variant:UniversesWithin:FlavorName:Selesnya Archivist
ManaCost:3 G
Types:Creature Human Citizen
PT:3/3

View File

@@ -1,4 +1,5 @@
Name:Doc Ock, Sinister Scientist
Variant:UniversesWithin:FlavorName:Ozor, Chronicler of Collapse
ManaCost:4 U
Types:Legendary Creature Human Scientist Villain
PT:4/5

View File

@@ -1,4 +1,5 @@
Name:Doc Ock's Henchmen
Variant:UniversesWithin:FlavorName:Obscura Alleylurkers
ManaCost:2 U
Types:Creature Human Villain
PT:2/1

View File

@@ -1,4 +1,5 @@
Name:Doc Ock's Tentacles
Variant:UniversesWithin:FlavorName:Giantcraft Helm
ManaCost:1
Types:Artifact Equipment
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Creature.YouCtrl+cmcGE5 | TriggerZones$ Battlefield | Execute$ TrigAttach | OptionalDecider$ You | TriggerDescription$ Whenever a creature you control with mana value 5 or greater enters, you may attach this Equipment to it.

View File

@@ -1,4 +1,5 @@
Name:Doctor Octopus, Master Planner
Variant:UniversesWithin:FlavorName:Neach, Pinnacle Pariah
ManaCost:5 U B
Types:Legendary Creature Human Scientist Villain
PT:4/8

View File

@@ -1,4 +1,5 @@
Name:Eddie Brock
Variant:UniversesWithin:FlavorName:Viggo, Enforcer of Ig's Crossing
ManaCost:2 B
Types:Legendary Creature Human Hero Villain
PT:3/3
@@ -12,6 +13,7 @@ Oracle:When Eddie Brock enters, return target creature card with mana value 1 or
ALTERNATE
Name:Venom, Lethal Protector
Variant:UniversesWithin:FlavorName:Viggo, End of Ig's Crossing
ManaCost:3 B R G
Types:Legendary Creature Symbiote Hero Villain
PT:5/5

View File

@@ -1,4 +1,5 @@
Name:Electro, Assaulting Battery
Variant:UniversesWithin:FlavorName:Bayo, Irritable Instructor
ManaCost:1 R R
Types:Legendary Creature Human Villain
PT:2/3

View File

@@ -1,4 +1,5 @@
Name:Electro's Bolt
Variant:UniversesWithin:FlavorName:Deathflame Burst
ManaCost:2 R
Types:Sorcery
A:SP$ DealDamage | ValidTgts$ Creature | NumDmg$ 4 | SpellDescription$ CARDNAME deals 4 damage to target creature.

View File

@@ -1,4 +1,5 @@
Name:Ezekiel Sims, Spider-Totem
Variant:UniversesWithin:FlavorName:Orris, Last of the Web Lords
ManaCost:4 G
Types:Legendary Creature Spider Human Advisor
PT:3/5

View File

@@ -1,4 +1,5 @@
Name:Flash Thompson, Spider-Fan
Variant:UniversesWithin:FlavorName:Basil, Cabaretti Loudmouth
ManaCost:1 W
Types:Legendary Creature Human Citizen
PT:2/2

View File

@@ -1,4 +1,5 @@
Name:Flying Octobot
Variant:UniversesWithin:FlavorName:Vexed Bots
ManaCost:1 U
Types:Artifact Creature Robot Villain
PT:1/1

View File

@@ -1,4 +1,5 @@
Name:Friendly Neighborhood
Variant:UniversesWithin:FlavorName:Remarkable Readings
ManaCost:3 W
Types:Enchantment Aura
K:Enchant:Land

View File

@@ -1,4 +1,5 @@
Name:Green Goblin, Revenant
Variant:UniversesWithin:FlavorName:Nu and Sumi, Career Criminals
ManaCost:3 B R
Types:Legendary Creature Goblin Human Villain
PT:3/3

View File

@@ -1,4 +1,5 @@
Name:Guy in the Chair
Variant:UniversesWithin:FlavorName:Eccentric Arachnologist
ManaCost:2 G
Types:Creature Human Advisor
PT:2/3

View File

@@ -1,4 +1,5 @@
Name:Gwen Stacy
Variant:UniversesWithin:FlavorName:Nia, Skysail Storyteller
ManaCost:1 R
Types:Legendary Creature Human Performer Hero
PT:2/1
@@ -14,6 +15,7 @@ Oracle:When Gwen Stacy enters, exile the top card of your library. You may play
ALTERNATE
Name:Ghost-Spider
Variant:UniversesWithin:FlavorName:Nia, Fabled Skyclimber
ManaCost:2 U R W
Types:Legendary Creature Spider Human Hero
PT:4/4

View File

@@ -1,4 +1,5 @@
Name:Gwenom, Remorseless
Variant:UniversesWithin:FlavorName:Egrix the Bile Bulwark
ManaCost:3 B B
Types:Legendary Creature Symbiote Spider Hero
PT:4/4

View File

@@ -1,4 +1,5 @@
Name:Heroes' Hangout
Variant:UniversesWithin:FlavorName:Fire-Brained Scheme
ManaCost:R
Types:Sorcery
A:SP$ Charm | Choices$ DBDateNight,DBPatrolNight

View File

@@ -1,4 +1,5 @@
Name:Hide on the Ceiling
Variant:UniversesWithin:FlavorName:Spectral Restitching
ManaCost:X U
Types:Instant
A:SP$ ChangeZone | ValidTgts$ Artifact,Creature | TgtPrompt$ Select X target artifacts and/or creatures | TargetMin$ X | TargetMax$ X | Origin$ Battlefield | Destination$ Exile | RememberChanged$ True | SubAbility$ DBDelTrig | SpellDescription$ Exile X target artifacts and/or creatures. Return the exiled cards to the battlefield under their owners' control at the beginning of the next end step.

View File

@@ -1,4 +1,5 @@
Name:Hobgoblin, Mantled Marauder
Variant:UniversesWithin:FlavorName:Cam and Farrik, Havoc Duo
ManaCost:1 R
Types:Legendary Creature Goblin Human Villain
PT:1/2

View File

@@ -1,4 +1,5 @@
Name:Hot Dog Cart
Variant:UniversesWithin:FlavorName:Treat Trolley
ManaCost:3
Types:Artifact
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigFood | TriggerDescription$ When this artifact enters, create a Food token. (It's an artifact with "{2}, {T}, Sacrifice this token: You gain 3 life.")

View File

@@ -1,4 +1,5 @@
Name:Hydro-Man, Fluid Felon
Variant:UniversesWithin:FlavorName:Belion, the Parched
ManaCost:U U
Types:Legendary Creature Elemental Villain
PT:2/2

View File

@@ -1,4 +1,5 @@
Name:Inner Demons Gangsters
Variant:UniversesWithin:FlavorName:Caldaia Brawlers
ManaCost:3 B
Types:Creature Human Rogue Villain
PT:3/4

View File

@@ -1,4 +1,5 @@
Name:Interdimensional Web Watch
Variant:UniversesWithin:FlavorName:Reality Fulcrum
ManaCost:4
Types:Artifact
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigExile | TriggerDescription$ When this artifact enters, exile the top two cards of your library. Until the end of your next turn, you may play those cards.

View File

@@ -1,4 +1,5 @@
Name:Iron Spider, Stark Upgrade
Variant:UniversesWithin:FlavorName:Fizik, Etherium Mechanic
ManaCost:3
Types:Legendary Artifact Creature Spider Hero
PT:2/3

View File

@@ -1,4 +1,5 @@
Name:J. Jonah Jameson
Variant:UniversesWithin:FlavorName:Lazlo, Enthusiastic Accuser
ManaCost:2 R
Types:Legendary Creature Human Citizen
PT:2/2

View File

@@ -1,4 +1,5 @@
Name:Jackal, Genius Geneticist
Variant:UniversesWithin:FlavorName:Druneth, Reviver of the Hive
ManaCost:G U
Types:Legendary Creature Human Scientist Villain
PT:1/1

View File

@@ -1,4 +1,5 @@
Name:Kapow!
Variant:UniversesWithin:FlavorName:Perilous Lunge
ManaCost:2 G
Types:Sorcery
A:SP$ PutCounter | ValidTgts$ Creature.YouCtrl | TgtPrompt$ Select target creature you control | CounterType$ P1P1 | CounterNum$ 1 | SubAbility$ DBFight | SpellDescription$ Put a +1/+1 counter on target creature you control. It fights target creature an opponent controls. (Each deals damage equal to its power to the other.)

View File

@@ -1,4 +1,5 @@
Name:Kraven, Proud Predator
Variant:UniversesWithin:FlavorName:Dreadfang, Loathed by Fans
ManaCost:1 R G
Types:Legendary Creature Human Warrior Villain
PT:*/4

View File

@@ -1,4 +1,5 @@
Name:Kraven the Hunter
Variant:UniversesWithin:FlavorName:Brako, Heartless Hunter
ManaCost:1 B G
Types:Legendary Creature Human Warrior Villain
PT:4/3

View File

@@ -1,4 +1,5 @@
Name:Kraven's Cats
Variant:UniversesWithin:FlavorName:Cruel Caracals
ManaCost:1 G
Types:Creature Cat Villain
PT:2/2

View File

@@ -1,4 +1,5 @@
Name:Kraven's Last Hunt
Variant:UniversesWithin:FlavorName:A Trail of Teacups
ManaCost:3 G
Types:Enchantment Saga
K:Chapter:3:DBMill,DBPump,DBReturn

View File

@@ -1,4 +1,5 @@
Name:Lady Octopus, Inspired Inventor
Variant:UniversesWithin:FlavorName:Merata, Neuron Hacker
ManaCost:U
Types:Legendary Creature Human Scientist Villain
PT:0/2

View File

@@ -1,4 +1,5 @@
Name:Living Brain, Mechanical Marvel
Variant:UniversesWithin:FlavorName:Error-9, Viral Node
ManaCost:4
Types:Legendary Artifact Creature Robot Villain
PT:3/3

View File

@@ -1,4 +1,5 @@
Name:Lizard, Connors's Curse
Variant:UniversesWithin:FlavorName:King of the Coldblood Curse
ManaCost:2 G G
Types:Legendary Creature Lizard Villain
PT:5/5

View File

@@ -1,4 +1,5 @@
Name:Madame Web, Clairvoyant
Variant:UniversesWithin:FlavorName:Olx, Mouth to Many Eyes
ManaCost:4 U U
Types:Legendary Creature Mutant Advisor
PT:4/4

View File

@@ -1,4 +1,5 @@
Name:Mary Jane Watson
Variant:UniversesWithin:FlavorName:Demera, Soul of a Spider
ManaCost:1 GW
Types:Legendary Creature Human Performer
PT:2/2

View File

@@ -1,4 +1,5 @@
Name:Masked Meower
Variant:UniversesWithin:FlavorName:Skittering Kitten
ManaCost:R
Types:Creature Spider Cat Hero
PT:1/1

View File

@@ -1,4 +1,5 @@
Name:Maximum Carnage
Variant:UniversesWithin:FlavorName:Lavabrink Repels the Magmaloth
ManaCost:4 R
Types:Enchantment Saga
K:Chapter:3:DBEffect,DBMana,DBDamage

View File

@@ -1,4 +1,5 @@
Name:Mechanical Mobster
Variant:UniversesWithin:FlavorName:Data Scrubber
ManaCost:3
Types:Artifact Creature Human Robot Villain
PT:2/1

View File

@@ -1,4 +1,5 @@
Name:Miles Morales
Variant:UniversesWithin:FlavorName:Cren, Undercity Dreamer
ManaCost:1 G
Types:Legendary Creature Human Citizen Hero
PT:1/2
@@ -11,6 +12,7 @@ Oracle:When Miles Morales enters, put a +1/+1 counter on each of up to two targe
ALTERNATE
Name:Ultimate Spider-Man
Variant:UniversesWithin:FlavorName:Cren of the Spider Brood
ManaCost:3 R G W
Types:Legendary Creature Spider Human Hero
PT:4/3

View File

@@ -1,4 +1,5 @@
Name:Mister Negative
Variant:UniversesWithin:FlavorName:Withar, Cocoon Keeper
ManaCost:5 W B
Types:Legendary Creature Human Villain
PT:5/5

View File

@@ -1,4 +1,5 @@
Name:Molten Man, Inferno Incarnate
Variant:UniversesWithin:FlavorName:The Infernus
ManaCost:2 R
Types:Legendary Creature Elemental Villain
PT:0/0

View File

@@ -1,4 +1,5 @@
Name:Morbius the Living Vampire
Variant:UniversesWithin:FlavorName:Tearle, Entropic Hunger
ManaCost:2 U B
Types:Legendary Creature Vampire Scientist Villain
PT:3/1

View File

@@ -1,4 +1,5 @@
Name:Morlun, Devourer of Spiders
Variant:UniversesWithin:FlavorName:Luis, Pompous Pillager
ManaCost:X B B
Types:Legendary Creature Vampire Villain
PT:2/1

View File

@@ -1,4 +1,5 @@
Name:Mysterio, Master of Illusion
Variant:UniversesWithin:FlavorName:The Watcher on the Road
ManaCost:3 U
Types:Legendary Creature Human Villain
PT:3/3

View File

@@ -1,4 +1,5 @@
Name:Mysterio's Phantasm
Variant:UniversesWithin:FlavorName:Phantasmal Vision
ManaCost:1 U
Types:Creature Illusion Villain
PT:1/3

View File

@@ -1,4 +1,5 @@
Name:News Helicopter
Variant:UniversesWithin:FlavorName:Opulent Valet
ManaCost:3
Types:Artifact Creature Construct
PT:1/1

View File

@@ -1,4 +1,5 @@
Name:Norman Osborn
Variant:UniversesWithin:FlavorName:Goben, Gene-Splice Savant
ManaCost:1 U
Types:Legendary Creature Human Scientist Villain
PT:1/1
@@ -12,6 +13,7 @@ Oracle:Norman Osborn can't be blocked.\nWhenever Norman Osborn deals combat dama
ALTERNATE
Name:Green Goblin
Variant:UniversesWithin:FlavorName:Fleem, Goben's Creation
ManaCost:1 U B R
Types:Legendary Creature Goblin Human Villain
PT:3/3

View File

@@ -1,18 +1,10 @@
Name:Oasis of Renewal
ManaCost:B G U
Types:Legendary Enchantment
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigSeekLand | TriggerDescription$ When CARDNAME enters and whenever a land card leaves your graveyard, seek a land card. This ability triggers only once each turn.
T:Mode$ ChangesZone | Origin$ Graveyard | Destination$ Any | ValidCard$ Card.Land+YouOwn | TriggerZones$ Battlefield | Execute$ TrigSeekLand | Secondary$ True | CheckSVar$ X | SVarCompare$ LT1 | TriggerDescription$ When CARDNAME enters and whenever a land card leaves your graveyard, seek a land card. This ability triggers only once each turn.
SVar:TrigSeekLand:DB$ Seek | Type$ Card.Land | SubAbility$ DBLogLand
SVar:DBLogLand:DB$ StoreSVar | SVar$ X | Type$ Number | Expression$ 1
SVar:X:Number$0
T:Mode$ Phase | Phase$ Cleanup | TriggerZones$ Battlefield | Execute$ DBLandClean | Static$ True
SVar:DBLandClean:DB$ StoreSVar | SVar$ X | Type$ Number | Expression$ 0
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigSeekNonLand | TriggerDescription$ When CARDNAME enters and whenever a nonland card leaves your graveyard, seek a nonland card. This ability triggers only once each turn.
T:Mode$ ChangesZone | Origin$ Graveyard | Destination$ Any | ValidCard$ Card.nonLand+YouOwn | TriggerZones$ Battlefield | Execute$ TrigSeekNonLand | Secondary$ True | CheckSVar$ Y | SVarCompare$ LT1 | TriggerDescription$ When CARDNAME enters and whenever a nonland card leaves your graveyard, seek a nonland card. This ability triggers only once each turn.
SVar:TrigSeekNonLand:DB$ Seek | Type$ Card.nonLand | SubAbility$ DBLogNonLand
SVar:DBLogNonLand:DB$ StoreSVar | SVar$ Y | Type$ Number | Expression$ 1
SVar:Y:Number$0
T:Mode$ Phase | Phase$ Cleanup | TriggerZones$ Battlefield | Execute$ DBNonLandClean | Static$ True
SVar:DBNonLandClean:DB$ StoreSVar | SVar$ Y | Type$ Number | Expression$ 0
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | ActivationLimit$ 1 | Execute$ TrigSeekLand | TriggerDescription$ When CARDNAME enters and whenever a land card leaves your graveyard, seek a land card. This ability triggers only once each turn.
T:Mode$ ChangesZone | Origin$ Graveyard | Destination$ Any | ValidCard$ Card.Land+YouOwn | TriggerZones$ Battlefield | ActivationLimit$ 1 | Execute$ TrigSeekLand | Secondary$ True | TriggerDescription$ When CARDNAME enters and whenever a land card leaves your graveyard, seek a land card. This ability triggers only once each turn.
SVar:TrigSeekLand:DB$ Seek | Type$ Card.Land
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | ActivationLimit$ 1 | Execute$ TrigSeekNonLand | TriggerDescription$ When CARDNAME enters and whenever a nonland card leaves your graveyard, seek a nonland card. This ability triggers only once each turn.
T:Mode$ ChangesZone | Origin$ Graveyard | Destination$ Any | ValidCard$ Card.nonLand+YouOwn | TriggerZones$ Battlefield | ActivationLimit$ 1 | Execute$ TrigSeekNonLand | Secondary$ True | TriggerDescription$ When CARDNAME enters and whenever a nonland card leaves your graveyard, seek a nonland card. This ability triggers only once each turn.
SVar:TrigSeekNonLand:DB$ Seek | Type$ Card.nonLand
Oracle:When Oasis of Renewal enters and whenever a land card leaves your graveyard, seek a land card. This ability triggers only once each turn.\nWhen Oasis of Renewal enters and whenever a nonland card leaves your graveyard, seek a nonland card. This ability triggers only once each turn.

View File

@@ -2,6 +2,6 @@ Name:Of One Mind
ManaCost:2 U
Types:Sorcery
S:Mode$ ReduceCost | ValidCard$ Card.Self | Type$ Spell | Amount$ 2 | EffectZone$ All | IsPresent$ Creature.Human+YouCtrl | CheckSVar$ Count$Valid Creature.nonHuman+YouCtrl | Description$ CARDNAME costs {2} less to cast if you control a Human creature and a non-Human creature.
DeckHints:Type$Human
A:SP$ Draw | NumCards$ 2 | SpellDescription$ Draw two cards.
DeckHints:Type$Human
Oracle:This spell costs {2} less to cast if you control a Human creature and a non-Human creature.\nDraw two cards.

View File

@@ -1,4 +1,5 @@
Name:Origin of Spider-Man
Variant:UniversesWithin:FlavorName:A Most Helpful Weaver
ManaCost:1 W
Types:Enchantment Saga
K:Chapter:3:DBToken,DBPutCounter,DBPump

View File

@@ -1,4 +1,5 @@
Name:Oscorp Industries
Variant:UniversesWithin:FlavorName:Exclusive Nightclub
ManaCost:no cost
Types:Land
R:Event$ Moved | ValidCard$ Card.Self | Destination$ Battlefield | ReplacementResult$ Updated | ReplaceWith$ ETBTapped | Description$ This land enters tapped.

View File

@@ -1,4 +1,5 @@
Name:Oscorp Research Team
Variant:UniversesWithin:FlavorName:Pinnacle Research Team
ManaCost:3 U
Types:Creature Human Scientist
PT:1/5

View File

@@ -1,4 +1,5 @@
Name:Parker Luck
Variant:UniversesWithin:FlavorName:Duskmourn's Claim
ManaCost:2 B
Types:Enchantment
T:Mode$ Phase | Phase$ End of Turn | ValidPlayer$ You | Execute$ TrigReveal | TriggerZones$ Battlefield | TriggerDescription$ At the beginning of your end step, two target players each reveal the top card of their library. They each lose life equal to the mana value of the card revealed by the other player. Then they each put the card they revealed into their hand.

View File

@@ -1,4 +1,5 @@
Name:Passenger Ferry
Variant:UniversesWithin:FlavorName:Carriage of Dreams
ManaCost:3
Types:Artifact Vehicle
PT:4/3

View File

@@ -1,4 +1,5 @@
Name:Peter Parker
Variant:UniversesWithin:FlavorName:Surris, Spidersilk Innovator
ManaCost:1 W
Types:Legendary Creature Human Scientist Hero
PT:0/1
@@ -11,6 +12,7 @@ Oracle:When Peter Parker enters, create a 2/1 green Spider creature token with r
ALTERNATE
Name:Amazing Spider-Man
Variant:UniversesWithin:FlavorName:Surris, Silk-Tech Vanguard
ManaCost:1 G W U
Types:Legendary Creature Spider Human Hero
PT:4/4

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