diff --git a/forge-ai/src/main/java/forge/ai/SpellApiToAi.java b/forge-ai/src/main/java/forge/ai/SpellApiToAi.java index 1360ce926f1..19657159607 100644 --- a/forge-ai/src/main/java/forge/ai/SpellApiToAi.java +++ b/forge-ai/src/main/java/forge/ai/SpellApiToAi.java @@ -163,6 +163,7 @@ public enum SpellApiToAi { .put(ApiType.Sacrifice, SacrificeAi.class) .put(ApiType.SacrificeAll, SacrificeAllAi.class) .put(ApiType.Scry, ScryAi.class) + .put(ApiType.Seek, AlwaysPlayAi.class) .put(ApiType.SetInMotion, AlwaysPlayAi.class) .put(ApiType.SetLife, LifeSetAi.class) .put(ApiType.SetState, SetStateAi.class) diff --git a/forge-ai/src/main/java/forge/ai/ability/CharmAi.java b/forge-ai/src/main/java/forge/ai/ability/CharmAi.java index b1e981d9d6a..79de3c099e3 100644 --- a/forge-ai/src/main/java/forge/ai/ability/CharmAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/CharmAi.java @@ -26,7 +26,7 @@ public class CharmAi extends SpellAbilityAi { @Override protected boolean checkApiLogic(Player ai, SpellAbility sa) { final Card source = sa.getHostCard(); - List choices = CharmEffect.makePossibleOptions(sa); + List choices = CharmEffect.makePossibleOptions(sa, false); final int num; final int min; diff --git a/forge-game/src/main/java/forge/game/GameActionUtil.java b/forge-game/src/main/java/forge/game/GameActionUtil.java index 22f305ce48b..c6b010d643b 100644 --- a/forge-game/src/main/java/forge/game/GameActionUtil.java +++ b/forge-game/src/main/java/forge/game/GameActionUtil.java @@ -380,6 +380,8 @@ public final class GameActionUtil { return costs; } + sa.clearPipsToReduce(); + Card source = sa.getHostCard(); final Game game = source.getGame(); boolean lkicheck = false; diff --git a/forge-game/src/main/java/forge/game/GameEntityCounterTable.java b/forge-game/src/main/java/forge/game/GameEntityCounterTable.java index c768247e03e..81a5f72acc5 100644 --- a/forge-game/src/main/java/forge/game/GameEntityCounterTable.java +++ b/forge-game/src/main/java/forge/game/GameEntityCounterTable.java @@ -166,7 +166,14 @@ public class GameEntityCounterTable extends ForwardingTable, Ga for (Map.Entry, Map> e : values.entrySet()) { boolean remember = cause != null && cause.hasParam("RememberPut"); for (Map.Entry ec : e.getValue().entrySet()) { - gm.getKey().addCounterInternal(ec.getKey(), ec.getValue(), e.getKey().orNull(), true, result, runParams); + Integer value = ec.getValue(); + if (value == null) { + continue; + } + if (cause != null && cause.hasParam("MaxFromEffect")) { + value = Math.min(value, Integer.parseInt(cause.getParam("MaxFromEffect")) - gm.getKey().getCounters(ec.getKey())); + } + gm.getKey().addCounterInternal(ec.getKey(), value, e.getKey().orNull(), true, result, runParams); if (remember && ec.getValue() >= 1) { cause.getHostCard().addRemembered(gm.getKey()); } diff --git a/forge-game/src/main/java/forge/game/ability/AbilityUtils.java b/forge-game/src/main/java/forge/game/ability/AbilityUtils.java index 91663dc0f76..caf567a5066 100644 --- a/forge-game/src/main/java/forge/game/ability/AbilityUtils.java +++ b/forge-game/src/main/java/forge/game/ability/AbilityUtils.java @@ -166,7 +166,13 @@ public class AbilityUtils { if (defined.startsWith("TopThird")) { int third = defined.contains("RoundedDown") ? (int) Math.floor(libSize / 3.0) : (int) Math.ceil(libSize / 3.0); - for (int i=0; i makePossibleOptions(final SpellAbility sa) { + public static List makePossibleOptions(final SpellAbility sa, boolean forDesc) { final Card source = sa.getHostCard(); List restriction = null; @@ -29,16 +29,19 @@ public class CharmEffect extends SpellAbilityEffect { } List choices = Lists.newArrayList(sa.getAdditionalAbilityList("Choices")); - List toRemove = Lists.newArrayList(); - for (AbilitySub ch : choices) { - // 603.3c If one of the modes would be illegal, that mode can't be chosen. - if ((ch.usesTargeting() && ch.isTrigger() && ch.getMinTargets() > 0 && - ch.getTargetRestrictions().getNumCandidates(ch, true) == 0) || - (restriction != null && restriction.contains(ch.getDescription()))) { - toRemove.add(ch); + + if (!forDesc) { + List toRemove = Lists.newArrayList(); + for (AbilitySub ch : choices) { + // 603.3c If one of the modes would be illegal, that mode can't be chosen. + if ((ch.usesTargeting() && ch.isTrigger() && ch.getMinTargets() > 0 && + ch.getTargetRestrictions().getNumCandidates(ch, true) == 0) || + (restriction != null && restriction.contains(ch.getDescription()))) { + toRemove.add(ch); + } } + choices.removeAll(toRemove); } - choices.removeAll(toRemove); int indx = 0; // set CharmOrder @@ -52,7 +55,7 @@ public class CharmEffect extends SpellAbilityEffect { public static String makeFormatedDescription(SpellAbility sa) { Card source = sa.getHostCard(); - List list = CharmEffect.makePossibleOptions(sa); + List list = CharmEffect.makePossibleOptions(sa, true); final int num; boolean additionalDesc = sa.hasParam("AdditionalDescription"); boolean optional = sa.hasParam("Optional"); @@ -166,7 +169,7 @@ public class CharmEffect extends SpellAbilityEffect { //this resets all previous choices sa.setSubAbility(null); - List choices = makePossibleOptions(sa); + List choices = makePossibleOptions(sa, false); // Entwine does use all Choices if (sa.isEntwine()) { diff --git a/forge-game/src/main/java/forge/game/ability/effects/CopyPermanentEffect.java b/forge-game/src/main/java/forge/game/ability/effects/CopyPermanentEffect.java index f034c4312c7..6c24d6080ff 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/CopyPermanentEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/CopyPermanentEffect.java @@ -258,7 +258,7 @@ public class CopyPermanentEffect extends TokenEffectBase { game.updateCombatForView(); game.fireEvent(new GameEventCombatChanged()); } - } // end resolve + } public static Card getProtoType(final SpellAbility sa, final Card original, final Player newOwner) { final Card host = sa.getHostCard(); diff --git a/forge-game/src/main/java/forge/game/ability/effects/SeekEffect.java b/forge-game/src/main/java/forge/game/ability/effects/SeekEffect.java new file mode 100644 index 00000000000..211a519fca9 --- /dev/null +++ b/forge-game/src/main/java/forge/game/ability/effects/SeekEffect.java @@ -0,0 +1,99 @@ +package forge.game.ability.effects; + +import com.google.common.collect.Lists; +import forge.game.Game; +import forge.game.ability.AbilityKey; +import forge.game.ability.AbilityUtils; +import forge.game.ability.SpellAbilityEffect; +import forge.game.card.*; +import forge.game.player.Player; +import forge.game.spellability.SpellAbility; +import forge.game.trigger.TriggerType; +import forge.game.zone.ZoneType; +import forge.util.Aggregates; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +public class SeekEffect extends SpellAbilityEffect { + + /* (non-Javadoc) + * @see forge.game.ability.SpellAbilityEffect#getStackDescription(forge.game.spellability.SpellAbility) + */ + @Override + protected String getStackDescription(SpellAbility sa) { + return sa.getDescription(); + } + + @Override + public void resolve(SpellAbility sa) { + final Card source = sa.getHostCard(); + final Game game = source.getGame(); + + List seekTypes = Lists.newArrayList(); + if (sa.hasParam("Types")) { + seekTypes.addAll(Arrays.asList(sa.getParam("Types").split(","))); + } else { + seekTypes.add(sa.getParamOrDefault("Type", "Card")); + } + + int seekNum = AbilityUtils.calculateAmount(source, sa.getParamOrDefault("Num", "1"), sa); + if (seekNum <= 0) { + return; + } + + final CardZoneTable triggerList = new CardZoneTable(); + CardCollectionView lastStateBattlefield = game.copyLastStateBattlefield(); + CardCollectionView lastStateGraveyard = game.copyLastStateGraveyard(); + + for (Player seeker : getTargetPlayers(sa)) { + if (!seeker.isInGame()) { + continue; + } + + CardCollection soughtCards = new CardCollection(); + + for (String seekType : seekTypes) { + CardCollection pool; + if (sa.hasParam("DefinedCards")) { + pool = AbilityUtils.getDefinedCards(source, sa.getParam("DefinedCards"), sa); + } else { + pool = new CardCollection(seeker.getCardsIn(ZoneType.Library)); + } + if (!seekType.equals("Card")) { + pool = CardLists.getValidCards(pool, seekType, source.getController(), source, sa); + } + if (pool.isEmpty()) { + continue; // can't find if nothing to seek + } + + for (final Card c : Aggregates.random(pool, seekNum)) { + + Map moveParams = AbilityKey.newMap(); + moveParams.put(AbilityKey.LastStateBattlefield, lastStateBattlefield); + moveParams.put(AbilityKey.LastStateGraveyard, lastStateGraveyard); + Card movedCard = game.getAction().moveToHand(c, sa, moveParams); + ZoneType resultZone = movedCard.getZone().getZoneType(); + if (!resultZone.equals(ZoneType.Library)) { // as long as it moved we add to triggerList + triggerList.put(ZoneType.Library, movedCard.getZone().getZoneType(), movedCard); + } + if (resultZone.equals(ZoneType.Hand)) { // if it went to hand as planned, consider it "sought" + soughtCards.add(movedCard); + } + + } + } + if (!soughtCards.isEmpty()) { + if (sa.hasParam("RememberFound")) { + source.addRemembered(soughtCards); + } + if (sa.hasParam("ImprintFound")) { + source.addImprintedCards(soughtCards); + } + game.getTriggerHandler().runTrigger(TriggerType.SeekAll, AbilityKey.mapFromPlayer(seeker), false); + } + } + triggerList.triggerChangesZoneAll(game, sa); + } +} diff --git a/forge-game/src/main/java/forge/game/ability/effects/UntapEffect.java b/forge-game/src/main/java/forge/game/ability/effects/UntapEffect.java index f7752512864..161d9d49c4d 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/UntapEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/UntapEffect.java @@ -72,7 +72,7 @@ public class UntapEffect extends SpellAbilityEffect { * whether the untapping is mandatory. */ private static void untapChoose(final SpellAbility sa, final boolean mandatory) { - final int num = Integer.parseInt(sa.getParam("Amount")); + final int num = AbilityUtils.calculateAmount(sa.getHostCard(), sa.getParam("Amount"), sa); final String valid = sa.getParam("UntapType"); for (final Player p : AbilityUtils.getDefinedPlayers(sa.getHostCard(), sa.getParam("Defined"), sa)) { diff --git a/forge-game/src/main/java/forge/game/card/Card.java b/forge-game/src/main/java/forge/game/card/Card.java index 0fc3b9723b9..44bf5eaf15e 100644 --- a/forge-game/src/main/java/forge/game/card/Card.java +++ b/forge-game/src/main/java/forge/game/card/Card.java @@ -526,7 +526,7 @@ public class Card extends GameEntity implements Comparable, IHasSVars { if (state == CardStateName.FaceDown) { view.updateHiddenId(game.nextHiddenCardId()); } - game.fireEvent(new GameEventCardStatsChanged(this)); //ensure stats updated for new characteristics + game.fireEvent(new GameEventCardStatsChanged(this, true)); //ensure stats updated for new characteristics } } return true; diff --git a/forge-game/src/main/java/forge/game/cost/CostDiscard.java b/forge-game/src/main/java/forge/game/cost/CostDiscard.java index 192cbd7bd5c..803b55f2cce 100644 --- a/forge-game/src/main/java/forge/game/cost/CostDiscard.java +++ b/forge-game/src/main/java/forge/game/cost/CostDiscard.java @@ -22,7 +22,6 @@ import java.util.Set; import com.google.common.collect.Sets; -import forge.card.CardType; import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.card.CardCollection; @@ -106,11 +105,7 @@ public class CostDiscard extends CostPartWithList { desc.append("card"); } else { - if (this.getTypeDescription() == null) { - desc.append(CardType.CoreType.isValidEnum(this.getType()) ? this.getType().toLowerCase() : this.getType()); - } else { - desc.append(this.getTypeDescription()); - } + desc.append(this.getDescriptiveType()); desc.append(" card"); } diff --git a/forge-game/src/main/java/forge/game/cost/CostExile.java b/forge-game/src/main/java/forge/game/cost/CostExile.java index 79a1cfbdeae..cb1347ac665 100644 --- a/forge-game/src/main/java/forge/game/cost/CostExile.java +++ b/forge-game/src/main/java/forge/game/cost/CostExile.java @@ -17,7 +17,6 @@ */ package forge.game.cost; -import forge.card.CardType; import forge.game.Game; import forge.game.ability.SpellAbilityEffect; import forge.game.card.Card; @@ -85,10 +84,7 @@ public class CostExile extends CostPartWithList { @Override public final String toString() { final Integer i = this.convertAmount(); - String desc = this.getTypeDescription() == null ? this.getType() : this.getTypeDescription(); - if (CardType.CoreType.isValidEnum(desc)) { - desc = desc.toLowerCase(); - } + String desc = this.getDescriptiveType(); String origin = this.from.name().toLowerCase(); if (this.payCostFromSource()) { diff --git a/forge-game/src/main/java/forge/game/event/GameEventCardStatsChanged.java b/forge-game/src/main/java/forge/game/event/GameEventCardStatsChanged.java index 140e3a2ef00..ad05e05753c 100644 --- a/forge-game/src/main/java/forge/game/event/GameEventCardStatsChanged.java +++ b/forge-game/src/main/java/forge/game/event/GameEventCardStatsChanged.java @@ -15,8 +15,14 @@ import forge.game.card.Card; public class GameEventCardStatsChanged extends GameEvent { public final Collection cards; + public boolean transform = false; public GameEventCardStatsChanged(Card affected) { + this(affected, false); + } + + public GameEventCardStatsChanged(Card affected, boolean isTransform) { cards = Arrays.asList(affected); + transform = isTransform; } public GameEventCardStatsChanged(Collection affected) { diff --git a/forge-game/src/main/java/forge/game/spellability/SpellAbility.java b/forge-game/src/main/java/forge/game/spellability/SpellAbility.java index c2b992902bf..be2f2bb8796 100644 --- a/forge-game/src/main/java/forge/game/spellability/SpellAbility.java +++ b/forge-game/src/main/java/forge/game/spellability/SpellAbility.java @@ -404,10 +404,7 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit } public boolean canPlayWithOptionalCost(OptionalCostValue opt) { - SpellAbility saOpt = GameActionUtil.addOptionalCosts(this, Lists.newArrayList(opt)); - boolean result = saOpt.canPlay(); - saOpt.clearPipsToReduce(); - return result; + return GameActionUtil.addOptionalCosts(this, Lists.newArrayList(opt)).canPlay(); } public boolean isPossible() { diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerSeekAll.java b/forge-game/src/main/java/forge/game/trigger/TriggerSeekAll.java new file mode 100644 index 00000000000..c1471c5f549 --- /dev/null +++ b/forge-game/src/main/java/forge/game/trigger/TriggerSeekAll.java @@ -0,0 +1,36 @@ +package forge.game.trigger; + +import forge.game.ability.AbilityKey; +import forge.game.card.Card; +import forge.game.spellability.SpellAbility; +import forge.util.Localizer; + +import java.util.Map; + +public class TriggerSeekAll extends Trigger { + + public TriggerSeekAll(Map params, Card host, boolean intrinsic) { + super(params, host, intrinsic); + } + + @Override + public boolean performTest(Map runParams) { + if (!matchesValidParam("ValidPlayer", runParams.get(AbilityKey.Player))) { + return false; + } + return true; + } + + @Override + public void setTriggeringObjects(SpellAbility sa, Map runParams) { + sa.setTriggeringObjectsFrom(runParams, AbilityKey.Player); + } + + @Override + public String getImportantStackObjects(SpellAbility sa) { + StringBuilder sb = new StringBuilder(); + sb.append(Localizer.getInstance().getMessage("lblPlayer")).append(": "); + sb.append(sa.getTriggeringObject(AbilityKey.Player)); + return sb.toString(); + } +} diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerType.java b/forge-game/src/main/java/forge/game/trigger/TriggerType.java index 50dc144c509..7faf2776c9e 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerType.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerType.java @@ -104,6 +104,7 @@ public enum TriggerType { Sacrificed(TriggerSacrificed.class), Scry(TriggerScry.class), SearchedLibrary(TriggerSearchedLibrary.class), + SeekAll(TriggerSeekAll.class), SetInMotion(TriggerSetInMotion.class), Shuffled(TriggerShuffled.class), Specializes(TriggerSpecializes.class), diff --git a/forge-gui-mobile/src/forge/Forge.java b/forge-gui-mobile/src/forge/Forge.java index a00fb6247bc..79cda06a27e 100644 --- a/forge-gui-mobile/src/forge/Forge.java +++ b/forge-gui-mobile/src/forge/Forge.java @@ -17,6 +17,7 @@ import com.badlogic.gdx.graphics.g2d.TextureRegion; import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.Clipboard; import forge.adventure.scene.*; +import forge.adventure.stage.GameHUD; import forge.adventure.util.Config; import forge.adventure.world.WorldSave; import forge.animation.ForgeAnimation; @@ -340,6 +341,7 @@ public class Forge implements ApplicationListener { try { Config.instance().loadResources(); SpellSmithScene.instance().loadEditions(); + GameHUD.getInstance().stopAudio(); if (startScene) { MusicPlaylist.invalidateMusicPlaylist(); SoundSystem.instance.setBackgroundMusic(MusicPlaylist.MENUS); diff --git a/forge-gui-mobile/src/forge/adventure/player/AdventurePlayer.java b/forge-gui-mobile/src/forge/adventure/player/AdventurePlayer.java index 98e47c52a3f..0ad4640b8c1 100644 --- a/forge-gui-mobile/src/forge/adventure/player/AdventurePlayer.java +++ b/forge-gui-mobile/src/forge/adventure/player/AdventurePlayer.java @@ -18,6 +18,8 @@ import forge.deck.DeckProxy; import forge.deck.DeckSection; import forge.item.InventoryItem; import forge.item.PaperCard; +import forge.sound.SoundEffectType; +import forge.sound.SoundSystem; import forge.util.ItemPool; import java.io.Serializable; @@ -516,6 +518,8 @@ public class AdventurePlayer implements Serializable, SaveFileContent { public void takeGold(int price) { gold -= price; onGoldChangeList.emit(); + //play sfx + SoundSystem.instance.play(SoundEffectType.CoinsDrop, false); } public void addShards(int number) { takeShards(-number); @@ -523,6 +527,8 @@ public class AdventurePlayer implements Serializable, SaveFileContent { public void takeShards(int number) { shards -= number; onShardsChangeList.emit(); + //play sfx + SoundSystem.instance.play(SoundEffectType.TakeShard, false); } public void setShards(int number) { diff --git a/forge-gui-mobile/src/forge/adventure/scene/DuelScene.java b/forge-gui-mobile/src/forge/adventure/scene/DuelScene.java index 66b3b82d820..0d916192653 100644 --- a/forge-gui-mobile/src/forge/adventure/scene/DuelScene.java +++ b/forge-gui-mobile/src/forge/adventure/scene/DuelScene.java @@ -13,6 +13,7 @@ import forge.adventure.data.EffectData; import forge.adventure.data.EnemyData; import forge.adventure.data.ItemData; import forge.adventure.player.AdventurePlayer; +import forge.adventure.stage.GameHUD; import forge.adventure.stage.IAfterMatch; import forge.adventure.util.Config; import forge.adventure.util.Current; @@ -67,6 +68,8 @@ public class DuelScene extends ForgeScene { Deck playerDeck; boolean chaosBattle = false; boolean callbackExit = false; + boolean arenaBattleChallenge = false; + boolean isArena = false; private LoadingOverlay matchOverlay; List playerExtras = new ArrayList<>(); List AIExtras = new ArrayList<>(); @@ -138,7 +141,13 @@ public class DuelScene extends ForgeScene { void afterGameEnd(String enemyName, boolean winner, boolean showOverlay, boolean alternate) { Runnable runnable = () -> Gdx.app.postRunnable(()-> { - SoundSystem.instance.setBackgroundMusic(MusicPlaylist.MENUS); //start background music + if (GameScene.instance().isNotInWorldMap()) { + SoundSystem.instance.pause(); + GameHUD.getInstance().playAudio(); + } else { + SoundSystem.instance.setBackgroundMusic(MusicPlaylist.MENUS); + SoundSystem.instance.resume(); + } dungeonEffect = null; callbackExit = false; Forge.clearTransitionScreen(); @@ -192,6 +201,7 @@ public class DuelScene extends ForgeScene { @Override public void enter() { + GameHUD.getInstance().unloadAudio(); Set appliedVariants = new HashSet<>(); appliedVariants.add(GameType.Constructed); AdventurePlayer advPlayer = Current.player(); @@ -267,6 +277,7 @@ public class DuelScene extends ForgeScene { addEffects(humanPlayer, playerEffects); currentEnemy = enemy.getData(); + boolean bossBattle = currentEnemy.boss; for (int i = 0; i < 8 && currentEnemy != null; i++) { Deck deck = null; @@ -278,6 +289,8 @@ public class DuelScene extends ForgeScene { } this.AIExtras = aiCards; deck = deckProxy.getDeck(); + } else if (this.arenaBattleChallenge) { + deck = Aggregates.random(DeckProxy.getAllGeneticAIDecks()).getDeck(); } else { deck = currentEnemy.copyPlayerDeck ? this.playerDeck : currentEnemy.generateDeck(Current.player().isFantasyMode(), Current.player().isUsingCustomDeck() || Current.player().getDifficulty().name.equalsIgnoreCase("Hard")); } @@ -332,7 +345,7 @@ public class DuelScene extends ForgeScene { rules.setWarnAboutAICards(false); hostedMatch.setEndGameHook(() -> DuelScene.this.GameEnd()); - hostedMatch.startMatch(rules, appliedVariants, players, guiMap); + hostedMatch.startMatch(rules, appliedVariants, players, guiMap, bossBattle ? MusicPlaylist.BOSS : MusicPlaylist.MATCH); MatchController.instance.setGameView(hostedMatch.getGameView()); boolean showMessages = enemy.getData().copyPlayerDeck && Current.player().isUsingCustomDeck(); if (chaosBattle || showMessages) { @@ -376,8 +389,15 @@ public class DuelScene extends ForgeScene { } public void initDuels(PlayerSprite playerSprite, EnemySprite enemySprite) { + initDuels(playerSprite, enemySprite, false); + } + public void initDuels(PlayerSprite playerSprite, EnemySprite enemySprite, boolean isArena) { this.player = playerSprite; this.enemy = enemySprite; + this.isArena = isArena; + this.arenaBattleChallenge = isArena + && (Current.player().getDifficulty().name.equalsIgnoreCase("Hard") + || Current.player().getDifficulty().name.equalsIgnoreCase("Insane")); this.playerDeck = (Deck) Current.player().getSelectedDeck().copyTo("PlayerDeckCopy"); this.chaosBattle = this.enemy.getData().copyPlayerDeck && Current.player().isFantasyMode(); this.AIExtras.clear(); diff --git a/forge-gui-mobile/src/forge/adventure/scene/GameScene.java b/forge-gui-mobile/src/forge/adventure/scene/GameScene.java index 87eae661704..d9575a5c8f3 100644 --- a/forge-gui-mobile/src/forge/adventure/scene/GameScene.java +++ b/forge-gui-mobile/src/forge/adventure/scene/GameScene.java @@ -64,14 +64,13 @@ public class GameScene extends HudScene { } else { World world = Current.world(); //this gets the name of the layer... this shoud be based on boundaries... - int currentBiome = World.highestBiome(world.getBiome((int) stage.getPlayerSprite().getX() / world.getTileSize(), (int) stage.getPlayerSprite().getY() / world.getTileSize())); + int currentBiome = World.highestBiome(world.getBiomeMapXY((int) stage.getPlayerSprite().getX() / world.getTileSize(), (int) stage.getPlayerSprite().getY() / world.getTileSize())); List biomeData = world.getData().GetBiomes(); - if (biomeData.size() <= currentBiome) //on roads.... + if (biomeData.size() <= currentBiome) //shouldn't be the case but default to waste if (skipRoads) { location = forHeader ? "Waste Map" : "waste"; } else { - //current workaround to get the POI town name - location = WorldStage.getInstance().getBoundary(); + location = ""; } else { BiomeData data = biomeData.get(currentBiome); diff --git a/forge-gui-mobile/src/forge/adventure/scene/NewGameScene.java b/forge-gui-mobile/src/forge/adventure/scene/NewGameScene.java index ae0238cdf80..a386d174feb 100644 --- a/forge-gui-mobile/src/forge/adventure/scene/NewGameScene.java +++ b/forge-gui-mobile/src/forge/adventure/scene/NewGameScene.java @@ -24,6 +24,7 @@ import forge.localinstance.properties.ForgePreferences; import forge.model.FModel; import forge.player.GamePlayerUtil; import forge.screens.TransitionScreen; +import forge.sound.SoundSystem; import forge.util.NameGenerator; import java.util.Random; @@ -190,7 +191,7 @@ public class NewGameScene extends UIScene { } Runnable runnable = () -> { started = false; - FModel.getPreferences().setPref(ForgePreferences.FPref.UI_ENABLE_MUSIC, false); + //FModel.getPreferences().setPref(ForgePreferences.FPref.UI_ENABLE_MUSIC, false); WorldSave.generateNewWorld(selectedName.getText(), gender.getCurrentIndex() == 0, race.getCurrentIndex(), @@ -200,6 +201,7 @@ public class NewGameScene extends UIScene { modes.get(mode.getCurrentIndex()), colorId.getCurrentIndex(), editionIds[starterEdition.getCurrentIndex()], 0);//maybe replace with enum GamePlayerUtil.getGuiPlayer().setName(selectedName.getText()); + SoundSystem.instance.changeBackgroundTrack(); Forge.switchScene(GameScene.instance()); }; Forge.setTransitionScreen(new TransitionScreen(runnable, null, false, true, "Generating World...")); diff --git a/forge-gui-mobile/src/forge/adventure/scene/RewardScene.java b/forge-gui-mobile/src/forge/adventure/scene/RewardScene.java index b7b5557c0d6..ede0fa74539 100644 --- a/forge-gui-mobile/src/forge/adventure/scene/RewardScene.java +++ b/forge-gui-mobile/src/forge/adventure/scene/RewardScene.java @@ -146,13 +146,15 @@ public class RewardScene extends UIScene { showLootOrDone(); return true; } - switch (type) { - case Shop: - doneButton.setText(Forge.getLocalizer().getMessage("lblLeave")); - break; - case Loot: - doneButton.setText(Forge.getLocalizer().getMessage("lblDone")); - break; + if (type != null) { + switch (type) { + case Shop: + doneButton.setText(Forge.getLocalizer().getMessage("lblLeave")); + break; + case Loot: + doneButton.setText(Forge.getLocalizer().getMessage("lblDone")); + break; + } } shown = false; clearGenerated(); diff --git a/forge-gui-mobile/src/forge/adventure/scene/SaveLoadScene.java b/forge-gui-mobile/src/forge/adventure/scene/SaveLoadScene.java index cbb7ad68221..751058629f9 100644 --- a/forge-gui-mobile/src/forge/adventure/scene/SaveLoadScene.java +++ b/forge-gui-mobile/src/forge/adventure/scene/SaveLoadScene.java @@ -21,6 +21,7 @@ import forge.adventure.util.Current; import forge.adventure.world.WorldSave; import forge.adventure.world.WorldSaveHeader; import forge.screens.TransitionScreen; +import forge.sound.SoundSystem; import forge.util.TextUtil; import java.io.File; @@ -217,6 +218,7 @@ public class SaveLoadScene extends UIScene { try { Forge.setTransitionScreen(new TransitionScreen(() -> { if (WorldSave.load(currentSlot)) { + SoundSystem.instance.changeBackgroundTrack(); Forge.switchScene(GameScene.instance()); } else { Forge.clearTransitionScreen(); @@ -236,6 +238,7 @@ public class SaveLoadScene extends UIScene { Current.player().updateDifficulty(Config.instance().getConfigData().difficulties[difficulty.getSelectedIndex()]); Current.player().setWorldPosY((int) (WorldSave.getCurrentSave().getWorld().getData().playerStartPosY * WorldSave.getCurrentSave().getWorld().getData().height * WorldSave.getCurrentSave().getWorld().getTileSize())); Current.player().setWorldPosX((int) (WorldSave.getCurrentSave().getWorld().getData().playerStartPosX * WorldSave.getCurrentSave().getWorld().getData().width * WorldSave.getCurrentSave().getWorld().getTileSize())); + SoundSystem.instance.changeBackgroundTrack(); Forge.switchScene(GameScene.instance()); } else { Forge.clearTransitionScreen(); diff --git a/forge-gui-mobile/src/forge/adventure/scene/StartScene.java b/forge-gui-mobile/src/forge/adventure/scene/StartScene.java index 543b812c223..cbbb9e845f7 100644 --- a/forge-gui-mobile/src/forge/adventure/scene/StartScene.java +++ b/forge-gui-mobile/src/forge/adventure/scene/StartScene.java @@ -10,6 +10,7 @@ import forge.adventure.util.Config; import forge.adventure.util.Controls; import forge.adventure.world.WorldSave; import forge.screens.TransitionScreen; +import forge.sound.SoundSystem; /** * First scene after the splash screen @@ -20,7 +21,6 @@ public class StartScene extends UIScene { TextraButton saveButton, resumeButton, continueButton; - public StartScene() { super(Forge.isLandscapeMode() ? "ui/start_menu.json" : "ui/start_menu_portrait.json"); ui.onButtonPress("Start", StartScene.this::NewGame); @@ -31,7 +31,7 @@ public class StartScene extends UIScene { ui.onButtonPress("Continue", StartScene.this::Continue); ui.onButtonPress("Settings", StartScene.this::settings); ui.onButtonPress("Exit", StartScene.this::Exit); - ui.onButtonPress("Switch", Forge::switchToClassic); + ui.onButtonPress("Switch", StartScene.this::switchToClassic); saveButton = ui.findActor("Save"); @@ -43,8 +43,8 @@ public class StartScene extends UIScene { } public static StartScene instance() { - if(object==null) - object=new StartScene(); + if (object == null) + object = new StartScene(); return object; } @@ -81,6 +81,7 @@ public class StartScene extends UIScene { try { Forge.setTransitionScreen(new TransitionScreen(() -> { if (WorldSave.load(WorldSave.filenameToSlot(lastActiveSave))) { + SoundSystem.instance.changeBackgroundTrack(); Forge.switchScene(GameScene.instance()); } else { Forge.clearTransitionScreen(); @@ -100,17 +101,22 @@ public class StartScene extends UIScene { } public boolean Exit() { - Dialog dialog = prepareDialog(Forge.getLocalizer().getMessage("lblExitForge"), ButtonOk|ButtonAbort,()->Forge.exit(true)); - dialog.text( Controls.newLabel(Forge.getLocalizer().getMessage("lblAreYouSureYouWishExitForge"))); + Dialog dialog = prepareDialog(Forge.getLocalizer().getMessage("lblExitForge"), ButtonOk | ButtonAbort, () -> Forge.exit(true)); + dialog.text(Controls.newLabel(Forge.getLocalizer().getMessage("lblAreYouSureYouWishExitForge"))); showDialog(dialog); return true; } + public void switchToClassic() { + GameHUD.getInstance().stopAudio(); + Forge.switchToClassic(); + } + @Override public void enter() { boolean hasSaveButton = WorldSave.getCurrentSave().getWorld().getData() != null; if (hasSaveButton) { - TileMapScene scene = TileMapScene.instance(); + TileMapScene scene = TileMapScene.instance(); hasSaveButton = !scene.currentMap().isInMap() || scene.isAutoHealLocation(); } saveButton.setVisible(hasSaveButton); @@ -130,10 +136,9 @@ public class StartScene extends UIScene { } - if(Forge.createNewAdventureMap) - { + if (Forge.createNewAdventureMap) { this.NewGame(); - GameStage.maximumScrollDistance=4f; + GameStage.maximumScrollDistance = 4f; } super.enter(); diff --git a/forge-gui-mobile/src/forge/adventure/scene/UIScene.java b/forge-gui-mobile/src/forge/adventure/scene/UIScene.java index 821c034968c..0e8fe6f184b 100644 --- a/forge-gui-mobile/src/forge/adventure/scene/UIScene.java +++ b/forge-gui-mobile/src/forge/adventure/scene/UIScene.java @@ -19,6 +19,8 @@ import com.github.tommyettinger.textra.TextraLabel; import forge.Forge; import forge.adventure.stage.GameHUD; import forge.adventure.util.*; +import forge.sound.SoundEffectType; +import forge.sound.SoundSystem; /** * Base class for an GUI scene where the elements are loaded from a json file @@ -27,86 +29,83 @@ public class UIScene extends Scene { protected UIActor ui; - public static class Selectable - { + public static class Selectable { public T actor; - public float getY() - { - Actor act=actor; - float y=0; - while (act!=null) - { - y+=act.getY(); - act=act.getParent(); + + public float getY() { + Actor act = actor; + float y = 0; + while (act != null) { + y += act.getY(); + act = act.getParent(); } return y; } - public float getX() - { - Actor act=actor; - float x=0; - while (act!=null) - { - x+=act.getX(); - act=act.getParent(); + + public float getX() { + Actor act = actor; + float x = 0; + while (act != null) { + x += act.getX(); + act = act.getParent(); } return x; } public Selectable(T newActor) { - actor=newActor; + actor = newActor; } - public void onSelect(UIScene scene) - { + public void onSelect(UIScene scene) { } - public void onDeSelect() - { + + public void onDeSelect() { //actor.fire(UIScene.eventExit()); } - public void onPressDown(UIScene scene) - { - if(actor instanceof TextField) - { - scene.requestTextInput(((TextField) actor).getText(),text-> ((TextField) actor).setText(text)); + + public void onPressDown(UIScene scene) { + if (actor instanceof TextField) { + scene.requestTextInput(((TextField) actor).getText(), text -> ((TextField) actor).setText(text)); } actor.fire(UIScene.eventTouchDown()); } - public void onPressUp() - { + + public void onPressUp() { actor.fire(UIScene.eventTouchUp()); } public float yDiff(Selectable finalOne) { - return Math.abs(finalOne.getY()-getY()); + return Math.abs(finalOne.getY() - getY()); } + public float xDiff(Selectable finalOne) { - return Math.abs(finalOne.getX()-getX()); + return Math.abs(finalOne.getX() - getX()); } } - static final public int ButtonYes=0x1; - static final public int ButtonNo=0x2; - static final public int ButtonOk=0x4; - static final public int ButtonAbort=0x8; + + static final public int ButtonYes = 0x1; + static final public int ButtonNo = 0x2; + static final public int ButtonOk = 0x4; + static final public int ButtonAbort = 0x8; + public Dialog prepareDialog(String header, int buttons, Runnable onOkOrYes) { - Dialog dialog =new Dialog(header, Controls.getSkin()) - { - protected void result(Object object) - { - if(onOkOrYes!=null&&object!=null&&object.equals(true)) + Dialog dialog = new Dialog(header, Controls.getSkin()) { + protected void result(Object object) { + SoundSystem.instance.play(SoundEffectType.ButtonPress, false); + if (onOkOrYes != null && object != null && object.equals(true)) onOkOrYes.run(); - this.hide(); + this.hide(); removeDialog(); } }; - if((buttons&ButtonYes)!=0) + if ((buttons & ButtonYes) != 0) dialog.button(Forge.getLocalizer().getMessage("lblYes"), true); - if((buttons&ButtonNo)!=0) + if ((buttons & ButtonNo) != 0) dialog.button(Forge.getLocalizer().getMessage("lblNo"), false); - if((buttons&ButtonOk)!=0) + if ((buttons & ButtonOk) != 0) dialog.button(Forge.getLocalizer().getMessage("lblOk"), true); - if((buttons&ButtonAbort)!=0) + if ((buttons & ButtonAbort) != 0) dialog.button(Forge.getLocalizer().getMessage("lblAbort"), false); dialog.setMovable(false); @@ -114,16 +113,16 @@ public class UIScene extends Scene { dialog.setResizable(false); return dialog; } - public void showDialog(Dialog dialog) - { + + public void showDialog(Dialog dialog) { stage.addActor(dialog); possibleSelectionStack.add(new Array<>()); addToSelectable(dialog.getContentTable()); addToSelectable(dialog.getButtonTable()); - dialog.getColor().a=0; + dialog.getColor().a = 0; stage.setKeyboardFocus(dialog); stage.setScrollFocus(dialog); - for(Dialog otherDialogs:dialogs) + for (Dialog otherDialogs : dialogs) otherDialogs.hide(); dialogs.add(dialog); selectFirst(); @@ -136,7 +135,7 @@ public class UIScene extends Scene { { @Override protected void result(@Null Object object) { - removeDialog(); + removeDialog(); } }; keyboardDialog.setText(text); @@ -145,41 +144,42 @@ public class UIScene extends Scene { //possibleSelection=keyboardDialog.keys(); } - public Array< Array> possibleSelectionStack=new Array<>(); - public Array< Dialog> dialogs=new Array<>(); - public Array getPossibleSelection() - { - if(possibleSelectionStack.isEmpty()) + public Array> possibleSelectionStack = new Array<>(); + public Array dialogs = new Array<>(); + + public Array getPossibleSelection() { + if (possibleSelectionStack.isEmpty()) possibleSelectionStack.add(ui.selectActors); - return possibleSelectionStack.get(possibleSelectionStack.size-1); - } + return possibleSelectionStack.get(possibleSelectionStack.size - 1); + } + protected Stage stage; String uiFile; - public static InputEvent eventTouchUp() - { + + public static InputEvent eventTouchUp() { InputEvent event = new InputEvent(); event.setPointer(-1); event.setType(InputEvent.Type.touchUp); return event; } - public static InputEvent eventTouchDown() - { + + public static InputEvent eventTouchDown() { InputEvent event = new InputEvent(); event.setPointer(-1); event.setType(InputEvent.Type.touchDown); return event; } - public static InputEvent eventExit() - { + + public static InputEvent eventExit() { InputEvent event = new InputEvent(); event.setPointer(-1); event.setType(InputEvent.Type.exit); return event; } - public static InputEvent eventEnter() - { + + public static InputEvent eventEnter() { InputEvent event = new InputEvent(); event.setPointer(-1); event.setType(InputEvent.Type.enter); @@ -188,26 +188,30 @@ public class UIScene extends Scene { @Override public boolean buttonUp(Controller controller, int keycode) { - return stage.keyUp(KeyBinding.controllerButtonToKey(controller,keycode)); + return stage.keyUp(KeyBinding.controllerButtonToKey(controller, keycode)); } + @Override public boolean buttonDown(Controller controller, int keycode) { - return stage.keyDown(KeyBinding.controllerButtonToKey(controller,keycode)); + return stage.keyDown(KeyBinding.controllerButtonToKey(controller, keycode)); } + protected void addToSelectable(Table table) { - for(Cell cell:table.getCells()) - { - if(cell.getActor()!=null&&cell.getActor().getClass()!=Actor.class&&!(cell.getActor()instanceof Label)&&!(cell.getActor()instanceof TextraLabel)) + for (Cell cell : table.getCells()) { + if (cell.getActor() != null && cell.getActor().getClass() != Actor.class && !(cell.getActor() instanceof Label) && !(cell.getActor() instanceof TextraLabel)) getPossibleSelection().add(new Selectable(cell.getActor())); } } + protected void addToSelectable(Button button)//prevent to addToSelectable(Table) fallback - { + { getPossibleSelection().add(new Selectable(button)); } + protected void addToSelectable(Actor button) { getPossibleSelection().add(new Selectable(button)); } + protected void addToSelectable(Selectable selectable) { getPossibleSelection().add(selectable); } @@ -222,14 +226,16 @@ public class UIScene extends Scene { stage = new Stage(new ScalingViewport(Scaling.stretch, getIntendedWidth(), getIntendedHeight())) { @Override public boolean keyUp(int keycode) { - keyReleased(keycode); + keyReleased(keycode); return super.keyUp(keycode); } + @Override public boolean keyDown(int keyCode) { - keyPressed(keyCode); + keyPressed(keyCode); return super.keyDown(keyCode); } + @Override public boolean mouseMoved(int screenX, int screenY) { pointerMoved(screenX, screenY); @@ -237,9 +243,8 @@ public class UIScene extends Scene { } }; ui = new UIActor(Config.instance().getFile(uiFile)); - for(Actor actor:ui.getChildren()) - { - if(actor instanceof ScrollPane) + for (Actor actor : ui.getChildren()) { + if (actor instanceof ScrollPane) stage.setScrollFocus(actor); } possibleSelectionStack.add(ui.selectActors); @@ -249,21 +254,17 @@ public class UIScene extends Scene { private void removeDialog() { - if(!dialogs.isEmpty()) - { - dialogs.get(dialogs.size-1).remove(); - dialogs.removeIndex(dialogs.size-1); + if (!dialogs.isEmpty()) { + dialogs.get(dialogs.size - 1).remove(); + dialogs.removeIndex(dialogs.size - 1); - if(!dialogs.isEmpty()) - dialogs.get(dialogs.size-1).show(stage); + if (!dialogs.isEmpty()) + dialogs.get(dialogs.size - 1).show(stage); } - if(possibleSelectionStack.isEmpty()) - { + if (possibleSelectionStack.isEmpty()) { getPossibleSelection(); - } - else - { - possibleSelectionStack.removeIndex(possibleSelectionStack.size-1); + } else { + possibleSelectionStack.removeIndex(possibleSelectionStack.size - 1); } } @@ -295,92 +296,80 @@ public class UIScene extends Scene { Forge.switchToLast(); return true; } - public Selectable getSelected() - { - for(Selectable selectable: getPossibleSelection()) - { - if(stage.getKeyboardFocus()==selectable.actor) + + public Selectable getSelected() { + for (Selectable selectable : getPossibleSelection()) { + if (stage.getKeyboardFocus() == selectable.actor) return selectable; } return null; } - public boolean keyReleased(int keycode) - { + + public boolean keyReleased(int keycode) { ui.pressUp(keycode); - if(!dialogShowing()) - { - Button pressedButton=ui.buttonPressed(keycode); - if(pressedButton!=null) - { - if(pressedButton.isVisible()) + if (!dialogShowing()) { + Button pressedButton = ui.buttonPressed(keycode); + if (pressedButton != null) { + if (pressedButton.isVisible()) pressedButton.fire(eventTouchUp()); } } - if(KeyBinding.Use.isPressed(keycode)){ - if(getSelected()!=null) + if (KeyBinding.Use.isPressed(keycode)) { + if (getSelected() != null) getSelected().onPressUp();//order is important, this might remove a dialog } return true; } + public boolean keyPressed(int keycode) { - Selectable selection=getSelected(); + Selectable selection = getSelected(); ui.pressDown(keycode); - if(stage.getKeyboardFocus() instanceof SelectBox) - { - SelectBox box=(SelectBox) stage.getKeyboardFocus(); - if(box.getScrollPane().hasParent()) - { - if(KeyBinding.Use.isPressed(keycode)) - { + if (stage.getKeyboardFocus() instanceof SelectBox) { + SelectBox box = (SelectBox) stage.getKeyboardFocus(); + if (box.getScrollPane().hasParent()) { + if (KeyBinding.Use.isPressed(keycode)) { box.getSelection().choose(box.getList().getSelected()); box.getScrollPane().hide(); } return false; } } - if(KeyBinding.Use.isPressed(keycode)){ - if(selection!=null) + if (KeyBinding.Use.isPressed(keycode)) { + if (selection != null) selection.onPressDown(this); } - if(KeyBinding.ScrollUp.isPressed(keycode)) - { - Actor focus=stage.getScrollFocus(); - if(focus!=null&&focus instanceof ScrollPane) - { - ScrollPane scroll=((ScrollPane)focus); - scroll.setScrollY(scroll.getScrollY()-20); + if (KeyBinding.ScrollUp.isPressed(keycode)) { + Actor focus = stage.getScrollFocus(); + if (focus != null && focus instanceof ScrollPane) { + ScrollPane scroll = ((ScrollPane) focus); + scroll.setScrollY(scroll.getScrollY() - 20); } } - if(KeyBinding.ScrollDown.isPressed(keycode)) - { - Actor focus=stage.getScrollFocus(); - if(focus!=null&&focus instanceof ScrollPane) - { - ScrollPane scroll=((ScrollPane)focus); - scroll.setScrollY(scroll.getScrollY()+20); + if (KeyBinding.ScrollDown.isPressed(keycode)) { + Actor focus = stage.getScrollFocus(); + if (focus != null && focus instanceof ScrollPane) { + ScrollPane scroll = ((ScrollPane) focus); + scroll.setScrollY(scroll.getScrollY() + 20); } } - if(KeyBinding.Down.isPressed(keycode)) + if (KeyBinding.Down.isPressed(keycode)) selectNextDown(); - if(KeyBinding.Up.isPressed(keycode)) + if (KeyBinding.Up.isPressed(keycode)) selectNextUp(); - if(!(stage.getKeyboardFocus() instanceof Selector)&&!(stage.getKeyboardFocus() instanceof TextField)&&!(stage.getKeyboardFocus() instanceof Slider)) - { - if(KeyBinding.Right.isPressed(keycode)) + if (!(stage.getKeyboardFocus() instanceof Selector) && !(stage.getKeyboardFocus() instanceof TextField) && !(stage.getKeyboardFocus() instanceof Slider)) { + if (KeyBinding.Right.isPressed(keycode)) selectNextRight(); - if(KeyBinding.Left.isPressed(keycode)) + if (KeyBinding.Left.isPressed(keycode)) selectNextLeft(); } - if(!dialogShowing()) - { - Button pressedButton=ui.buttonPressed(keycode); - if(pressedButton!=null) - { - if(pressedButton.isVisible()) + if (!dialogShowing()) { + Button pressedButton = ui.buttonPressed(keycode); + if (pressedButton != null) { + if (pressedButton.isVisible()) pressedButton.fire(eventTouchDown()); } } @@ -396,11 +385,13 @@ public class UIScene extends Scene { public void disconnected(final Controller controller) { ui.controllerDisconnected(); } + @Override public void connected(final Controller controller) { selectFirst(); ui.controllerConnected(); } + public boolean pointerMoved(int screenX, int screenY) { unselectActors(); return false; @@ -417,152 +408,128 @@ public class UIScene extends Scene { } }, 0.10f); } + public void unselectActors() { for (Selectable selectable : getPossibleSelection()) { - selectable.onDeSelect(); + selectable.onDeSelect(); } } - Array visibleSelection() - { - Array selectables=new Array<>(); + + Array visibleSelection() { + Array selectables = new Array<>(); for (Selectable selectable : getPossibleSelection()) { - if(selectable.actor.isVisible()) - { - if(selectable.actor instanceof Button) - { - if(!((Button)selectable.actor).isDisabled()) + if (selectable.actor.isVisible()) { + if (selectable.actor instanceof Button) { + if (!((Button) selectable.actor).isDisabled()) selectables.add(selectable); - } - else - { + } else { selectables.add(selectable); } } } return selectables; } + public void selectNextDown() { - if(getSelected()==null) - { + if (getSelected() == null) { selectFirst(); - } - else - { - Selectable current =getSelected(); - Array candidates=new Array<>(); - for(Selectable selectable:visibleSelection()) - { - if(selectable.xDiff(current)<0.1&&selectable!=current) + } else { + Selectable current = getSelected(); + Array candidates = new Array<>(); + for (Selectable selectable : visibleSelection()) { + if (selectable.xDiff(current) < 0.1 && selectable != current) candidates.add(selectable); } - if(candidates.isEmpty()) + if (candidates.isEmpty()) candidates.addAll(visibleSelection()); - Selectable finalOne=null; - Selectable fallback=null; - for(Selectable candidate:candidates) - { - if(fallback==null||candidate.getY()>fallback.getY()) - fallback=candidate; - if(candidate.getY() fallback.getY()) + fallback = candidate; + if (candidate.getY() < current.getY() && (finalOne == null || current.yDiff(candidate) < current.yDiff(finalOne))) { + finalOne = candidate; } } - if(finalOne==null) - for(Selectable candidate:visibleSelection()) - { - if(candidate.getY() candidates=new Array<>(); - for(Selectable selectable:visibleSelection()) - { - if(selectable.yDiff(current)<0.1&&selectable!=current) + } else { + Selectable current = getSelected(); + Array candidates = new Array<>(); + for (Selectable selectable : visibleSelection()) { + if (selectable.yDiff(current) < 0.1 && selectable != current) candidates.add(selectable); } - if(candidates.isEmpty()) + if (candidates.isEmpty()) candidates.addAll(visibleSelection()); - Selectable finalOne=null; - Selectable fallback=null; - for(Selectable candidate:candidates) - { - if(fallback==null||candidate.getX()>fallback.getX()) - fallback=candidate; - if(candidate.getX() fallback.getX()) + fallback = candidate; + if (candidate.getX() < current.getX() && (finalOne == null || current.xDiff(candidate) < current.xDiff(finalOne))) { + finalOne = candidate; } } - if(finalOne==null) - for(Selectable candidate:visibleSelection()) - { - if(candidate.getX() candidates=new Array<>(); - for(Selectable selectable:visibleSelection()) - { - if(selectable.yDiff(current)<0.1&&selectable!=current) + } else { + Selectable current = getSelected(); + Array candidates = new Array<>(); + for (Selectable selectable : visibleSelection()) { + if (selectable.yDiff(current) < 0.1 && selectable != current) candidates.add(selectable); } - if(candidates.isEmpty()) + if (candidates.isEmpty()) candidates.addAll(visibleSelection()); - Selectable finalOne=null; - Selectable fallback=null; - for(Selectable candidate:candidates) - { - if(fallback==null||candidate.getX()current.getX()&&(finalOne==null||current.xDiff(candidate) current.getX() && (finalOne == null || current.xDiff(candidate) < current.xDiff(finalOne))) { + finalOne = candidate; } } - if(finalOne==null) - for(Selectable candidate:visibleSelection()) - { - if(candidate.getX()>current.getX()&&(finalOne==null||current.xDiff(candidate) current.getX() && (finalOne == null || current.xDiff(candidate) < current.xDiff(finalOne))) { + finalOne = candidate; } } - if(finalOne!=null) + if (finalOne != null) selectActor(finalOne); - else if(fallback!=null) + else if (fallback != null) selectActor(fallback); } @@ -571,43 +538,35 @@ public class UIScene extends Scene { public void selectNextUp() { - if(getSelected()==null) - { + if (getSelected() == null) { selectFirst(); - } - else - { - Selectable current =getSelected(); - Array candidates=new Array<>(); - for(Selectable selectable:visibleSelection()) - { - if(selectable.xDiff(current)<0.1&&selectable!=current) + } else { + Selectable current = getSelected(); + Array candidates = new Array<>(); + for (Selectable selectable : visibleSelection()) { + if (selectable.xDiff(current) < 0.1 && selectable != current) candidates.add(selectable); } - if(candidates.isEmpty()) + if (candidates.isEmpty()) candidates.addAll(visibleSelection()); - Selectable finalOne=null; - Selectable fallback=null; - for(Selectable candidate:candidates) - { - if(fallback==null||candidate.getY()current.getY()&&(finalOne==null||current.yDiff(candidate) current.getY() && (finalOne == null || current.yDiff(candidate) < current.yDiff(finalOne))) { + finalOne = candidate; } } - if(finalOne==null)//allowAllNow - for(Selectable candidate:visibleSelection()) - { - if(candidate.getY()>current.getY()&&(finalOne==null||current.yDiff(candidate) current.getY() && (finalOne == null || current.yDiff(candidate) < current.yDiff(finalOne))) { + finalOne = candidate; } } - if(finalOne!=null) + if (finalOne != null) selectActor(finalOne); - else if(fallback!=null) + else if (fallback != null) selectActor(fallback); } @@ -615,22 +574,18 @@ public class UIScene extends Scene { private void selectFirst() { - Selectable result=null; - for(Selectable candidate: getPossibleSelection()) - { - if(result==null|| candidate.getY()>result.getY()) - { - result=candidate; + Selectable result = null; + for (Selectable candidate : getPossibleSelection()) { + if (result == null || candidate.getY() > result.getY()) { + result = candidate; } } selectActor(result); } - ScrollPane scrollPaneOfActor(Actor actor) - { - while (actor!=null) - { - if(actor.getParent() instanceof ScrollPane) - { + + ScrollPane scrollPaneOfActor(Actor actor) { + while (actor != null) { + if (actor.getParent() instanceof ScrollPane) { return (ScrollPane) actor.getParent(); } actor = actor.getParent(); @@ -641,16 +596,16 @@ public class UIScene extends Scene { public void selectActor(Selectable actor) { - unselectActors(); - if(actor==null)return; - stage.setKeyboardFocus(actor.actor); - ScrollPane scrollPane=scrollPaneOfActor(actor.actor); - if(scrollPane!=null) - { - scrollPane.scrollTo(actor.actor.getX(),actor.actor.getY(),actor.actor.getWidth(),actor.actor.getHeight(),false,false); - } - actor.onSelect(this); + unselectActors(); + if (actor == null) return; + stage.setKeyboardFocus(actor.actor); + ScrollPane scrollPane = scrollPaneOfActor(actor.actor); + if (scrollPane != null) { + scrollPane.scrollTo(actor.actor.getX(), actor.actor.getY(), actor.actor.getWidth(), actor.actor.getHeight(), false, false); + } + actor.onSelect(this); } + Image screenImage; TextureRegion backgroundTexture; @@ -659,6 +614,7 @@ public class UIScene extends Scene { stage.cancelTouchFocus(); return super.leave(); } + @Override public void enter() { if (screenImage != null) { @@ -674,6 +630,7 @@ public class UIScene extends Scene { Gdx.input.setInputProcessor(stage); super.enter(); } + public TextureRegion getUIBackground() { try { Actor a = ui.getChild(0); diff --git a/forge-gui-mobile/src/forge/adventure/stage/GameHUD.java b/forge-gui-mobile/src/forge/adventure/stage/GameHUD.java index 1a9b91db2cb..d24d5cc4d77 100644 --- a/forge-gui-mobile/src/forge/adventure/stage/GameHUD.java +++ b/forge-gui-mobile/src/forge/adventure/stage/GameHUD.java @@ -2,6 +2,8 @@ package forge.adventure.stage; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Input; +import com.badlogic.gdx.audio.Music; +import com.badlogic.gdx.files.FileHandle; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.Pixmap; import com.badlogic.gdx.graphics.Texture; @@ -33,8 +35,11 @@ import forge.adventure.world.WorldSave; import forge.deck.Deck; import forge.gui.FThreads; import forge.gui.GuiBase; +import forge.localinstance.properties.ForgePreferences; +import forge.model.FModel; import forge.sound.MusicPlaylist; import forge.sound.SoundSystem; +import org.apache.commons.lang3.tuple.Pair; /** * Stage to handle everything rendered in the HUD @@ -275,7 +280,10 @@ public class GameHUD extends Stage { updatelife = false; lifePoints.setText("[%95][+Life]" + lifepointsTextColor + " " + AdventurePlayer.current().getLife() + "/" + AdventurePlayer.current().getMaxLife()); } - updateMusic(); + if (!GameScene.instance().isNotInWorldMap()) + updateMusic(); + else + SoundSystem.instance.pause(); } Texture miniMapTexture; @@ -301,7 +309,122 @@ public class GameHUD extends Stage { } else { deckActor.setColor(menuActor.getColor()); } - updateMusic(); + if (GameScene.instance().isNotInWorldMap()) { + SoundSystem.instance.pause(); + playAudio(); + } else { + unloadAudio(); + SoundSystem.instance.resume(); // resume World BGM + } + } + + private Pair audio = null; + + public void playAudio() { + switch (GameScene.instance().getAdventurePlayerLocation(false, false)) { + case "capital": + case "town": + setAudio(MusicPlaylist.TOWN); + break; + case "dungeon": + case "cave": + setAudio(MusicPlaylist.CAVE); + break; + case "castle": + setAudio(MusicPlaylist.CASTLE); + break; + default: + break; + } + if (audio != null) { + audio.getRight().setLooping(true); + audio.getRight().play(); + audio.getRight().setVolume(FModel.getPreferences().getPrefInt(ForgePreferences.FPref.UI_VOL_MUSIC) / 100f); + } + } + + public void fadeAudio(float value) { + if (audio != null) { + audio.getRight().setVolume((FModel.getPreferences().getPrefInt(ForgePreferences.FPref.UI_VOL_MUSIC) * value) / 100f); + } + } + + float fade = 1f; + + void fadeIn() { + if (fade >= 1f) + return; + for (int i = 10; i > 1; i--) { + float delay = i * 0.1f; + Timer.schedule(new Timer.Task() { + @Override + public void run() { + fade += 0.1f; + if (fade > 1f) + fade = 1f; + fadeAudio(fade); + } + }, delay); + } + } + + void fadeOut() { + for (int i = 10; i > 1; i--) { + float delay = i * 0.1f; + Timer.schedule(new Timer.Task() { + @Override + public void run() { + fade -= 0.1f; + if (fade < 0.1f) + fade = 0.1f; + fadeAudio(fade); + } + }, delay); + } + } + + public void stopAudio() { + if (audio != null) { + audio.getRight().stop(); + } + } + + public void pauseMusic() { + if (audio != null) { + audio.getRight().pause(); + } + SoundSystem.instance.pause(); + } + + public void unloadAudio() { + if (audio != null) { + audio.getRight().setOnCompletionListener(null); + audio.getRight().stop(); + Forge.getAssets().manager().unload(audio.getLeft().path()); + } + audio = null; + currentAudioPlaylist = null; + } + + private MusicPlaylist currentAudioPlaylist = null; + + private void setAudio(MusicPlaylist playlist) { + if (playlist.equals(currentAudioPlaylist)) + return; + unloadAudio(); + audio = getMusic(playlist); + } + + private Pair getMusic(MusicPlaylist playlist) { + FileHandle file = Gdx.files.absolute(playlist.getNewRandomFilename()); + Music music = Forge.getAssets().getMusic(file); + if (music != null) { + currentAudioPlaylist = playlist; + return Pair.of(file, music); + } else { + currentAudioPlaylist = null; + return null; + } } private void openDeck() { @@ -580,17 +703,6 @@ public class GameHUD extends Stage { case "white": changeBGM(MusicPlaylist.WHITE); break; - case "capital": - case "town": - changeBGM(MusicPlaylist.TOWN); - break; - case "dungeon": - case "cave": - changeBGM(MusicPlaylist.CAVE); - break; - case "castle": - changeBGM(MusicPlaylist.CASTLE); - break; case "waste": changeBGM(MusicPlaylist.MENUS); break; @@ -598,7 +710,6 @@ public class GameHUD extends Stage { break; } } - float fade = 1f; void changeBGM(MusicPlaylist playlist) { if (!playlist.equals(SoundSystem.instance.getCurrentPlaylist())) { diff --git a/forge-gui-mobile/src/forge/adventure/stage/MapSprite.java b/forge-gui-mobile/src/forge/adventure/stage/MapSprite.java index 27188dbe120..87252921090 100644 --- a/forge-gui-mobile/src/forge/adventure/stage/MapSprite.java +++ b/forge-gui-mobile/src/forge/adventure/stage/MapSprite.java @@ -63,30 +63,6 @@ public class MapSprite extends Actor { return actorGroup; } - public static String getBoundaryName(int chunkX, int chunkY) { - String boundary = ""; - List poi = WorldSave.getCurrentSave().getWorld().getPointsOfInterest(chunkX, chunkY); - - for (PointOfInterest p : poi) { - if ("town".equalsIgnoreCase(p.getData().type)) { - if (p.getData().name.startsWith("Waste")) - boundary = "waste"; - else if (p.getData().name.startsWith("Plains")) - boundary = "white"; - else if (p.getData().name.startsWith("Forest")) - boundary = "green"; - else if (p.getData().name.startsWith("Island")) - boundary = "blue"; - else if (p.getData().name.startsWith("Mountain")) - boundary = "red"; - else if (p.getData().name.startsWith("Swamp")) - boundary = "black"; - break; - } - } - return boundary; - } - //BitmapFont font; @Override public void draw(Batch batch, float parentAlpha) { diff --git a/forge-gui-mobile/src/forge/adventure/stage/WorldStage.java b/forge-gui-mobile/src/forge/adventure/stage/WorldStage.java index 1cd18b07c80..047e4b9804b 100644 --- a/forge-gui-mobile/src/forge/adventure/stage/WorldStage.java +++ b/forge-gui-mobile/src/forge/adventure/stage/WorldStage.java @@ -294,12 +294,6 @@ public class WorldStage extends GameStage implements SaveFileContent { background.loadChunk(pos.x, pos.y); handlePointsOfInterestCollision(); } - public String getBoundary() { - if (background == null) - return ""; - GridPoint2 pos = background.translateFromWorldToChunk(player.getX(), player.getY()); - return MapSprite.getBoundaryName(pos.x, pos.y); - } @Override public void leave() { diff --git a/forge-gui-mobile/src/forge/adventure/util/CardUtil.java b/forge-gui-mobile/src/forge/adventure/util/CardUtil.java index 108fa1f2927..1aceb7abb97 100644 --- a/forge-gui-mobile/src/forge/adventure/util/CardUtil.java +++ b/forge-gui-mobile/src/forge/adventure/util/CardUtil.java @@ -648,7 +648,9 @@ public class CardUtil { FileHandle handle = Config.instance().getFile(path); if (handle.exists()) return generateDeck(json.fromJson(GeneratedDeckData.class, handle), starterEdition, discourageDuplicates); - return null; + Deck deck = DeckgenUtil.getRandomOrPreconOrThemeDeck(colors, true, false, true); + System.err.println("Error loading JSON: " + handle.path() + "\nGenerating random deck: "+deck.getName()); + return deck; } diff --git a/forge-gui-mobile/src/forge/adventure/util/Controls.java b/forge-gui-mobile/src/forge/adventure/util/Controls.java index be813e19a87..ebc99cd67b2 100644 --- a/forge-gui-mobile/src/forge/adventure/util/Controls.java +++ b/forge-gui-mobile/src/forge/adventure/util/Controls.java @@ -27,6 +27,8 @@ import com.github.tommyettinger.textra.TypingLabel; import forge.Forge; import forge.adventure.player.AdventurePlayer; import forge.card.ColorSet; +import forge.sound.SoundEffectType; +import forge.sound.SoundSystem; import java.util.function.Function; @@ -52,6 +54,13 @@ public class Controls { static class TextButtonFix extends TextraButton { public TextButtonFix(@Null String text) { super(text == null ? "NULL" : text, Controls.getSkin(), Controls.getTextraFont()); + addListener(new ClickListener(){ + @Override + public void clicked(InputEvent event, float x, float y) { + super.clicked(event, x, y); + SoundSystem.instance.play(SoundEffectType.ButtonPress, false); + } + }); } @Override @@ -74,6 +83,7 @@ public class Controls { getTextraLabel().setWidth(getTextraLabel().layout.getWidth() + (getTextraLabel().style != null && getTextraLabel().style.background != null ? getTextraLabel().style.background.getLeftWidth() + getTextraLabel().style.background.getRightWidth() : 0.0F)); layout(); } + } static public TextraButton newTextButton(String text) { diff --git a/forge-gui-mobile/src/forge/adventure/util/MapDialog.java b/forge-gui-mobile/src/forge/adventure/util/MapDialog.java index 225676a8f7b..1cc22adcd1d 100644 --- a/forge-gui-mobile/src/forge/adventure/util/MapDialog.java +++ b/forge-gui-mobile/src/forge/adventure/util/MapDialog.java @@ -15,11 +15,11 @@ import forge.Forge; import forge.adventure.character.EnemySprite; import forge.adventure.data.DialogData; import forge.adventure.player.AdventurePlayer; +import forge.adventure.stage.GameHUD; import forge.adventure.stage.MapStage; import forge.card.ColorSet; import forge.localinstance.properties.ForgePreferences; import forge.model.FModel; -import forge.sound.SoundSystem; import forge.util.Localizer; import org.apache.commons.lang3.tuple.Pair; @@ -196,7 +196,7 @@ public class MapDialog { fade += 0.1f; if (fade > 1f) fade = 1f; - SoundSystem.instance.fadeModifier(fade); + GameHUD.getInstance().fadeAudio(fade); } }, delay); } @@ -211,7 +211,7 @@ public class MapDialog { fade -= 0.1f; if (fade < 0.1f) fade = 0.1f; - SoundSystem.instance.fadeModifier(fade); + GameHUD.getInstance().fadeAudio(fade); } }, delay); } diff --git a/forge-gui-mobile/src/forge/adventure/util/RewardActor.java b/forge-gui-mobile/src/forge/adventure/util/RewardActor.java index 13cefacef11..71ae37acca7 100644 --- a/forge-gui-mobile/src/forge/adventure/util/RewardActor.java +++ b/forge-gui-mobile/src/forge/adventure/util/RewardActor.java @@ -41,6 +41,8 @@ import forge.card.CardRenderer; import forge.game.card.CardView; import forge.gui.GuiBase; import forge.item.PaperCard; +import forge.sound.SoundEffectType; +import forge.sound.SoundSystem; import forge.util.ImageFetcher; import forge.util.ImageUtil; import org.apache.commons.lang3.StringUtils; @@ -593,6 +595,7 @@ public class RewardActor extends Actor implements Disposable, ImageFetcher.Callb return; clicked = true; flipProcess = 0; + SoundSystem.instance.play(SoundEffectType.FlipCard, false); } public void sold() { @@ -608,7 +611,7 @@ public class RewardActor extends Actor implements Disposable, ImageFetcher.Callb super.act(delta); if (clicked) { if (flipProcess < 1) - flipProcess += delta * 1.5; + flipProcess += delta * 2.4; else flipProcess = 1; diff --git a/forge-gui-mobile/src/forge/adventure/world/World.java b/forge-gui-mobile/src/forge/adventure/world/World.java index a94706bc3b1..3ee2f0090aa 100644 --- a/forge-gui-mobile/src/forge/adventure/world/World.java +++ b/forge-gui-mobile/src/forge/adventure/world/World.java @@ -238,6 +238,14 @@ public class World implements Disposable, SaveFileContent { } } + public long getBiomeMapXY(int x, int y) { + try { + return biomeMap[x][height - y - 1] & (~(0b1< - eJzVlUkOgCAMRdl6Me9/JFcmhkCHP2hswgp++0pbOI8xzh+tlb2lj3SIVbURRyevbtz7LGORPspJ4b+i/ZIv85P1oKK2We9UOJ+aiI+ZlZ3fynxX+Jxs816kc/KtajHzIf5Ud6c2BZ8rN0fvKQydLSbeM+7M4GBD3l12ddm6+VffPwVfplH1DlNf9M9C4nT/N3aeunF2nNFfhDJltXfNDcOInGHjZ+cqewo+5/2z86uu/8p/961w9ucuhnsxDBe0OnBV + eJzVl11uwkAMhHnMPsBtegWKckDOgNqehjOgwjHIKrLqjDz+WZUHRhopJNn1F6/3h2Pb7Y5v5NPi7+nPXZX2uq12tq2WfuYpionfg0IO65nV1sqdvh9pTr53a1sjQ+a7Ti3XZoSPSWLflbN8+NviiPgidhy/DB/jxVhz8+tAP2Pv4Liz2hQei81jZHPCm6OePD6PDd+NYjCmbL4rfJU84JhafDh/u9j6lGWTa0vn/WqMgzG99ZGpwhf18XGoxa6yZfis2rweVr+Sy1tTIr5MPN0f67vCZvWB7BHTf9tbVzSflY8Kl9SD5VG+aNwz+cvUqWbFfrJ8LHcsjrBpXabVkTAXbMxG1h3Nqpku6twYcbJ9ITN3qvJq65PUDzLgPTlXjKwrFcYMX/fXkuufactm7ZeZ+Jb6WEv/3p7LWHueZnXNpM+60XpiKbsPsxpj7YULc47nzJHcix7kO3/b9n+AZdZOz03L7DvRjO3V9sYt8hMoNu4z diff --git a/forge-gui/res/adventure/Shandalar/sprites/heroes/devil_f.atlas b/forge-gui/res/adventure/Shandalar/sprites/heroes/devil_f.atlas index f74f0f227e3..eea311559b0 100644 --- a/forge-gui/res/adventure/Shandalar/sprites/heroes/devil_f.atlas +++ b/forge-gui/res/adventure/Shandalar/sprites/heroes/devil_f.atlas @@ -130,7 +130,7 @@ WalkDown xy: 144, 16 size: 16, 16 WalkDown - xy: 160, 0 + xy: 160, 16 size: 16, 16 WalkDown xy: 176, 16 diff --git a/forge-gui/res/adventure/Shandalar/sprites/heroes/devil_m.atlas b/forge-gui/res/adventure/Shandalar/sprites/heroes/devil_m.atlas index e73b83092f4..0c69e52cadf 100644 --- a/forge-gui/res/adventure/Shandalar/sprites/heroes/devil_m.atlas +++ b/forge-gui/res/adventure/Shandalar/sprites/heroes/devil_m.atlas @@ -130,7 +130,7 @@ WalkDown xy: 144, 16 size: 16, 16 WalkDown - xy: 160, 0 + xy: 160, 16 size: 16, 16 WalkDown xy: 176, 16 diff --git a/forge-gui/res/adventure/Shandalar/sprites/heroes/dwarf_f.atlas b/forge-gui/res/adventure/Shandalar/sprites/heroes/dwarf_f.atlas index 057b175d0cb..1f50e503b18 100644 --- a/forge-gui/res/adventure/Shandalar/sprites/heroes/dwarf_f.atlas +++ b/forge-gui/res/adventure/Shandalar/sprites/heroes/dwarf_f.atlas @@ -130,7 +130,7 @@ WalkDown xy: 144, 16 size: 16, 16 WalkDown - xy: 160, 0 + xy: 160, 16 size: 16, 16 WalkDown xy: 176, 16 diff --git a/forge-gui/res/adventure/Shandalar/sprites/heroes/dwarf_m.atlas b/forge-gui/res/adventure/Shandalar/sprites/heroes/dwarf_m.atlas index bcb9acccb0e..8bbb8643143 100644 --- a/forge-gui/res/adventure/Shandalar/sprites/heroes/dwarf_m.atlas +++ b/forge-gui/res/adventure/Shandalar/sprites/heroes/dwarf_m.atlas @@ -130,7 +130,7 @@ WalkDown xy: 144, 16 size: 16, 16 WalkDown - xy: 160, 0 + xy: 160, 16 size: 16, 16 WalkDown xy: 176, 16 diff --git a/forge-gui/res/adventure/Shandalar/sprites/heroes/elf_f.atlas b/forge-gui/res/adventure/Shandalar/sprites/heroes/elf_f.atlas index 3ed50cfca8b..52870af1724 100644 --- a/forge-gui/res/adventure/Shandalar/sprites/heroes/elf_f.atlas +++ b/forge-gui/res/adventure/Shandalar/sprites/heroes/elf_f.atlas @@ -130,7 +130,7 @@ WalkDown xy: 144, 16 size: 16, 16 WalkDown - xy: 160, 0 + xy: 160, 16 size: 16, 16 WalkDown xy: 176, 16 diff --git a/forge-gui/res/adventure/Shandalar/sprites/heroes/elf_m.atlas b/forge-gui/res/adventure/Shandalar/sprites/heroes/elf_m.atlas index af6cc32db79..eb666543667 100644 --- a/forge-gui/res/adventure/Shandalar/sprites/heroes/elf_m.atlas +++ b/forge-gui/res/adventure/Shandalar/sprites/heroes/elf_m.atlas @@ -130,7 +130,7 @@ WalkDown xy: 144, 16 size: 16, 16 WalkDown - xy: 160, 0 + xy: 160, 16 size: 16, 16 WalkDown xy: 176, 16 diff --git a/forge-gui/res/adventure/Shandalar/sprites/heroes/human_f.atlas b/forge-gui/res/adventure/Shandalar/sprites/heroes/human_f.atlas index a2c6cdcb1cb..4ca358f3222 100644 --- a/forge-gui/res/adventure/Shandalar/sprites/heroes/human_f.atlas +++ b/forge-gui/res/adventure/Shandalar/sprites/heroes/human_f.atlas @@ -130,7 +130,7 @@ WalkDown xy: 144, 16 size: 16, 16 WalkDown - xy: 160, 0 + xy: 160, 16 size: 16, 16 WalkDown xy: 176, 16 diff --git a/forge-gui/res/adventure/Shandalar/sprites/heroes/human_m.atlas b/forge-gui/res/adventure/Shandalar/sprites/heroes/human_m.atlas index cb4150e8783..7e0d697a3fc 100644 --- a/forge-gui/res/adventure/Shandalar/sprites/heroes/human_m.atlas +++ b/forge-gui/res/adventure/Shandalar/sprites/heroes/human_m.atlas @@ -130,7 +130,7 @@ WalkDown xy: 144, 16 size: 16, 16 WalkDown - xy: 160, 0 + xy: 160, 16 size: 16, 16 WalkDown xy: 176, 16 diff --git a/forge-gui/res/adventure/Shandalar/sprites/heroes/kor_f.atlas b/forge-gui/res/adventure/Shandalar/sprites/heroes/kor_f.atlas index 08333a8d63c..52c6fa7a716 100644 --- a/forge-gui/res/adventure/Shandalar/sprites/heroes/kor_f.atlas +++ b/forge-gui/res/adventure/Shandalar/sprites/heroes/kor_f.atlas @@ -130,7 +130,7 @@ WalkDown xy: 144, 16 size: 16, 16 WalkDown - xy: 160, 0 + xy: 160, 16 size: 16, 16 WalkDown xy: 176, 16 diff --git a/forge-gui/res/adventure/Shandalar/sprites/heroes/kor_m.atlas b/forge-gui/res/adventure/Shandalar/sprites/heroes/kor_m.atlas index e97dfb3a6ab..5d7b348f318 100644 --- a/forge-gui/res/adventure/Shandalar/sprites/heroes/kor_m.atlas +++ b/forge-gui/res/adventure/Shandalar/sprites/heroes/kor_m.atlas @@ -130,7 +130,7 @@ WalkDown xy: 144, 16 size: 16, 16 WalkDown - xy: 160, 0 + xy: 160, 16 size: 16, 16 WalkDown xy: 176, 16 diff --git a/forge-gui/res/adventure/Shandalar/sprites/heroes/metathran_f.atlas b/forge-gui/res/adventure/Shandalar/sprites/heroes/metathran_f.atlas index 2f6381788ed..c22ba5659c4 100644 --- a/forge-gui/res/adventure/Shandalar/sprites/heroes/metathran_f.atlas +++ b/forge-gui/res/adventure/Shandalar/sprites/heroes/metathran_f.atlas @@ -130,7 +130,7 @@ WalkDown xy: 144, 16 size: 16, 16 WalkDown - xy: 160, 0 + xy: 160, 16 size: 16, 16 WalkDown xy: 176, 16 diff --git a/forge-gui/res/adventure/Shandalar/sprites/heroes/metathran_m.atlas b/forge-gui/res/adventure/Shandalar/sprites/heroes/metathran_m.atlas index 1dfcbc9ea5c..f459edd47e0 100644 --- a/forge-gui/res/adventure/Shandalar/sprites/heroes/metathran_m.atlas +++ b/forge-gui/res/adventure/Shandalar/sprites/heroes/metathran_m.atlas @@ -130,7 +130,7 @@ WalkDown xy: 144, 16 size: 16, 16 WalkDown - xy: 160, 0 + xy: 160, 16 size: 16, 16 WalkDown xy: 176, 16 diff --git a/forge-gui/res/adventure/Shandalar/sprites/heroes/phyrexian_r.atlas b/forge-gui/res/adventure/Shandalar/sprites/heroes/phyrexian_r.atlas index 79bab0a41b3..4d965a6dd67 100644 --- a/forge-gui/res/adventure/Shandalar/sprites/heroes/phyrexian_r.atlas +++ b/forge-gui/res/adventure/Shandalar/sprites/heroes/phyrexian_r.atlas @@ -130,7 +130,7 @@ WalkDown xy: 144, 16 size: 16, 16 WalkDown - xy: 160, 0 + xy: 160, 16 size: 16, 16 WalkDown xy: 176, 16 diff --git a/forge-gui/res/adventure/Shandalar/sprites/heroes/phyrexian_u.atlas b/forge-gui/res/adventure/Shandalar/sprites/heroes/phyrexian_u.atlas index 617d110aca0..b49a88230a4 100644 --- a/forge-gui/res/adventure/Shandalar/sprites/heroes/phyrexian_u.atlas +++ b/forge-gui/res/adventure/Shandalar/sprites/heroes/phyrexian_u.atlas @@ -130,7 +130,7 @@ WalkDown xy: 144, 16 size: 16, 16 WalkDown - xy: 160, 0 + xy: 160, 16 size: 16, 16 WalkDown xy: 176, 16 diff --git a/forge-gui/res/adventure/Shandalar/sprites/heroes/undead_f.atlas b/forge-gui/res/adventure/Shandalar/sprites/heroes/undead_f.atlas index 483715fb39d..5e324f85588 100644 --- a/forge-gui/res/adventure/Shandalar/sprites/heroes/undead_f.atlas +++ b/forge-gui/res/adventure/Shandalar/sprites/heroes/undead_f.atlas @@ -130,7 +130,7 @@ WalkDown xy: 144, 16 size: 16, 16 WalkDown - xy: 160, 0 + xy: 160, 16 size: 16, 16 WalkDown xy: 176, 16 diff --git a/forge-gui/res/adventure/Shandalar/sprites/heroes/undead_m.atlas b/forge-gui/res/adventure/Shandalar/sprites/heroes/undead_m.atlas index a6db8ece6bb..8cbfb68ca4e 100644 --- a/forge-gui/res/adventure/Shandalar/sprites/heroes/undead_m.atlas +++ b/forge-gui/res/adventure/Shandalar/sprites/heroes/undead_m.atlas @@ -130,7 +130,7 @@ WalkDown xy: 144, 16 size: 16, 16 WalkDown - xy: 160, 0 + xy: 160, 16 size: 16, 16 WalkDown xy: 176, 16 diff --git a/forge-gui/res/adventure/Shandalar/sprites/heroes/viashino_f.atlas b/forge-gui/res/adventure/Shandalar/sprites/heroes/viashino_f.atlas index 20378f573ba..3ef4d042ee4 100644 --- a/forge-gui/res/adventure/Shandalar/sprites/heroes/viashino_f.atlas +++ b/forge-gui/res/adventure/Shandalar/sprites/heroes/viashino_f.atlas @@ -130,7 +130,7 @@ WalkDown xy: 144, 16 size: 16, 16 WalkDown - xy: 160, 0 + xy: 160, 16 size: 16, 16 WalkDown xy: 176, 16 diff --git a/forge-gui/res/adventure/Shandalar/sprites/heroes/viashino_m.atlas b/forge-gui/res/adventure/Shandalar/sprites/heroes/viashino_m.atlas index e56db484379..c6abb1cda71 100644 --- a/forge-gui/res/adventure/Shandalar/sprites/heroes/viashino_m.atlas +++ b/forge-gui/res/adventure/Shandalar/sprites/heroes/viashino_m.atlas @@ -130,7 +130,7 @@ WalkDown xy: 144, 16 size: 16, 16 WalkDown - xy: 160, 0 + xy: 160, 16 size: 16, 16 WalkDown xy: 176, 16 diff --git a/forge-gui/res/adventure/Shandalar/world/enemies.json b/forge-gui/res/adventure/Shandalar/world/enemies.json index a782a6a39b0..4e43022e1bb 100644 --- a/forge-gui/res/adventure/Shandalar/world/enemies.json +++ b/forge-gui/res/adventure/Shandalar/world/enemies.json @@ -351,7 +351,11 @@ "type": "deckCard", "probability": 1, "count": 2, - "addMaxCount": 6 + "addMaxCount": 6, + "rarity": [ + "common", + "uncommon" + ] }, { "type": "card", @@ -1241,12 +1245,16 @@ "type": "deckCard", "probability": 1, "count": 2, - "addMaxCount": 4 + "addMaxCount": 4, + "rarity": [ + "common", + "uncommon" + ] }, { "type": "card", "probability": 0.5, - "count": 3, + "count": 1, "colors": [ "Green" ], @@ -1330,7 +1338,11 @@ "type": "deckCard", "probability": 1, "count": 2, - "addMaxCount": 4 + "addMaxCount": 5, + "rarity": [ + "common", + "uncommon" + ] }, { "type": "card", @@ -2830,7 +2842,11 @@ "type": "deckCard", "probability": 1, "count": 2, - "addMaxCount": 4 + "addMaxCount": 5, + "rarity": [ + "common", + "uncommon" + ] }, { "type": "gold", @@ -3366,7 +3382,7 @@ "type": "deckCard", "probability": 1, "count": 2, - "addMaxCount": 8 + "addMaxCount": 4 }, { "type": "card", @@ -3397,7 +3413,7 @@ { "type": "card", "probability": 1, - "count": 3, + "count": 1, "colors": [ "Blue" ], @@ -4153,7 +4169,7 @@ "type": "deckCard", "probability": 1, "count": 2, - "addMaxCount": 8 + "addMaxCount": 4 }, { "type": "card", @@ -4471,7 +4487,11 @@ "type": "deckCard", "probability": 1, "count": 2, - "addMaxCount": 8 + "addMaxCount": 4, + "rarity": [ + "common", + "uncommon" + ] }, { "type": "card", @@ -4519,7 +4539,11 @@ "type": "deckCard", "probability": 1, "count": 2, - "addMaxCount": 8 + "addMaxCount": 5, + "rarity": [ + "common", + "uncommon" + ] }, { "type": "card", @@ -4643,7 +4667,11 @@ "type": "deckCard", "probability": 1, "count": 2, - "addMaxCount": 8 + "addMaxCount": 4, + "rarity": [ + "common", + "uncommon" + ] }, { "type": "card", @@ -5087,7 +5115,11 @@ "type": "deckCard", "probability": 1, "count": 2, - "addMaxCount": 4 + "addMaxCount": 8, + "rarity": [ + "common", + "uncommon" + ] }, { "type": "card", @@ -6524,7 +6556,7 @@ "type": "deckCard", "probability": 1, "count": 2, - "addMaxCount": 8 + "addMaxCount": 4 }, { "type": "card", @@ -6755,7 +6787,11 @@ "type": "deckCard", "probability": 1, "count": 2, - "addMaxCount": 4 + "addMaxCount": 6, + "rarity": [ + "common", + "uncommon" + ] }, { "type": "gold", @@ -6794,7 +6830,11 @@ "type": "deckCard", "probability": 1, "count": 2, - "addMaxCount": 4 + "addMaxCount": 4, + "rarity": [ + "common", + "uncommon" + ] }, { "type": "gold", @@ -6802,23 +6842,6 @@ "count": 10, "addMaxCount": 90 }, - { - "type": "card", - "probability": 0.5, - "count": 2, - "colors": [ - "Green" - ], - "rarity": [ - "Mythic Rare" - ] - }, - { - "type": "deckCard", - "probability": 1, - "count": 2, - "addMaxCount": 8 - }, { "type": "card", "probability": 1, @@ -7303,7 +7326,11 @@ "type": "deckCard", "probability": 1, "count": 2, - "addMaxCount": 8 + "addMaxCount": 8, + "rarity": [ + "common", + "uncommon" + ] }, { "type": "card", @@ -7349,7 +7376,7 @@ "type": "deckCard", "probability": 1, "count": 2, - "addMaxCount": 8 + "addMaxCount": 4 }, { "type": "card", @@ -8432,7 +8459,11 @@ "type": "deckCard", "probability": 1, "count": 2, - "addMaxCount": 4 + "addMaxCount": 4, + "rarity": [ + "common", + "uncommon" + ] }, { "type": "gold", @@ -9187,7 +9218,11 @@ "type": "deckCard", "probability": 1, "count": 2, - "addMaxCount": 8 + "addMaxCount": 8, + "rarity": [ + "common", + "uncommon" + ] }, { "type": "card", @@ -9866,7 +9901,11 @@ "type": "deckCard", "probability": 1, "count": 3, - "addMaxCount": 7 + "addMaxCount": 6, + "rarity": [ + "common", + "uncommon" + ] }, { "type": "gold", @@ -10194,7 +10233,11 @@ "type": "deckCard", "probability": 1, "count": 2, - "addMaxCount": 8 + "addMaxCount": 8, + "rarity": [ + "common", + "uncommon" + ] }, { "type": "card", @@ -10716,7 +10759,7 @@ "type": "deckCard", "probability": 1, "count": 2, - "addMaxCount": 8 + "addMaxCount": 4 }, { "type": "card", @@ -11219,18 +11262,11 @@ { "type": "deckCard", "probability": 1, - "count": 1, - "addMaxCount": 4, + "count": 2, + "addMaxCount": 8, "rarity": [ "common", "uncommon" - ], - "cardTypes": [ - "Creature", - "Artifact", - "Enchantment", - "Instant", - "Sorcery" ] }, { diff --git a/forge-gui/res/adventure/Shandalar/world/white.json b/forge-gui/res/adventure/Shandalar/world/white.json index 95363006152..80b9dd8cb44 100644 --- a/forge-gui/res/adventure/Shandalar/world/white.json +++ b/forge-gui/res/adventure/Shandalar/world/white.json @@ -45,7 +45,6 @@ "Fox", "Frost Titan", "Griffin", - "Horse", "Horseman", "Human", "Human elite", diff --git a/forge-gui/res/adventure/music/boss/boss1.mp3 b/forge-gui/res/adventure/music/boss/boss1.mp3 new file mode 100644 index 00000000000..75df8af1a52 Binary files /dev/null and b/forge-gui/res/adventure/music/boss/boss1.mp3 differ diff --git a/forge-gui/res/adventure/music/boss/boss2.mp3 b/forge-gui/res/adventure/music/boss/boss2.mp3 new file mode 100644 index 00000000000..153079a2e57 Binary files /dev/null and b/forge-gui/res/adventure/music/boss/boss2.mp3 differ diff --git a/forge-gui/res/adventure/music/match/match1.mp3 b/forge-gui/res/adventure/music/match/match1.mp3 index c008420120a..1bd081b1278 100644 Binary files a/forge-gui/res/adventure/music/match/match1.mp3 and b/forge-gui/res/adventure/music/match/match1.mp3 differ diff --git a/forge-gui/res/adventure/music/match/match2.mp3 b/forge-gui/res/adventure/music/match/match2.mp3 index 8935336ba9a..b8442665226 100644 Binary files a/forge-gui/res/adventure/music/match/match2.mp3 and b/forge-gui/res/adventure/music/match/match2.mp3 differ diff --git a/forge-gui/res/adventure/music/match/match3.mp3 b/forge-gui/res/adventure/music/match/match3.mp3 index 6f832031214..466fce711e0 100644 Binary files a/forge-gui/res/adventure/music/match/match3.mp3 and b/forge-gui/res/adventure/music/match/match3.mp3 differ diff --git a/forge-gui/res/blockdata/blocks.txt b/forge-gui/res/blockdata/blocks.txt index 9ada9398861..0cf7a3ae807 100644 --- a/forge-gui/res/blockdata/blocks.txt +++ b/forge-gui/res/blockdata/blocks.txt @@ -119,3 +119,4 @@ Dominaria Remastered, 3/6/DMR, DMR Phyrexia: All Will Be One, 3/6/ONE, ONE Phyrexia: All Will Be One Jumpstart, -/2/ONE, Meta-Choose(S(ONE Mite-y 1)Mite-y 1;S(ONE Mite-y 2)Mite-y 2;S(ONE Progress 1)Progress 1;S(ONE Progress 2)Progress 2;S(ONE Corruption 1)Corruption 1;S(ONE Corruption 2)Corruption 2;S(ONE Rebellious 1)Rebellious 1;S(ONE Rebellious 2)Rebellious 2;S(ONE Toxic 1)Toxic 1;S(ONE Toxic 2)Toxic 2)Themes Alchemy: Phyrexia, 3/6/ONE, YONE +Shadows over Innistrad Remastered, 3/6/SIR, SIR diff --git a/forge-gui/res/cardsfolder/a/artillery_enthusiast.txt b/forge-gui/res/cardsfolder/a/artillery_enthusiast.txt index b9c2a21c66d..d793620cef5 100644 --- a/forge-gui/res/cardsfolder/a/artillery_enthusiast.txt +++ b/forge-gui/res/cardsfolder/a/artillery_enthusiast.txt @@ -4,7 +4,7 @@ Types:Creature Goblin Artificer PT:1/2 S:Mode$ Continuous | Affected$ Creature.modified+YouCtrl | AddKeyword$ Menace | Description$ Modified creatures you control have menace. T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigSeek | TriggerDescription$ When CARDNAME enters the battlefield, you may discard a card. If you do, seek a card with mana value equal to that card's mana value. -SVar:TrigSeek:AB$ ChangeZone | Cost$ Discard<1/Card> | Origin$ Library | Destination$ Hand | AtRandom$ True | NoShuffle$ True | Mandatory$ True | NoLooking$ True | NoReveal$ True | ChangeType$ Card.cmcEQX | ChangeNum$ 1 +SVar:TrigSeek:AB$ Seek | Cost$ Discard<1/Card> | Type$ Card.cmcEQX SVar:X:Discarded$CardManaCost DeckHas:Ability$Discard & Keyword$Menace DeckHints:Type$Equipment|Aura & Ability$Counters diff --git a/forge-gui/res/cardsfolder/b/back_alley_gardener.txt b/forge-gui/res/cardsfolder/b/back_alley_gardener.txt index 47ced49c724..b4cd36ba725 100644 --- a/forge-gui/res/cardsfolder/b/back_alley_gardener.txt +++ b/forge-gui/res/cardsfolder/b/back_alley_gardener.txt @@ -3,6 +3,8 @@ ManaCost:R G W Types:Creature Elf Druid PT:3/4 T:Mode$ ChangesZoneAll | ValidCards$ Creature.Other+YouCtrl | Destination$ Battlefield | TriggerZones$ Battlefield | ActivationLimit$ 1 | Execute$ TrigSeek | TriggerDescription$ Alliance — Whenever one or more other creatures enter the battlefield under your control, seek a land card, then put it onto the battlefield tapped. This ability triggers only once each turn. -SVar:TrigSeek:DB$ ChangeZone | Origin$ Library | Destination$ Battlefield | AtRandom$ True | NoShuffle$ True | Mandatory$ True | NoLooking$ True | NoReveal$ True | ChangeType$ Land | ChangeNum$ 1 | Tapped$ True +SVar:TrigSeek:DB$ Seek | Type$ Land | RememberFound$ True | SubAbility$ DBPut +SVar:DBPut:DB$ ChangeZone | Origin$ Hand | Destination$ Battlefield | Defined$ Remembered | Tapped$ True | SubAbility$ DBCleanup +SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True SVar:BuffedBy:Creature Oracle:Alliance — Whenever one or more other creatures enter the battlefield under your control, seek a land card, then put it onto the battlefield tapped. This ability triggers only once each turn. diff --git a/forge-gui/res/cardsfolder/b/bounty_of_the_deep.txt b/forge-gui/res/cardsfolder/b/bounty_of_the_deep.txt index 2ab88fd98f3..52dcc846b62 100644 --- a/forge-gui/res/cardsfolder/b/bounty_of_the_deep.txt +++ b/forge-gui/res/cardsfolder/b/bounty_of_the_deep.txt @@ -1,9 +1,8 @@ Name:Bounty of the Deep ManaCost:2 U Types:Sorcery -A:SP$ Branch | BranchConditionSVar$ X | BranchConditionSVarCompare$ GE1 | TrueSubAbility$ Seek2NonLand | FalseSubAbility$ Seek1Land | StackDescription$ SpellDescription | SpellDescription$ If you have no land cards in your hand, seek a land card and a nonland card. Otherwise, seek two nonland cards. -SVar:Seek1Land:DB$ ChangeZone | Origin$ Library | Destination$ Hand | AtRandom$ True | NoShuffle$ True | Mandatory$ True | NoLooking$ True | NoReveal$ True | ChangeType$ Card.Land | ChangeNum$ 1 | SubAbility$ Seek1NonLand -SVar:Seek1NonLand:DB$ ChangeZone | Origin$ Library | Destination$ Hand | AtRandom$ True | NoShuffle$ True | Mandatory$ True | NoLooking$ True | NoReveal$ True | ChangeType$ Card.nonLand | ChangeNum$ 1 -SVar:Seek2NonLand:DB$ ChangeZone | Origin$ Library | Destination$ Hand | AtRandom$ True | NoShuffle$ True | Mandatory$ True | NoLooking$ True | NoReveal$ True | ChangeType$ Card.nonLand | ChangeNum$ 2 +A:SP$ Branch | BranchConditionSVar$ X | BranchConditionSVarCompare$ GE1 | TrueSubAbility$ Seek2 | FalseSubAbility$ Seek1 | StackDescription$ SpellDescription | SpellDescription$ If you have no land cards in your hand, seek a land card and a nonland card. Otherwise, seek two nonland cards. +SVar:Seek1:DB$ Seek | Types$ Card.Land,Card.nonLand +SVar:Seek2:DB$ Seek | Type$ Card.nonLand | Num$ 2 SVar:X:Count$ValidHand Land.YouCtrl Oracle:If you have no land cards in your hand, seek a land card and a nonland card. Otherwise, seek two nonland cards. diff --git a/forge-gui/res/cardsfolder/c/cabaretti_revels.txt b/forge-gui/res/cardsfolder/c/cabaretti_revels.txt index aada0a675a4..c6ca583db19 100644 --- a/forge-gui/res/cardsfolder/c/cabaretti_revels.txt +++ b/forge-gui/res/cardsfolder/c/cabaretti_revels.txt @@ -2,7 +2,9 @@ Name:Cabaretti Revels ManaCost:R R G Types:Enchantment T:Mode$ SpellCast | ValidCard$ Creature | ValidActivatingPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigSeek | TriggerDescription$ Whenever you cast a creature spell, seek a creature card with lesser mana value, then put it onto the battlefield. -SVar:TrigSeek:DB$ ChangeZone | Origin$ Library | Destination$ Battlefield | AtRandom$ True | NoShuffle$ True | Mandatory$ True | NoLooking$ True | NoReveal$ True | ChangeNum$ 1 | ChangeType$ Creature.cmcLTX +SVar:TrigSeek:DB$ Seek | Type$ Creature.cmcLTX | RememberFound$ True | SubAbility$ DBPut +SVar:DBPut:DB$ ChangeZone | Origin$ Hand | Destination$ Battlefield | Defined$ Remembered | SubAbility$ DBCleanup +SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True SVar:X:TriggeredCard$CardManaCost SVar:BuffedBy:Creature Oracle:Whenever you cast a creature spell, seek a creature card with lesser mana value, then put it onto the battlefield. diff --git a/forge-gui/res/cardsfolder/c/chaos_balor.txt b/forge-gui/res/cardsfolder/c/chaos_balor.txt index 36aaed72e2d..d114bbd77dc 100644 --- a/forge-gui/res/cardsfolder/c/chaos_balor.txt +++ b/forge-gui/res/cardsfolder/c/chaos_balor.txt @@ -5,9 +5,9 @@ PT:4/5 K:Flying T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigCharm | TriggerDescription$ Whenever CARDNAME attacks or dies, ABILITY T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigCharm | Secondary$ True | TriggerDescription$ Whenever CARDNAME attacks or dies, ABILITY -SVar:TrigCharm:DB$ Charm | CharmNum$ 2 | Choices$ DiscardSeek,DamageTreasures,DamagePump | AdditionalDescription$ Each mode must target a different player. -SVar:DiscardSeek:DB$ Discard | ValidTgts$ Player | TargetUnique$ True | TgtPrompt$ Select target player to discard hand and seek | Mode$ Hand | RememberDiscarded$ True | SubAbility$ DBSeek | SpellDescription$ Target player discards all cards in their hand, then seeks that many nonland cards. -SVar:DBSeek:DB$ ChangeZone | Defined$ ParentTarget | Origin$ Library | Destination$ Hand | AtRandom$ True | NoShuffle$ True | Mandatory$ True | NoLooking$ True | NoReveal$ True | ChangeNum$ X | ChangeType$ Card.nonLand | SubAbility$ DBCleanup +SVar:TrigCharm:DB$ Charm | CharmNum$ 2 | Choices$ DiscardSeek,DamageTreasures,DamagePump | AdditionalDescription$ . Each mode must target a different player. +SVar:DiscardSeek:DB$ Discard | ValidTgts$ Player | TargetUnique$ True | Mode$ Hand | RememberDiscarded$ True | SubAbility$ DBSeek | SpellDescription$ Target player discards all cards in their hand, then seeks that many nonland cards. +SVar:DBSeek:DB$ Seek | Defined$ Targeted | Num$ X | Type$ Card.nonLand | SubAbility$ DBCleanup SVar:DamageTreasures:DB$ DealDamage | ValidTgts$ Player | TargetUnique$ True | TgtPrompt$ Select target player to take 2 damage and create two Treasures | NumDmg$ 2 | SubAbility$ DBToken | SpellDescription$ CARDNAME deals 2 damage to target player and they create two Treasure tokens. SVar:DBToken:DB$ Token | TokenScript$ c_a_treasure_sac | TokenAmount$ 2 | TokenOwner$ ParentTarget SVar:DamagePump:DB$ DamageAll | ValidTgts$ Player | TargetUnique$ True | NumDmg$ 2 | RememberDamaged$ True | ValidCards$ Creature | ValidDescription$ each creature target player controls. | SubAbility$ DBEffect | SpellDescription$ CARDNAME deals 2 damage to each creature target player controls. Those creatures perpetually get +2/+0. diff --git a/forge-gui/res/cardsfolder/c/choice_of_fortunes.txt b/forge-gui/res/cardsfolder/c/choice_of_fortunes.txt index d6d6d99ce6d..63a03e894b9 100644 --- a/forge-gui/res/cardsfolder/c/choice_of_fortunes.txt +++ b/forge-gui/res/cardsfolder/c/choice_of_fortunes.txt @@ -1,9 +1,9 @@ Name:Choice of Fortunes ManaCost:2 U Types:Sorcery -A:SP$ ChangeZone | Origin$ Library | Destination$ Hand | AtRandom$ True | NoShuffle$ True | Mandatory$ True | NoLooking$ True | NoReveal$ True | ChangeType$ Card | ChangeNum$ 2 | RememberChanged$ True | SubAbility$ DBShuffle | StackDescription$ SpellDescription | SpellDescription$ Seek two cards. +A:SP$ Seek | Num$ 2 | RememberFound$ True | SubAbility$ DBShuffle | SpellDescription$ Seek two cards. SVar:DBShuffle:DB$ ChangeZone | Optional$ True | Defined$ Remembered | Origin$ Hand | Destination$ Library | Shuffle$ True | ForgetChanged$ True | SubAbility$ DBSeek | StackDescription$ SpellDescription | SpellDescription$ You may shuffle them into your library. -SVar:DBSeek:DB$ ChangeZone | ConditionDefined$ Remembered | ConditionPresent$ Card | ConditionCompare$ EQ0 | Origin$ Library | Destination$ Hand | AtRandom$ True | NoShuffle$ True | Mandatory$ True | NoLooking$ True | NoReveal$ True | ChangeType$ Card | ChangeNum$ 2 | SubAbility$ DBCleanup | StackDescription$ SpellDescription | SpellDescription$ If you do, seek two cards. +SVar:DBSeek:DB$ Seek | ConditionDefined$ Remembered | ConditionPresent$ Card | ConditionCompare$ EQ0 | Num$ 2 | SubAbility$ DBCleanup | SpellDescription$ If you do, seek two cards. SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True | SubAbility$ DBEffect SVar:DBEffect:DB$ Effect | StaticAbilities$ STHandSize | Duration$ Permanent | SpellDescription$ You have no maximum hand size for the rest of the game. SVar:STHandSize:Mode$ Continuous | EffectZone$ Command | Affected$ You | SetMaxHandSize$ Unlimited | Description$ You have no maximum hand size for the rest of the game. diff --git a/forge-gui/res/cardsfolder/c/crucias_titan_of_the_waves.txt b/forge-gui/res/cardsfolder/c/crucias_titan_of_the_waves.txt index c591e6c6eb7..c8457f3e633 100644 --- a/forge-gui/res/cardsfolder/c/crucias_titan_of_the_waves.txt +++ b/forge-gui/res/cardsfolder/c/crucias_titan_of_the_waves.txt @@ -5,8 +5,8 @@ PT:3/3 T:Mode$ Phase | Phase$ End of Turn | OptionalDecider$ You | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigToken | TriggerDescription$ At the beginning of your end step, you may discard a card. If you do, create a Treasure token and choose ambitious or expedient. If you chose ambitious, seek a card with greater mana value than the discarded card. If you chose expedient, seek a card with lesser mana value than the discarded card. SVar:TrigToken:AB$ Token | Cost$ Discard<1/Card> | TokenScript$ c_a_treasure_sac | SubAbility$ DBChoose SVar:DBChoose:DB$ GenericChoice | Choices$ Ambitious,Expedient | Defined$ You | AILogic$ Random -SVar:Ambitious:DB$ ChangeZone | Origin$ Library | Destination$ Hand | AtRandom$ True | NoShuffle$ True | Mandatory$ True | NoLooking$ True | NoReveal$ True | ChangeType$ Card.cmcGTX | ChangeNum$ 1 | SpellDescription$ Ambitious - Seek a card with greater mana value than the discarded card. -SVar:Expedient:DB$ ChangeZone | Origin$ Library | Destination$ Hand | AtRandom$ True | NoShuffle$ True | Mandatory$ True | NoLooking$ True | NoReveal$ True | ChangeType$ Card.cmcLTX | ChangeNum$ 1 | SpellDescription$ Expedient - Seek a card with lesser mana value than the discarded card. +SVar:Ambitious:DB$ Seek | Type$ Card.cmcGTX | SpellDescription$ Ambitious - Seek a card with greater mana value than the discarded card. +SVar:Expedient:DB$ Seek | Type$ Card.cmcLTX | SpellDescription$ Expedient - Seek a card with lesser mana value than the discarded card. DeckHas:Ability$Sacrifice|Token|Discard & Type$Treasure|Artifact SVar:X:Discarded$CardManaCost Oracle:At the beginning of your end step, you may discard a card. If you do, create a Treasure token and choose ambitious or expedient. If you chose ambitious, seek a card with greater mana value than the discarded card. If you chose expedient, seek a card with lesser mana value than the discarded card. diff --git a/forge-gui/res/cardsfolder/d/darigaazs_whelp.txt b/forge-gui/res/cardsfolder/d/darigaazs_whelp.txt index f1bc1b38f12..385ed7efeb2 100644 --- a/forge-gui/res/cardsfolder/d/darigaazs_whelp.txt +++ b/forge-gui/res/cardsfolder/d/darigaazs_whelp.txt @@ -8,7 +8,7 @@ T:Mode$ Drawn | ValidCard$ Card.YouOwn+Dragon | TriggerZones$ Battlefield | Exec SVar:DBEffect:DB$ Effect | StaticAbilities$ PerpetualP1P1 | RememberObjects$ TriggeredCard | Name$ Darigaaz's Whelp's Perpetual Effect | Duration$ Permanent SVar:PerpetualP1P1:Mode$ Continuous | Affected$ Card.IsRemembered | AddPower$ 1 | AddToughness$ 1 | EffectZone$ Command | AffectedZone$ Battlefield,Hand,Graveyard,Exile,Stack,Library,Command | Description$ This card perpetually gets +1/+1. T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self+kicked | Execute$ TrigSeek | TriggerDescription$ When this creature enters the battlefield, if it was kicked, seek a Dragon card. CARDNAME and that Dragon card each perpetually get +1/+1. -SVar:TrigSeek:DB$ ChangeZone | RememberChanged$ True | Origin$ Library | Destination$ Hand | AtRandom$ True | NoShuffle$ True | Mandatory$ True | NoLooking$ True | NoReveal$ True | ChangeType$ Card.Dragon | SubAbility$ DBEffectBis +SVar:TrigSeek:DB$ Seek | RememberFound$ True | Type$ Card.Dragon | SubAbility$ DBEffectBis SVar:DBEffectBis:DB$ Effect | StaticAbilities$ PerpetualP1P1Bis | RememberObjects$ Remembered | Name$ Darigaaz's Whelp's Perpetual Effect | Duration$ Permanent | SubAbility$ DBCleanup SVar:PerpetualP1P1Bis:Mode$ Continuous | Affected$ Card.IsRemembered,Card.EffectSource | AddPower$ 1 | AddToughness$ 1 | EffectZone$ Command | AffectedZone$ Battlefield,Hand,Graveyard,Exile,Stack,Library,Command | Description$ CARDNAME and the conjured Dragon card each perpetually get +1/+1. SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True diff --git a/forge-gui/res/cardsfolder/d/diviner_of_fates.txt b/forge-gui/res/cardsfolder/d/diviner_of_fates.txt index 9e20ef971f6..e923d4009b5 100644 --- a/forge-gui/res/cardsfolder/d/diviner_of_fates.txt +++ b/forge-gui/res/cardsfolder/d/diviner_of_fates.txt @@ -5,6 +5,6 @@ PT:2/1 T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigConnive | TriggerDescription$ When CARDNAME enters the battlefield, it connives. (Draw a card, then discard a card. If you discarded a nonland card, put a +1/+1 counter on this creature.) SVar:TrigConnive:DB$ Connive T:Mode$ DiscardedAll | ValidPlayer$ You | ValidCard$ Card | TriggerZones$ Battlefield | Execute$ TrigSeek | ActivationLimit$ 1 | TriggerDescription$ Whenever you discard one or more cards, seek a card that shares a card type with one of the discarded cards. This ability triggers only once each turn. -SVar:TrigSeek:DB$ ChangeZone | Origin$ Library | Destination$ Hand | AtRandom$ True | NoShuffle$ True | Mandatory$ True | NoLooking$ True | NoReveal$ True | ChangeType$ Card.sharesCardTypeWith TriggeredCards | ChangeNum$ 1 +SVar:TrigSeek:DB$ Seek | Type$ Card.sharesCardTypeWith TriggeredCards DeckHas:Ability$Discard|Counters Oracle:When Diviner of Fates enters the battlefield, it connives.\nWhenever you discard one or more cards, seek a card that shares a card type with one of the discarded cards. This ability triggers only once each turn. diff --git a/forge-gui/res/cardsfolder/f/faceless_agent.txt b/forge-gui/res/cardsfolder/f/faceless_agent.txt index 0176922a7ca..fcf085d3150 100644 --- a/forge-gui/res/cardsfolder/f/faceless_agent.txt +++ b/forge-gui/res/cardsfolder/f/faceless_agent.txt @@ -4,5 +4,5 @@ Types:Creature Shapeshifter PT:2/2 K:Changeling T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigSeek | TriggerDescription$ When CARDNAME enters the battlefield, seek a creature card of the most prevalent creature type in your library. -SVar:TrigSeek:DB$ ChangeZone | Origin$ Library | Destination$ Hand | AtRandom$ True | NoShuffle$ True | Mandatory$ True | NoLooking$ True | NoReveal$ True | ChangeType$ Card.Creature+MostProminentCreatureTypeInLibrary | ChangeNum$ 1 +SVar:TrigSeek:DB$ Seek | Type$ Card.Creature+MostProminentCreatureTypeInLibrary Oracle:Changeling\nWhen Faceless Agent enters the battlefield, seek a creature card of the most prevalent creature type in your library. diff --git a/forge-gui/res/cardsfolder/f/faith_unbroken.txt b/forge-gui/res/cardsfolder/f/faith_unbroken.txt index e21c64c5914..8a62039a5a6 100644 --- a/forge-gui/res/cardsfolder/f/faith_unbroken.txt +++ b/forge-gui/res/cardsfolder/f/faith_unbroken.txt @@ -2,7 +2,7 @@ Name:Faith Unbroken ManaCost:3 W Types:Enchantment Aura K:Enchant creature you control -A:SP$ Attach | Cost$ 3 W | ValidTgts$ Creature | AILogic$ Pump +A:SP$ Attach | Cost$ 3 W | ValidTgts$ Creature.YouCtrl | AILogic$ Pump T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigExile | TriggerDescription$ When CARDNAME enters the battlefield, exile target creature an opponent controls until CARDNAME leaves the battlefield. SVar:TrigExile:DB$ ChangeZone | Origin$ Battlefield | Destination$ Exile | ValidTgts$ Creature.OppCtrl | TgtPrompt$ Select target creature an opponent controls | Duration$ UntilHostLeavesPlay SVar:PlayMain1:TRUE diff --git a/forge-gui/res/cardsfolder/f/frenzied_geistblaster.txt b/forge-gui/res/cardsfolder/f/frenzied_geistblaster.txt index c8fe1a00c19..b3382b76048 100644 --- a/forge-gui/res/cardsfolder/f/frenzied_geistblaster.txt +++ b/forge-gui/res/cardsfolder/f/frenzied_geistblaster.txt @@ -3,10 +3,9 @@ ManaCost:1 R Types:Creature Human Wizard PT:2/2 K:Prowess -T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | CheckSVar$ Z | SVarCompare$ GE20 | Execute$ TrigSeek | TriggerDescription$ When CARDNAME enters the battlefield, if there are twenty or more instant and/or sorcery cards among cards in your graveyard, hand, and library, you may discard a card. If you do, seek an instant or sorcery card. -SVar:TrigSeek:AB$ ChangeZone | Cost$ Discard<1/Card> | Origin$ Library | Destination$ Hand | AtRandom$ True | NoShuffle$ True | NoLooking$ True | NoReveal$ True | ChangeNum$ 1 | ChangeType$ Instant,Sorcery -SVar:X:Count$ValidGraveyard Instant.YouOwn,Sorcery.YouOwn -SVar:Y:Count$ValidLibrary Instant.YouOwn,Sorcery.YouOwn/Plus.X -SVar:Z:Count$ValidHand Instant.YouOwn,Sorcery.YouOwn/Plus.Y +T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | CheckSVar$ X | SVarCompare$ GE20 | Execute$ TrigSeek | TriggerDescription$ When CARDNAME enters the battlefield, if there are twenty or more instant and/or sorcery cards among cards in your graveyard, hand, and library, you may discard a card. If you do, seek an instant or sorcery card. +SVar:TrigSeek:AB$ Seek | Cost$ Discard<1/Card> | Type$ Instant,Sorcery +SVar:X:Count$ValidGraveyard,Library,Hand Instant.YouOwn,Sorcery.YouOwn DeckNeeds:Type$Instant|Sorcery +DeckHas:Ability$Discard Oracle:When Frenzied Geistblaster enters the battlefield, if there are twenty or more instant and/or sorcery cards among cards in your graveyard, hand, and library, you may discard a card. If you do, seek an instant or sorcery card. diff --git a/forge-gui/res/cardsfolder/f/freyalise_skyshroud_partisan.txt b/forge-gui/res/cardsfolder/f/freyalise_skyshroud_partisan.txt index 10b59c94cee..519629b03b8 100644 --- a/forge-gui/res/cardsfolder/f/freyalise_skyshroud_partisan.txt +++ b/forge-gui/res/cardsfolder/f/freyalise_skyshroud_partisan.txt @@ -7,7 +7,7 @@ SVar:DBRandom:DB$ ChooseCard | Defined$ You | Choices$ Elf.YouOwn | ChoiceZone$ SVar:DBEffect:DB$ Effect | RememberObjects$ Targeted | StaticAbilities$ PerpetualP1P1 | Name$ Freyalise, Skyshroud Partisan's Perpetual Effect | Duration$ Permanent | SubAbility$ DBCleanup SVar:PerpetualP1P1:Mode$ Continuous | Affected$ Card.IsRemembered,Card.ChosenCard | AddPower$ 1 | AddToughness$ 1 | EffectZone$ Command | AffectedZone$ Battlefield,Hand,Graveyard,Exile,Stack,Library,Command | Description$ The target Elf and randomly chosen card perpetually get +1/+1. SVar:DBCleanup:DB$ Cleanup | ClearChosenCard$ True -A:AB$ ChangeZone | Cost$ SubCounter<1/LOYALTY> | Planeswalker$ True | Origin$ Library | Destination$ Hand | AtRandom$ True | NoShuffle$ True | Mandatory$ True | NoLooking$ True | NoReveal$ True | ChangeType$ Card.Elf | ChangeNum$ 1 | StackDescription$ SpellDescription | SpellDescription$ Seek an Elf card. +A:AB$ Seek | Cost$ SubCounter<1/LOYALTY> | Planeswalker$ True | Type$ Card.Elf | StackDescription$ REP Seek_{p:You} seeks | SpellDescription$ Seek an Elf card. A:AB$ MakeCard | Conjure$ True | Cost$ SubCounter<6/LOYALTY> | Planeswalker$ True | Ultimate$ True | Name$ Regal Force | Zone$ Battlefield | SpellDescription$ Conjure a Regal Force card onto the battlefield. DeckNeeds:Type$Elf Oracle:[+1]: Choose up to one target Elf. Untap it. It and a random Elf creature card in your hand each perpetually gets +1/+1.\n[-1]: Seek an Elf card.\n[-6]: Conjure a Regal Force card onto the battlefield. diff --git a/forge-gui/res/cardsfolder/g/gate_of_the_black_dragon.txt b/forge-gui/res/cardsfolder/g/gate_of_the_black_dragon.txt index d21a5cad9f5..fea1821811f 100644 --- a/forge-gui/res/cardsfolder/g/gate_of_the_black_dragon.txt +++ b/forge-gui/res/cardsfolder/g/gate_of_the_black_dragon.txt @@ -2,7 +2,7 @@ Name:Gate of the Black Dragon ManaCost:no cost Types:Land Swamp Gate K:CARDNAME enters the battlefield tapped. -A:AB$ ChangeZone | Cost$ 3 B T | Origin$ Library | Destination$ Hand | AtRandom$ True | NoShuffle$ True | Mandatory$ True | NoLooking$ True | NoReveal$ True | ChangeNum$ 1 | ChangeType$ Card.nonLand | GameActivationLimit$ 1 | StackDescription$ SpellDescription | SpellDescription$ Seek a nonland card. Activate only once. +A:AB$ Seek | Cost$ 3 B T | Type$ Card.nonLand | GameActivationLimit$ 1 | StackDescription$ {p:You} seeks a nonland card. | SpellDescription$ Seek a nonland card. Activate only once. Text:{T}: Add {B}. DeckHints:Type$Gate Oracle:Gate of the Black Dragon enters the battlefield tapped.\n{3}{B}, {T}: Seek a nonland card. Activate only once.\n{T}: Add {B}. diff --git a/forge-gui/res/cardsfolder/g/gate_to_manorborn.txt b/forge-gui/res/cardsfolder/g/gate_to_manorborn.txt index e490a6a0690..51425c00e89 100644 --- a/forge-gui/res/cardsfolder/g/gate_to_manorborn.txt +++ b/forge-gui/res/cardsfolder/g/gate_to_manorborn.txt @@ -2,7 +2,7 @@ Name:Gate to Manorborn ManaCost:no cost Types:Land Forest Gate K:CARDNAME enters the battlefield tapped. -A:AB$ ChangeZone | Cost$ 3 G T | Origin$ Library | Destination$ Hand | AtRandom$ True | NoShuffle$ True | Mandatory$ True | NoLooking$ True | NoReveal$ True | ChangeNum$ 1 | ChangeType$ Card.nonLand | GameActivationLimit$ 1 | StackDescription$ SpellDescription | SpellDescription$ Seek a nonland card. Activate only once. +A:AB$ Seek | Cost$ 3 G T | Type$ Card.nonLand | GameActivationLimit$ 1 | StackDescription$ {p:You} seeks a nonland card. | SpellDescription$ Seek a nonland card. Activate only once. Text:{T}: Add {G}. DeckHints:Type$Gate Oracle:Gate to Manorborn enters the battlefield tapped.\n{3}{G}, {T}: Seek a nonland card. Activate only once.\n{T}: Add {G}. diff --git a/forge-gui/res/cardsfolder/g/gate_to_seatower.txt b/forge-gui/res/cardsfolder/g/gate_to_seatower.txt index a0a33c0ec23..b6046d7e99f 100644 --- a/forge-gui/res/cardsfolder/g/gate_to_seatower.txt +++ b/forge-gui/res/cardsfolder/g/gate_to_seatower.txt @@ -2,7 +2,7 @@ Name:Gate to Seatower ManaCost:no cost Types:Land Island Gate K:CARDNAME enters the battlefield tapped. -A:AB$ ChangeZone | Cost$ 3 U T | Origin$ Library | Destination$ Hand | AtRandom$ True | NoShuffle$ True | Mandatory$ True | NoLooking$ True | NoReveal$ True | ChangeNum$ 1 | ChangeType$ Card.nonLand | GameActivationLimit$ 1 | StackDescription$ SpellDescription | SpellDescription$ Seek a nonland card. Activate only once. +A:AB$ Seek | Cost$ 3 U T | Type$ Card.nonLand | GameActivationLimit$ 1 | StackDescription$ {p:You} seeks a nonland card. | SpellDescription$ Seek a nonland card. Activate only once. Text:{T}: Add {U}. DeckHints:Type$Gate Oracle:Gate to Seatower enters the battlefield tapped.\n{3}{U}, {T}: Seek a nonland card. Activate only once.\n{T}: Add {U}. diff --git a/forge-gui/res/cardsfolder/g/gate_to_the_citadel.txt b/forge-gui/res/cardsfolder/g/gate_to_the_citadel.txt index 22319bdaf45..a95e8124bf7 100644 --- a/forge-gui/res/cardsfolder/g/gate_to_the_citadel.txt +++ b/forge-gui/res/cardsfolder/g/gate_to_the_citadel.txt @@ -2,7 +2,7 @@ Name:Gate to the Citadel ManaCost:no cost Types:Land Plains Gate K:CARDNAME enters the battlefield tapped. -A:AB$ ChangeZone | Cost$ 3 W T | Origin$ Library | Destination$ Hand | AtRandom$ True | NoShuffle$ True | Mandatory$ True | NoLooking$ True | NoReveal$ True | ChangeNum$ 1 | ChangeType$ Card.nonLand | GameActivationLimit$ 1 | StackDescription$ SpellDescription | SpellDescription$ Seek a nonland card. Activate only once. +A:AB$ Seek | Cost$ 3 W T | Type$ Card.nonLand | GameActivationLimit$ 1 | StackDescription$ {p:You} seeks a nonland card. | SpellDescription$ Seek a nonland card. Activate only once. Text:{T}: Add {W}. DeckHints:Type$Gate Oracle:Gate to the Citadel enters the battlefield tapped.\n{3}{W}, {T}: Seek a nonland card. Activate only once.\n{T}: Add {W}. diff --git a/forge-gui/res/cardsfolder/g/gate_to_tumbledown.txt b/forge-gui/res/cardsfolder/g/gate_to_tumbledown.txt index 60c3065c7b3..879cfe74bb9 100644 --- a/forge-gui/res/cardsfolder/g/gate_to_tumbledown.txt +++ b/forge-gui/res/cardsfolder/g/gate_to_tumbledown.txt @@ -2,7 +2,7 @@ Name:Gate to Tumbledown ManaCost:no cost Types:Land Mountain Gate K:CARDNAME enters the battlefield tapped. -A:AB$ ChangeZone | Cost$ 3 R T | Origin$ Library | Destination$ Hand | AtRandom$ True | NoShuffle$ True | Mandatory$ True | NoLooking$ True | NoReveal$ True | ChangeNum$ 1 | ChangeType$ Card.nonLand | GameActivationLimit$ 1 | StackDescription$ SpellDescription | SpellDescription$ Seek a nonland card. Activate only once. +A:AB$ Seek | Cost$ 3 R T | Type$ Card.nonLand | GameActivationLimit$ 1 | StackDescription$ {p:You} seeks a nonland card. | SpellDescription$ Seek a nonland card. Activate only once. Text:{T}: Add {R}. DeckHints:Type$Gate Oracle:Gate to Tumbledown enters the battlefield tapped.\n{3}{R}, {T}: Seek a nonland card. Activate only once.\n{T}: Add {R}. diff --git a/forge-gui/res/cardsfolder/g/geistpack_alpha.txt b/forge-gui/res/cardsfolder/g/geistpack_alpha.txt index c3a8bb214b0..8c17749238c 100644 --- a/forge-gui/res/cardsfolder/g/geistpack_alpha.txt +++ b/forge-gui/res/cardsfolder/g/geistpack_alpha.txt @@ -4,7 +4,7 @@ Types:Creature Wolf PT:5/4 K:Trample T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigSeek | TriggerDescription$ When CARDNAME dies, seek a permanent card with mana value equal to the number of lands you control. -SVar:TrigSeek:DB$ ChangeZone | Origin$ Library | Destination$ Hand | AtRandom$ True | NoShuffle$ True | Mandatory$ True | NoLooking$ True | NoReveal$ True | ChangeType$ Card.Permanent+cmcEQX | ChangeNum$ 1 +SVar:TrigSeek:DB$ Seek | Type$ Card.Permanent+cmcEQX SVar:X:Count$Valid Land.YouCtrl SVar:NeedsToPlayVar:X GE4 SVar:BuffedBy:Land diff --git a/forge-gui/res/cardsfolder/g/ghitu_embercoiler.txt b/forge-gui/res/cardsfolder/g/ghitu_embercoiler.txt index 0949ee38930..14b47abef50 100644 --- a/forge-gui/res/cardsfolder/g/ghitu_embercoiler.txt +++ b/forge-gui/res/cardsfolder/g/ghitu_embercoiler.txt @@ -4,8 +4,9 @@ Types:Creature Human Wizard PT:2/2 K:Prowess T:Mode$ Phase | Phase$ Main1 | PreCombatMain$ True | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigSeek | TriggerDescription$ At the beginning of your precombat main phase, you may discard a card. If you do, seek a card with greater mana value and exile it. Until the end of your next turn, you may play the exiled card. -SVar:TrigSeek:AB$ ChangeZone | Cost$ Discard<1/Card> | Origin$ Library | Destination$ Exile | AtRandom$ True | NoShuffle$ True | Mandatory$ True | NoLooking$ True | NoReveal$ True | ChangeType$ Card.cmcGTX | ChangeNum$ 1 | RememberChanged$ True | SubAbility$ DBEffect +SVar:TrigSeek:AB$ Seek | Cost$ Discard<1/Card> | Type$ Card.cmcGTX | RememberFound$ True | SubAbility$ DBExile SVar:X:Discarded$CardManaCost +SVar:DBExile:DB$ ChangeZone | Origin$ Hand | Destination$ Exile | Defined$ Remembered | SubAbility$ DBEffect SVar:DBEffect:DB$ Effect | RememberObjects$ Remembered | StaticAbilities$ MayPlay | Duration$ UntilTheEndOfYourNextTurn | ForgetOnMoved$ Exile | SubAbility$ DBCleanup SVar:MayPlay:Mode$ Continuous | Affected$ Card.IsRemembered | MayPlay$ True | EffectZone$ Command | AffectedZone$ Exile | Description$ Until the end of your next turn, you may play the exiled card. SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True diff --git a/forge-gui/res/cardsfolder/g/gitrog_horror_of_zhava.txt b/forge-gui/res/cardsfolder/g/gitrog_horror_of_zhava.txt index 1d5b0f1adb3..155e1f3b6eb 100644 --- a/forge-gui/res/cardsfolder/g/gitrog_horror_of_zhava.txt +++ b/forge-gui/res/cardsfolder/g/gitrog_horror_of_zhava.txt @@ -4,11 +4,13 @@ Types:Legendary Creature Frog Horror PT:6/6 K:Menace T:Mode$ Phase | Phase$ BeginCombat | TriggerZones$ Battlefield | Execute$ TrigSac | IsPresent$ Card.Self+untapped | TriggerDescription$ At the beginning of each combat, if CARDNAME is untapped, any opponent may sacrifice a nontoken creature. If they do, tap CARDNAME, then seek a land card and put it onto the battlefield tapped. -SVar:TrigSac:DB$ Sacrifice | Defined$ Opponent | Amount$ 1 | SacValid$ Creature.nonToken | RememberSacrificed$ True | Optional$ True | AILogic$ DesecrationDemon | SubAbility$ DBTap -SVar:DBTap:DB$ Tap | Defined$ Self | ConditionCheckSVar$ X | ConditionSVarCompare$ GE1 | SubAbility$ DBSeek -SVar:DBSeek:DB$ ChangeZone | Origin$ Library | Destination$ Battlefield | AtRandom$ True | NoShuffle$ True | Mandatory$ True | NoLooking$ True | NoReveal$ True | ChangeType$ Land | ChangeNum$ 1 | ConditionCheckSVar$ X | ConditionSVarCompare$ GE1 | SubAbility$ DBCleanup -SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True +SVar:TrigSac:DB$ Sacrifice | Defined$ Opponent | Amount$ 1 | SacValid$ Creature.nonToken | RememberSacrificed$ True | Optional$ True | AILogic$ DesecrationDemon | SubAbility$ DBBranch +SVar:DBBranch:DB$ Branch | BranchConditionSVar$ X | TrueSubAbility$ DBTap SVar:X:Remembered$Amount +SVar:DBTap:DB$ Tap | SubAbility$ DBSeek +SVar:DBSeek:DB$ Seek | Type$ Card.Land | ImprintFound$ True | SubAbility$ DBPut +SVar:DBPut:DB$ ChangeZone | Origin$ Hand | Destination$ Battlefield | Defined$ Imprinted | Tapped$ True | SubAbility$ DBCleanup +SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True | ClearImprinted$ True T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Land.YouCtrl | TriggerZones$ Battlefield | Execute$ TrigEffect | TriggerDescription$ Whenever a land enters the battlefield under your control, it perpetually gains "{B}{G}, {T}, Sacrifice this land: Draw a card." SVar:TrigEffect:DB$ Effect | RememberObjects$ TriggeredCard | StaticAbilities$ PerpetualStatic | Name$ Gitrog, Horror of Zhava's Perpetual Effect | Duration$ Permanent | SubAbility$ DBCleanup SVar:PerpetualStatic:Mode$ Continuous | Affected$ Card.IsRemembered | AddAbility$ PerpetualSacDraw | EffectZone$ All | Description$ This land card perpetually gains "{B}{G}, {T}, Sacrifice this land: Draw a card." diff --git a/forge-gui/res/cardsfolder/g/goblin_trapfinder.txt b/forge-gui/res/cardsfolder/g/goblin_trapfinder.txt index 4219a54d504..d04ac152795 100644 --- a/forge-gui/res/cardsfolder/g/goblin_trapfinder.txt +++ b/forge-gui/res/cardsfolder/g/goblin_trapfinder.txt @@ -3,7 +3,7 @@ ManaCost:R Types:Creature Goblin PT:1/1 T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | TriggerZones$ Battlefield | Execute$ DBSeek | TriggerDescription$ When CARDNAME dies, seek a creature card with mana value 3 or less. That card perpetually gains haste, "This spell costs {1} less to cast," and "At the beginning of your end step, sacrifice this creature." -SVar:DBSeek:DB$ ChangeZone | Origin$ Library | Destination$ Hand | AtRandom$ True | NoShuffle$ True | NoLooking$ True | NoReveal$ True | ChangeNum$ 1 | ChangeType$ Creature.cmcLE3+YouOwn | RememberChanged$ True | SubAbility$ DBEffect +SVar:DBSeek:DB$ Seek | Type$ Creature.cmcLE3+YouOwn | RememberFound$ True | SubAbility$ DBEffect SVar:DBEffect:DB$ Effect | StaticAbilities$ PerpetualAbility | RememberObjects$ Remembered | Triggers$ Update | Name$ Goblin Trapfinder's Perpetual Effect | Duration$ Permanent SVar:PerpetualAbility:Mode$ Continuous | Affected$ Card.IsRemembered | AddTrigger$ TrigSac | AddStaticAbility$ PerpetualReduceCost | AddKeyword$ Haste | EffectZone$ Command | AffectedZone$ Battlefield,Hand,Graveyard,Exile,Stack,Library,Command | Description$ This card perpetually gains haste, "This spell costs {1} less to cast," and "At the beginning of your end step, sacrifice this creature." SVar:PerpetualReduceCost:Mode$ ReduceCost | ValidCard$ Card.Self | Type$ Spell | Amount$ 1 | EffectZone$ All | Description$ This spell costs {1} less to cast. diff --git a/forge-gui/res/cardsfolder/h/hollowhenge_wrangler.txt b/forge-gui/res/cardsfolder/h/hollowhenge_wrangler.txt index 89c7e495279..fbfe5a67c0f 100644 --- a/forge-gui/res/cardsfolder/h/hollowhenge_wrangler.txt +++ b/forge-gui/res/cardsfolder/h/hollowhenge_wrangler.txt @@ -3,6 +3,7 @@ ManaCost:3 G G Types:Creature Elemental PT:6/6 T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigSeek | TriggerDescription$ When CARDNAME enters the battlefield, seek a land card. -SVar:TrigSeek:DB$ ChangeZone | Origin$ Library | Destination$ Hand | AtRandom$ True | NoShuffle$ True | Mandatory$ True | NoLooking$ True | NoReveal$ True | ChangeType$ Land | ChangeNum$ 1 +SVar:TrigSeek:DB$ Seek | Type$ Card.Land A:AB$ MakeCard | Cost$ Discard<1/Land/land> | Conjure$ True | Name$ Hollowhenge Beast | Zone$ Hand | AdditionalActivationZone$ Graveyard | StackDescription$ Conjure a card named Hollowhenge Beast into your hand. | SpellDescription$ Conjure a card named Hollowhenge Beast into your hand. You may also activate this ability while CARDNAME is in your graveyard. +DeckHas:Ability$Discard Oracle:When Hollowhenge Wrangler enters the battlefield, seek a land card.\nDiscard a land card: Conjure a card named Hollowhenge Beast into your hand. You may also activate this ability while Hollowhenge Wrangler is in your graveyard. diff --git a/forge-gui/res/cardsfolder/i/inquisitor_captain.txt b/forge-gui/res/cardsfolder/i/inquisitor_captain.txt index 0c4e1bcc5be..7de4999e5e8 100644 --- a/forge-gui/res/cardsfolder/i/inquisitor_captain.txt +++ b/forge-gui/res/cardsfolder/i/inquisitor_captain.txt @@ -3,13 +3,11 @@ ManaCost:3 W Types:Creature Human Cleric PT:3/3 K:Vigilance -T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.wasCast+Self | CheckSVar$ Z | SVarCompare$ GE20 | Execute$ TrigSeek | TriggerDescription$ When CARDNAME enters the battlefield, if you cast it and there are twenty or more creature cards with mana value 3 or less among cards in your graveyard, hand, and library, seek two creature cards with mana value 3 or less. Put one of them onto the battlefield and shuffle the other into your library. -SVar:TrigSeek:DB$ ChangeZone | Origin$ Library | Destination$ Library | AtRandom$ True | NoShuffle$ True | Mandatory$ True | NoLooking$ True | NoReveal$ True | ChangeType$ Creature.YouOwn+cmcLE3 | ChangeNum$ 2 | RememberChanged$ True | SubAbility$ DBChangeZone1 -SVar:DBChangeZone1:DB$ ChangeZone | Origin$ Library | Destination$ Battlefield | ChangeType$ Creature.IsRemembered | ChangeNum$ 1 | Mandatory$ True | NoLooking$ True | SelectPrompt$ Select a card for the battlefield | Shuffle$ True | SubAbility$ DBChangeZone2 | StackDescription$ None -SVar:DBChangeZone2:DB$ ChangeZone | Origin$ Library | Destination$ Library | ChangeType$ Creature.IsRemembered | Mandatory$ True | NoLooking$ True | StackDescription$ None | SubAbility$ DBCleanup +T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.wasCast+Self | CheckSVar$ X | SVarCompare$ GE20 | Execute$ TrigSeek | TriggerDescription$ When CARDNAME enters the battlefield, if you cast it and there are twenty or more creature cards with mana value 3 or less among cards in your graveyard, hand, and library, seek two creature cards with mana value 3 or less. Put one of them onto the battlefield and shuffle the other into your library. +SVar:TrigSeek:DB$ Seek | Type$ Creature.YouOwn+cmcLE3 | Num$ 2 | RememberFound$ True | SubAbility$ DBChangeZone1 +SVar:DBChangeZone1:DB$ ChangeZone | Origin$ Hand | Destination$ Battlefield | ChangeType$ Creature.IsRemembered | ChangeNum$ 1 | Mandatory$ True | SelectPrompt$ Select a card for the battlefield | SubAbility$ DBChangeZone2 +SVar:DBChangeZone2:DB$ ChangeZone | Origin$ Hand | Destination$ Library | ChangeType$ Creature.IsRemembered | Mandatory$ True | Shuffle$ True | SubAbility$ DBCleanup SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True -SVar:X:Count$ValidGraveyard Creature.YouOwn+cmcLE3 -SVar:Y:Count$ValidLibrary Creature.YouOwn+cmcLE3/Plus.X -SVar:Z:Count$ValidHand Creature.YouOwn+cmcLE3/Plus.Y +SVar:X:Count$ValidGraveyard,Library,Hand Creature.YouOwn+cmcLE3 DeckNeeds:Type$Creature Oracle:Vigilance\nWhen Inquisitor Captain enters the battlefield, if you cast it and there are twenty or more creature cards with mana value 3 or less among cards in your graveyard, hand, and library, seek two creature cards with mana value 3 or less. Put one of them onto the battlefield and shuffle the other into your library. diff --git a/forge-gui/res/cardsfolder/j/jukai_liberator.txt b/forge-gui/res/cardsfolder/j/jukai_liberator.txt index 5398a61c662..a29f8191224 100644 --- a/forge-gui/res/cardsfolder/j/jukai_liberator.txt +++ b/forge-gui/res/cardsfolder/j/jukai_liberator.txt @@ -5,6 +5,6 @@ PT:3/3 K:Ninjutsu:1 G T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | CombatDamage$ True | Execute$ TrigChoose | TriggerZones$ Battlefield | TriggerDescription$ Whenever CARDNAME deals combat damage to a player, choose land or nonland. Seek a permanent card of the chosen type. SVar:TrigChoose:DB$ ChooseType | Type$ Card | ValidTypes$ Land,Nonland | SubAbility$ DBSeek -SVar:DBSeek:DB$ ChangeZone | Origin$ Library | Destination$ Hand | AtRandom$ True | NoShuffle$ True | Mandatory$ True | NoLooking$ True | NoReveal$ True | ChangeType$ Card.ChosenType | ChangeNum$ 1 | SubAbility$ DBCleanup +SVar:DBSeek:DB$ Seek | Type$ Card.Permanent+ChosenType | SubAbility$ DBCleanup SVar:DBCleanup:DB$ Cleanup | ClearChosenType$ True Oracle:Ninjutsu {1}{G}\nWhenever Jukai Liberator deals combat damage to a player, choose land or nonland. Seek a permanent card of the chosen type. diff --git a/forge-gui/res/cardsfolder/k/kardum_patron_of_flames.txt b/forge-gui/res/cardsfolder/k/kardum_patron_of_flames.txt index db26d1521f5..3f7ab49125d 100644 --- a/forge-gui/res/cardsfolder/k/kardum_patron_of_flames.txt +++ b/forge-gui/res/cardsfolder/k/kardum_patron_of_flames.txt @@ -5,7 +5,9 @@ PT:4/3 K:Haste T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigCounter | TriggerZones$ Battlefield | TriggerDescription$ Whenever CARDNAME attacks, put a flame counter on it, then seek a card with mana value equal to the number of flame counters on it and exile that card face down. SVar:TrigCounter:DB$ PutCounter | CounterType$ FLAME | CounterNum$ 1 | ValidCards$ Self | SubAbility$ DBSeek -SVar:DBSeek:DB$ ChangeZone | Origin$ Library | Destination$ Exile | ExileFaceDown$ True | AtRandom$ True | NoShuffle$ True | NoLooking$ True | NoReveal$ True | ChangeNum$ 1 | ChangeType$ Card.cmcEQX+YouOwn | RememberChanged$ True +SVar:DBSeek:DB$ Seek | Type$ Card.cmcEQX+YouOwn | ImprintFound$ True | SubAbility$ DBExile +SVar:DBExile:DB$ ChangeZone | Origin$ Hand | Destination$ Exile | Defined$ Imprinted | ExileFaceDown$ True | Mandatory$ True | SubAbility$ DBClearImprinted +SVar:DBClearImprinted:DB$ Cleanup | ClearImprinted$ True T:Mode$ ChangesZone | ValidCard$ Card.Self | Origin$ Battlefield | Destination$ Graveyard | Execute$ TrigReturn | TriggerDescription$ When NICKNAME dies, put the cards exiled with it into their owner's hand. At the beginning of the end step of your next turn, discard those cards. SVar:TrigReturn:DB$ ChangeZoneAll | ChangeType$ Card.IsRemembered+ExiledWithSource | Origin$ Exile | Destination$ Hand | SubAbility$ DBDelay SVar:DBDelay:DB$ DelayedTrigger | DelayedTriggerDefinedPlayer$ You | Mode$ Phase | Phase$ End of Turn | Execute$ TrigDiscardExiled | RememberObjects$ Remembered | TriggerDescription$ At the beginning of the end step of your next turn, discard those cards. @@ -16,4 +18,5 @@ T:Mode$ ChangesZone | Origin$ Exile | Destination$ Any | Static$ True | ValidCar SVar:DBForget:DB$ Pump | ForgetObjects$ TriggeredCard SVar:X:Count$CardCounters.FLAME SVar:HasAttackEffect:TRUE +DeckHas:Ability$Discard Oracle:Haste\nWhenever Kardum, Patron of Flames attacks, put a flame counter on it, then seek a card with mana value equal to the number of flame counters on it and exile that card face down.\nWhen Kardum dies, put all cards you own exiled with it into your hand. At the beginning of the end step of your next turn, discard those cards. diff --git a/forge-gui/res/cardsfolder/k/karlach_raging_tiefling.txt b/forge-gui/res/cardsfolder/k/karlach_raging_tiefling.txt index cd6a3b01f5c..3124af2e097 100644 --- a/forge-gui/res/cardsfolder/k/karlach_raging_tiefling.txt +++ b/forge-gui/res/cardsfolder/k/karlach_raging_tiefling.txt @@ -39,7 +39,7 @@ SVar:TrigReturn:DB$ ChangeZone | Origin$ Graveyard | Destination$ Battlefield | SVar:DBEffect:DB$ Effect | RememberObjects$ TriggeredCard | StaticAbilities$ PerpetualStatic | Duration$ Permanent SVar:PerpetualStatic:Mode$ Continuous | Affected$ Card.IsRemembered | AddKeyword$ CARDNAME can't block. | EffectZone$ Command | AffectedZone$ Battlefield,Hand,Graveyard,Exile,Stack,Library,Command | Description$ It perpetually gains "This creature can't block." T:Mode$ Specializes | ValidCard$ Card.Self | Execute$ TrigSeek | TriggerDescription$ When this card specializes from any zone, seek an instant or sorcery card with mana value 3 or less. Until end of turn, you may cast that card without paying its mana cost. -SVar:TrigSeek:DB$ ChangeZone | Origin$ Library | Destination$ Hand | AtRandom$ True | NoShuffle$ True | NoLooking$ True | NoReveal$ True | ChangeNum$ 1 | ChangeType$ Instant.cmcLE3,Sorcery.cmcLE3 | RememberChanged$ True +SVar:TrigSeek:DB$ Seek | Type$ Instant.cmcLE3,Sorcery.cmcLE3 | RememberFound$ True | SubAbility$ DBEffect SVar:DBEffect:DB$ Effect | StaticAbilities$ MayPlay | RememberObjects$ Remembered | ForgetOnMoved$ Hand | SubAbility$ DBCleanup SVar:MayPlay:Mode$ Continuous | Affected$ Card.IsRemembered+nonLand | MayPlayWithoutManaCost$ True | EffectZone$ Command | AffectedZone$ Hand SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True diff --git a/forge-gui/res/cardsfolder/k/kindred_denial.txt b/forge-gui/res/cardsfolder/k/kindred_denial.txt index 260bebf0617..cdce64e818f 100644 --- a/forge-gui/res/cardsfolder/k/kindred_denial.txt +++ b/forge-gui/res/cardsfolder/k/kindred_denial.txt @@ -2,6 +2,6 @@ Name:Kindred Denial ManaCost:2 U U Types:Instant A:SP$ Counter | TargetType$ Spell | ValidTgts$ Card | TgtPrompt$ Select target spell | RememberCounteredCMC$ True | SubAbility$ DBSeek | SpellDescription$ Counter target spell. -SVar:DBSeek:DB$ ChangeZone | Origin$ Library | Destination$ Hand | AtRandom$ True | NoShuffle$ True | Mandatory$ True | NoLooking$ True | NoReveal$ True | ChangeType$ Card.cmcEQX | ChangeNum$ 1 | StackDescription$ SpellDescription | SpellDescription$ Seek a card with the same mana value as that spell. +SVar:DBSeek:DB$ Seek | Type$ Card.cmcEQX | StackDescription$ REP Seek_{p:You} seeks | SpellDescription$ Seek a card with the same mana value as that spell. SVar:X:Count$RememberedNumber Oracle:Counter target spell. Seek a card with the same mana value as that spell. diff --git a/forge-gui/res/cardsfolder/k/klement_novice_acolyte.txt b/forge-gui/res/cardsfolder/k/klement_novice_acolyte.txt index 555650c8afa..7996b1846e3 100644 --- a/forge-gui/res/cardsfolder/k/klement_novice_acolyte.txt +++ b/forge-gui/res/cardsfolder/k/klement_novice_acolyte.txt @@ -36,10 +36,10 @@ Types:Legendary Creature Tiefling Cleric PT:3/4 K:Vigilance T:Mode$ Specializes | ValidCard$ Card.Self | Execute$ TrigSeek | TriggerDescription$ When this creature specializes, seek three nonland permanent cards. Choose one of those cards and shuffle the rest into your library. -SVar:TrigSeek:DB$ ChangeZone | Origin$ Library | Destination$ Hand | AtRandom$ True | NoShuffle$ True | Mandatory$ True | NoLooking$ True | NoReveal$ True | ChangeNum$ 3 | ChangeType$ Permanent.nonLand | RememberChanged$ True | SubAbility$ DBChooseCard +SVar:TrigSeek:DB$ Seek | Num$ 3 | ChangeType$ Card.Permanent+nonLand | RememberFound$ True | SubAbility$ DBChooseCard SVar:DBChooseCard:DB$ ChooseCard | ChoiceZone$ Hand | Choices$ Card.IsRemembered | ForgetChosen$ True | SubAbility$ DBShuffle -SVar:DBShuffle:DB$ ChangeZone | Origin$ Hand | Destination$ Library | Defined$ Remembered | Shuffle$ True | SubAbility$ DBClearChosen -SVar:DBClearChosen:DB$ Cleanup | ClearChosenCard$ True +SVar:DBShuffle:DB$ ChangeZone | Origin$ Hand | Destination$ Library | Defined$ Remembered | Shuffle$ True | SubAbility$ DBCleanup +SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True | ClearChosenCard$ True Oracle:Vigilance\nWhen this creature specializes, seek three nonland permanent cards. Choose one of those cards and shuffle the rest into your library. SPECIALIZE:BLACK diff --git a/forge-gui/res/cardsfolder/l/laezel_githyanki_warrior.txt b/forge-gui/res/cardsfolder/l/laezel_githyanki_warrior.txt index 4403fb253cf..041183334bb 100644 --- a/forge-gui/res/cardsfolder/l/laezel_githyanki_warrior.txt +++ b/forge-gui/res/cardsfolder/l/laezel_githyanki_warrior.txt @@ -22,7 +22,7 @@ PT:3/6 K:Double Strike T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigSeek | TriggerDescription$ When this creature enters the battlefield or specializes, seek a nonland permanent card with mana value 3 or less. T:Mode$ Specializes | ValidCard$ Card.Self | Execute$ TrigSeek | Secondary$ True | TriggerDescription$ When this creature enters the battlefield or specializes, seek a nonland permanent card with mana value 3 or less. -SVar:TrigSeek:DB$ ChangeZone | Origin$ Library | Destination$ Hand | AtRandom$ True | NoShuffle$ True | Mandatory$ True | NoLooking$ True | NoReveal$ True | ChangeType$ Permanent.nonLand+cmcLE3 +SVar:TrigSeek:DB$ Seek | Type$ Card.Permanent+nonLand+cmcLE3 Oracle:Double strike\nWhen this creature enters the battlefield or specializes, seek a nonland permanent card with mana value 3 or less. SPECIALIZE:BLUE diff --git a/forge-gui/res/cardsfolder/l/lukamina_moon_druid.txt b/forge-gui/res/cardsfolder/l/lukamina_moon_druid.txt index b8bcc8d1bb9..c44b863436c 100644 --- a/forge-gui/res/cardsfolder/l/lukamina_moon_druid.txt +++ b/forge-gui/res/cardsfolder/l/lukamina_moon_druid.txt @@ -4,7 +4,7 @@ Types:Legendary Creature Human Druid PT:2/2 K:Specialize:3:Wild Shape:Activate only if you control six or more lands.:IsPresent$ Land.YouCtrl | PresentCompare$ GE6 T:Mode$ ChangesZone | ValidCard$ Card.wasCastByYou+Self | Destination$ Battlefield | Execute$ TrigSeek | TriggerDescription$ When CARDNAME enters the battlefield, if you cast it, seek a land card with a basic land type. -SVar:TrigSeek:DB$ ChangeZone | Origin$ Library | Destination$ Hand | AtRandom$ True | NoShuffle$ True | Mandatory$ True | NoLooking$ True | NoReveal$ True | ChangeType$ Land.hasABasicLandType | ChangeNum$ 1 +SVar:TrigSeek:DB$ Seek | Type$ Land.hasABasicLandType AlternateMode:Specialize Oracle:Wild Shape — Specialize {3}. Activate only if you control six or more lands.\nWhen Lukamina, Moon Druid enters the battlefield, if you cast it, seek a land card with a basic land type. diff --git a/forge-gui/res/cardsfolder/n/norns_disassembly.txt b/forge-gui/res/cardsfolder/n/norns_disassembly.txt index 7506f1f00de..795c3f8fd9b 100644 --- a/forge-gui/res/cardsfolder/n/norns_disassembly.txt +++ b/forge-gui/res/cardsfolder/n/norns_disassembly.txt @@ -1,7 +1,7 @@ Name:Norn's Disassembly ManaCost:W Types:Enchantment -A:AB$ ChangeZone | Cost$ 1 W Sac<1/Permanent.Historic/Historic permanent> | Origin$ Library | Destination$ Hand | AtRandom$ True | NoShuffle$ True | Mandatory$ True | NoLooking$ True | NoReveal$ True | ChangeType$ Card.Historic | ChangeNum$ 1 | SpellDescription$ Seek a historic card. +A:AB$ Seek | Cost$ 1 W Sac<1/Permanent.Historic/historic permanent> | Type$ Card.Historic | StackDescription$ REP Seek_{p:You} seeks | SpellDescription$ Seek a historic card. DeckHas:Ability$Sacrifice DeckNeeds:Type$Legendary|Artifact|Planeswalker Oracle:{1}{W}, Sacrifice a historic permanent: Seek a historic card. diff --git a/forge-gui/res/cardsfolder/o/obsessive_collector.txt b/forge-gui/res/cardsfolder/o/obsessive_collector.txt index 809f5bf7613..e0cecad3a11 100644 --- a/forge-gui/res/cardsfolder/o/obsessive_collector.txt +++ b/forge-gui/res/cardsfolder/o/obsessive_collector.txt @@ -5,6 +5,6 @@ PT:4/4 K:Flying K:Ward:2 T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | Execute$ TrigSeek | CombatDamage$ True | TriggerDescription$ Whenever CARDNAME deals combat damage to a player, seek a card with mana value equal to the number of cards in your hand. -SVar:TrigSeek:DB$ ChangeZone | Origin$ Library | Destination$ Hand | AtRandom$ True | NoShuffle$ True | Mandatory$ True | NoLooking$ True | NoReveal$ True | ChangeType$ Card.cmcEQX | ChangeNum$ 1 +SVar:TrigSeek:DB$ Seek | Type$ Card.cmcEQX SVar:X:Count$InYourHand Oracle:Flying\nWard {2}\nWhenever Obsessive Collector deals combat damage to a player, seek a card with mana value equal to the number of cards in your hand. diff --git a/forge-gui/res/cardsfolder/o/one_with_the_multiverse.txt b/forge-gui/res/cardsfolder/o/one_with_the_multiverse.txt index bbd1dbe8a5e..f3baa110847 100644 --- a/forge-gui/res/cardsfolder/o/one_with_the_multiverse.txt +++ b/forge-gui/res/cardsfolder/o/one_with_the_multiverse.txt @@ -1,6 +1,6 @@ Name:One With the Multiverse ManaCost:6 U U Types:Enchantment -S:Mode$ Continuous | Affected$ Card.TopLibrary+YouCtrl | AffectedZone$ Library | MayLookAt$ Player | MayPlay$ True | Description$ Play with the top card of your library revealed. You may play lands and cast spells from the top of your library. +S:Mode$ Continuous | Affected$ Card.TopLibrary+YouCtrl | AffectedZone$ Library | MayLookAt$ You | MayPlay$ True | Description$ You may look at the top card of your library any time. You may play lands and cast spells from the top of your library. S:Mode$ Continuous | MayPlay$ True | MayPlayWithoutManaCost$ True | MayPlayLimit$ 1 | MayPlayDontGrantZonePermissions$ True | Affected$ Card.nonLand+TopLibrary+YouCtrl,Card.nonLand+YouOwn | AffectedZone$ Library,Hand | Description$ Once during each of your turns, you may cast a spell from your hand or the top of your library without paying its mana cost. -Oracle:Play with the top card of your library revealed.\nYou may play lands and cast spells from the top of your library.\nOnce during each of your turns, you may cast a spell from your hand or the top of your library without paying its mana cost. +Oracle:You may look at the top card of your library any time.\nYou may play lands and cast spells from the top of your library.\nOnce during each of your turns, you may cast a spell from your hand or the top of your library without paying its mana cost. diff --git a/forge-gui/res/cardsfolder/p/puppet_raiser.txt b/forge-gui/res/cardsfolder/p/puppet_raiser.txt index 8d616af25ab..364db14bcef 100644 --- a/forge-gui/res/cardsfolder/p/puppet_raiser.txt +++ b/forge-gui/res/cardsfolder/p/puppet_raiser.txt @@ -4,7 +4,7 @@ Types:Creature Zombie Wizard PT:3/4 T:Mode$ Phase | Phase$ End of Turn | ValidPlayer$ You | TriggerZones$ Battlefield | IsPresent$ Card.Creature+YouOwn | PresentZone$ Graveyard | PresentCompare$ GE1 | Execute$ TrigExile | TriggerDescription$ At the beginning of your end step, exile up to one target creature card from your graveyard. If you do, seek a creature card with mana value equal to the mana value of that card plus one. That card perpetually gains menace. SVar:TrigExile:DB$ ChangeZone | Origin$ Graveyard | Destination$ Exile | ValidTgts$ Creature.YouOwn | TgtPrompt$ Select up to one target creature card in your graveyard | TargetMin$ 0 | TargetMax$ 1 | RememberChanged$ True | SubAbility$ DBSeek -SVar:DBSeek:DB$ ChangeZone | Origin$ Library | Destination$ Hand | AtRandom$ True | NoShuffle$ True | Mandatory$ True | NoLooking$ True | NoReveal$ True | ChangeType$ Creature.cmcEQX | ChangeNum$ 1 | Imprint$ True | SubAbility$ DBEffect +SVar:DBSeek:DB$ Seek | Type$ Creature.cmcEQX | ImprintFound$ True | SubAbility$ DBEffect SVar:DBEffect:DB$ Effect | RememberObjects$ Imprinted | StaticAbilities$ PerpetualAbility | Duration$ Permanent | Name$ Puppet Raiser's Perpetual Effect | SubAbility$ DBCleanup SVar:PerpetualAbility:Mode$ Continuous | Affected$ Card.IsRemembered | EffectZone$ Command | AffectedZone$ Battlefield,Hand,Graveyard,Exile,Stack,Library,Command | AddKeyword$ Menace | Triggers$ Update | Description$ That card perpetually gains menace. SVar:Update:Mode$ ChangesZone | Origin$ Any | Destination$ Any | Static$ True | ValidCard$ Card.IsRemembered | Execute$ DBUpdate diff --git a/forge-gui/res/cardsfolder/s/sarevok_the_usurper.txt b/forge-gui/res/cardsfolder/s/sarevok_the_usurper.txt index 2dcb1cf6ae6..280d6314572 100644 --- a/forge-gui/res/cardsfolder/s/sarevok_the_usurper.txt +++ b/forge-gui/res/cardsfolder/s/sarevok_the_usurper.txt @@ -7,8 +7,8 @@ T:Mode$ Phase | Phase$ BeginCombat | ValidPlayer$ You | TriggerZones$ Battlefiel SVar:TrigPump:DB$ Pump | ValidTgts$ Creature.YouCtrl | TgtPrompt$ Select target creature you control | NumAtt$ X SVar:X:Count$TypeInYourYard.Creature DeckHas:Ability$Graveyard -Oracle:Specialize {3}\nAt the beginning of combat on your turn, target creature you control gets +X/+0 until end of turn, where X is the number of creature cards in your graveyard. AlternateMode:Specialize +Oracle:Specialize {3}\nAt the beginning of combat on your turn, target creature you control gets +X/+0 until end of turn, where X is the number of creature cards in your graveyard. SPECIALIZE:WHITE @@ -29,7 +29,6 @@ Name:Sarevok, Deceitful Usurper ManaCost:3 U B Types:Legendary Creature Human Knight PT:4/4 -K:First Strike T:Mode$ Phase | Phase$ BeginCombat | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigPump | TriggerDescription$ At the beginning of combat on your turn, target creature you control gets +X/+0 until end of turn, where X is the number of creature, instant, and sorcery cards in your graveyard. SVar:TrigPump:DB$ Pump | ValidTgts$ Creature.YouCtrl | TgtPrompt$ Select target creature you control | NumAtt$ X SVar:X:Count$ValidGraveyard Instant.YouOwn,Sorcery.YouOwn,Creature.YouOwn @@ -45,8 +44,10 @@ ManaCost:3 B B Types:Legendary Creature Human Knight PT:4/4 T:Mode$ Specializes | ValidCard$ Card.Self | TriggerZones$ Battlefield | Execute$ TrigSeek | TriggerDescription$ When this creature specializes, seek a creature card and put it into your graveyard, then conjure two duplicates of it into your graveyard. -SVar:TrigSeek:DB$ ChangeZone | Origin$ Library | Destination$ Graveyard | AtRandom$ True | NoShuffle$ True | Mandatory$ True | NoLooking$ True | NoReveal$ True | ChangeType$ Creature.YouCtrl | ChangeNum$ 1 | SubAbility$ DBConjure | RememberChanged$ True -SVar:DBConjure:DB$ Makecard | Conjure$ True | DefinedName$ Remembered | Zone$ Graveyard | Amount$ 2 +SVar:TrigSeek:DB$ Seek | Type$ Card.Creature | RememberFound$ True | SubAbility$ DBPut +SVar:DBPut:DB$ ChangeZone | Origin$ Hand | Destination$ Graveyard | Defined$ Remembered | SubAbility$ DBConjure +SVar:DBConjure:DB$ MakeCard | Conjure$ True | DefinedName$ Remembered | Zone$ Graveyard | Amount$ 2 | SubAbility$ DBCleanup +SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True T:Mode$ Phase | Phase$ BeginCombat | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigPump | TriggerDescription$ At the beginning of combat on your turn, target creature you control gets +X/+0 until end of turn, where X is the number of creature cards in your graveyard. SVar:TrigPump:DB$ Pump | ValidTgts$ Creature.YouCtrl | TgtPrompt$ Select target creature you control | NumAtt$ X SVar:X:Count$TypeInYourYard.Creature @@ -64,7 +65,7 @@ T:Mode$ Phase | Phase$ BeginCombat | ValidPlayer$ You | TriggerZones$ Battlefiel SVar:TrigPump:DB$ Pump | ValidTgts$ Creature.YouCtrl | TgtPrompt$ Select target creature you control | NumAtt$ X | KW$ Menace SVar:X:Count$TypeInYourYard.Creature DeckHas:Ability$Graveyard & Keyword$Menace -Oracle:Menace\nAt the beginning of combat on your turn, target creature you control gains Menace and gets +X/+0 until end of turn, where X is the number of creature cards in your graveyard. +Oracle:Menace\nAt the beginning of combat on your turn, target creature you control gains menace and gets +X/+0 until end of turn, where X is the number of creature cards in your graveyard. SPECIALIZE:GREEN diff --git a/forge-gui/res/cardsfolder/s/settle_the_wilds.txt b/forge-gui/res/cardsfolder/s/settle_the_wilds.txt index 64cbd175323..c50049248f9 100644 --- a/forge-gui/res/cardsfolder/s/settle_the_wilds.txt +++ b/forge-gui/res/cardsfolder/s/settle_the_wilds.txt @@ -1,7 +1,9 @@ Name:Settle the Wilds ManaCost:2 G Types:Sorcery -A:SP$ ChangeZone | Origin$ Library | Destination$ Battlefield | Tapped$ True | AtRandom$ True | NoShuffle$ True | Mandatory$ True | NoLooking$ True | NoReveal$ True | ChangeType$ Land.Basic | ChangeNum$ 1 | SubAbility$ DBSeek | StackDescription$ SpellDescription | SpellDescription$ Seek a basic land card and put it onto the battlefield tapped. -SVar:DBSeek:DB$ ChangeZone | Origin$ Library | Destination$ Hand | AtRandom$ True | NoShuffle$ True | Mandatory$ True | NoLooking$ True | NoReveal$ True | ChangeType$ Permanent.cmcEQX | ChangeNum$ 1 | StackDescription$ SpellDescription | SpellDescription$ Then seek a permanent card with mana value equal to the number of lands you control. +A:SP$ Seek | Type$ Card.Land+Basic | SubAbility$ DBPut | RememberFound$ True | StackDescription$ REP Seek_{p:You} seeks | SpellDescription$ Seek a basic land card and put it onto the battlefield tapped. +SVar:DBPut:DB$ ChangeZone | Origin$ Hand | Destination$ Battlefield | Defined$ Remembered | Tapped$ True | StackDescription$ None | SubAbility$ DBCleanup +SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True | SubAbility$ DBSeek +SVar:DBSeek:DB$ Seek | Type$ Card.Permanent+cmcEQX | StackDescription$ REP seek_{p:You} seeks & you_they | SpellDescription$ Then seek a permanent card with mana value equal to the number of lands you control. SVar:X:Count$Valid Land.YouCtrl Oracle:Seek a basic land card and put it onto the battlefield tapped. Then seek a permanent card with mana value equal to the number of lands you control. diff --git a/forge-gui/res/cardsfolder/s/signature_spells.txt b/forge-gui/res/cardsfolder/s/signature_spells.txt index aa0418d9ea9..4553d04c062 100644 --- a/forge-gui/res/cardsfolder/s/signature_spells.txt +++ b/forge-gui/res/cardsfolder/s/signature_spells.txt @@ -2,7 +2,8 @@ Name:Signature Spells ManaCost:4 U U Types:Enchantment T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigSeekTwo | TriggerDescription$ When CARDNAME enters the battlefield, seek two instant and/or sorcery cards with mana value 3, then exile them. -SVar:TrigSeekTwo:DB$ ChangeZone | Imprint$ True | Origin$ Library | Destination$ Exile | AtRandom$ True | NoShuffle$ True | Mandatory$ True | NoLooking$ True | NoReveal$ True | ChangeNum$ 2 | ChangeType$ Card.Instant+cmcEQ3,Card.Sorcery+cmcEQ3 | StackDescription$ SpellDescription | SpellDescription$ Seek two nonland cards, then put a card from your hand on the bottom of your library. +SVar:TrigSeekTwo:DB$ Seek | ImprintFound$ True | Num$ 2 | Type$ Card.Instant+cmcEQ3,Card.Sorcery+cmcEQ3 | SubAbility$ DBExile +SVar:DBExile:DB$ ChangeZone | Origin$ Hand | Destination$ Exile | Defined$ Imprinted T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | Execute$ DBCopy | TriggerZones$ Battlefield | OptionalDecider$ You | TriggerDescription$ At the beginning of your upkeep, you may copy a card exiled with CARDNAME. You may cast the copy without paying its mana cost. SVar:DBCopy:DB$ Play | Valid$ Card.IsImprinted+ExiledWithSource | ValidZone$ Exile | WithoutManaCost$ True | ValidSA$ Spell | Optional$ True | CopyCard$ True T:Mode$ ChangesZone | Origin$ Exile | Destination$ Any | Static$ True | ValidCard$ Card.IsImprinted+ExiledWithSource | Execute$ DBForget diff --git a/forge-gui/res/cardsfolder/s/skyshroud_lookout.txt b/forge-gui/res/cardsfolder/s/skyshroud_lookout.txt index 0a3a4c53713..b09ba63b2b8 100644 --- a/forge-gui/res/cardsfolder/s/skyshroud_lookout.txt +++ b/forge-gui/res/cardsfolder/s/skyshroud_lookout.txt @@ -4,6 +4,6 @@ Types:Creature Elf Archer PT:1/1 K:Reach T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigSeek | TriggerDescription$ When CARDNAME enters the battlefield, seek an Elf card. -SVar:TrigSeek:DB$ ChangeZone | Origin$ Library | Destination$ Hand | AtRandom$ True | NoShuffle$ True | Mandatory$ True | NoLooking$ True | NoReveal$ True | ChangeType$ Card.Elf | ChangeNum$ 1 +SVar:TrigSeek:DB$ Seek | Type$ Card.Elf DeckHints:Type$Elf Oracle:Reach\nWhen Skyshroud Lookout enters the battlefield, seek an Elf card. diff --git a/forge-gui/res/cardsfolder/s/soulstealer_axe.txt b/forge-gui/res/cardsfolder/s/soulstealer_axe.txt index 3d30322d7a7..4ff4fccbc19 100644 --- a/forge-gui/res/cardsfolder/s/soulstealer_axe.txt +++ b/forge-gui/res/cardsfolder/s/soulstealer_axe.txt @@ -3,7 +3,7 @@ ManaCost:1 Types:Artifact Equipment S:Mode$ Continuous | Affected$ Creature.EquippedBy | AddKeyword$ Trample | Description$ Equipped creature has trample. T:Mode$ DamageDone | ValidSource$ Creature.EquippedBy | ValidTarget$ Player | CombatDamage$ True | Execute$ TrigSeek | TriggerZones$ Battlefield | TriggerDescription$ Whenever equipped creature deals combat damage to a player, seek a card with mana value equal to that damage. -SVar:TrigSeek:DB$ ChangeZone | Origin$ Library | Destination$ Hand | AtRandom$ True | NoShuffle$ True | Mandatory$ True | NoLooking$ True | NoReveal$ True | ChangeType$ Card.cmcEQX | ChangeNum$ 1 +SVar:TrigSeek:DB$ Seek | Type$ Card.cmcEQX SVar:X:TriggerCount$DamageAmount K:Equip:2 Oracle:Equipped creature has trample.\nWhenever equipped creature deals combat damage to a player, seek a card with mana value equal to that damage.\nEquip {2} diff --git a/forge-gui/res/cardsfolder/s/sunes_intervention.txt b/forge-gui/res/cardsfolder/s/sunes_intervention.txt index a1627766130..c4a310a5c93 100644 --- a/forge-gui/res/cardsfolder/s/sunes_intervention.txt +++ b/forge-gui/res/cardsfolder/s/sunes_intervention.txt @@ -3,7 +3,7 @@ ManaCost:4 W W Types:Instant A:SP$ Charm | MinCharmNum$ 1 | CharmNum$ 5 | Choices$ KnightTokens,SeekCard,DestroyArtifact,DestroyEnchantment,GainLife SVar:KnightTokens:DB$ Token | TokenOwner$ You | TokenScript$ w_2_2_knight | TokenAmount$ 2 | SpellDescription$ Create two 2/2 white Knight creature tokens. -SVar:SeekCard:DB$ ChangeZone | Origin$ Library | Destination$ Hand | AtRandom$ True | NoShuffle$ True | Mandatory$ True | NoLooking$ True | NoReveal$ True | ChangeType$ Card.Permanent+nonLand+cmcLE3 | ChangeNum$ 1 | SpellDescription$ Seek a nonland permanent card with mana value 3 or less. +SVar:SeekCard:DB$ Seek | Type$ Card.Permanent+nonLand+cmcLE3 | SpellDescription$ Seek a nonland permanent card with mana value 3 or less. SVar:DestroyArtifact:DB$ Destroy | ValidTgts$ Artifact | TgtPrompt$ Select target artifact | SpellDescription$ Destroy target artifact. SVar:DestroyEnchantment:DB$ Destroy | ValidTgts$ Enchantment | TgtPrompt$ Select target enchantment | SpellDescription$ Destroy target enchantment. SVar:GainLife:DB$ GainLife | ValidTgts$ Player | TgtPrompt$ Select target player to gain 3 life | LifeAmount$ 3 | SpellDescription$ Target player gains 3 life. diff --git a/forge-gui/res/cardsfolder/t/trove_mage.txt b/forge-gui/res/cardsfolder/t/trove_mage.txt index d0eecc3956d..e62484d87ba 100644 --- a/forge-gui/res/cardsfolder/t/trove_mage.txt +++ b/forge-gui/res/cardsfolder/t/trove_mage.txt @@ -3,7 +3,7 @@ ManaCost:2 U Types:Creature Human Wizard PT:2/2 T:Mode$ ChangesZone | ValidCard$ Card.Self | Destination$ Battlefield | Execute$ TrigSeek | TriggerDescription$ When CARDNAME enters the battlefield, seek an artifact card from among the top ten cards of your library, then shuffle. -SVar:TrigSeek:DB$ Dig | Defined$ You | DigNum$ 10 | ChangeNum$ 1 | ChangeValid$ Card.Artifact | DestinationZone$ Hand | Mandatory$ True | NoLooking$ True | DestinationZone2$ Library | LibraryPosition2$ 0 | SkipReorder$ True | RandomChange$ True | SubAbility$ Shuffle +SVar:TrigSeek:DB$ Seek | DefinedCards$ Top_10_OfLibrary | Type$ Artifact | SubAbility$ Shuffle SVar:Shuffle:DB$ Shuffle DeckNeeds:Type$Artifact Oracle:When Trove Mage enters the battlefield, seek an artifact card from among the top ten cards of your library, then shuffle. diff --git a/forge-gui/res/cardsfolder/u/unexpected_conversion.txt b/forge-gui/res/cardsfolder/u/unexpected_conversion.txt index bcb2c59c57f..2ebf97a9223 100644 --- a/forge-gui/res/cardsfolder/u/unexpected_conversion.txt +++ b/forge-gui/res/cardsfolder/u/unexpected_conversion.txt @@ -2,10 +2,11 @@ Name:Unexpected Conversion ManaCost:2 U Types:Sorcery A:SP$ Draw | NumCards$ 2 | SubAbility$ DBExile | SpellDescription$ Draw two cards. -SVar:DBExile:DB$ ChangeZone | Origin$ Hand | Destination$ Exile | Hidden$ True | ChangeType$ Instant,Sorcery | SelectPrompt$ Select an instant or sorcery card from your hand | RememberChanged$ True | SubAbility$ ExileHand | StackDescription$ SpellDescription | SpellDescription$ Then you may exile an instant or sorcery card from your hand. -SVar:ExileHand:DB$ ChangeZone | Origin$ Hand | Destination$ Exile | DefinedPlayer$ You | ChangeType$ Remembered.sameName | ChangeNum$ NumInHand | Chooser$ You | Imprint$ True | SubAbility$ ExileLib | StackDescription$ SpellDescription | ConditionDefined$ Remembered | ConditionPresent$ Card | ConditionCompare$ GE1 | SpellDescription$ If you do, search your hand -SVar:ExileLib:DB$ ChangeZone | Origin$ Library | Destination$ Exile | DefinedPlayer$ You | ChangeType$ Remembered.sameName | ChangeNum$ NumInLib | Chooser$ You | Shuffle$ True | StackDescription$ SpellDescription | SubAbility$ DBSeek | ConditionDefined$ Remembered | ConditionPresent$ Card | ConditionCompare$ GE1 | SpellDescription$ and library for any number of cards with the same name, exile them, then shuffle. -SVar:DBSeek:DB$ ChangeZone | Origin$ Library | Destination$ Hand | AtRandom$ True | NoShuffle$ True | NoLooking$ True | NoReveal$ True | ChangeNum$ X | ChangeType$ Instant,Sorcery | SubAbility$ DBCleanup | StackDescription$ SpellDescription | SpellDescription$ Seek an instant or sorcery card for each card exiled from your hand this way. +SVar:DBExile:DB$ ChangeZone | Origin$ Hand | Destination$ Exile | Hidden$ True | ChangeType$ Instant,Sorcery | SelectPrompt$ Select an instant or sorcery card from your hand | RememberChanged$ True | SubAbility$ DBBranch | StackDescription$ REP you_{p:You} & your_their | SpellDescription$ Then you may exile an instant or sorcery card from your hand. +SVar:DBBranch:DB$ Branch | BranchConditionSVar$ X | TrueSubAbility$ ExileHand +SVar:ExileHand:DB$ ChangeZone | Origin$ Hand | Destination$ Exile | DefinedPlayer$ You | ChangeType$ Remembered.sameName | ChangeNum$ NumInHand | Chooser$ You | Imprint$ True | SubAbility$ ExileLib | StackDescription$ SpellDescription | SpellDescription$ If you do, search your hand +SVar:ExileLib:DB$ ChangeZone | Origin$ Library | Destination$ Exile | DefinedPlayer$ You | ChangeType$ Remembered.sameName | ChangeNum$ NumInLib | Chooser$ You | Shuffle$ True | StackDescription$ SpellDescription | SubAbility$ DBSeek | SpellDescription$ and library for any number of cards with the same name, exile them, then shuffle. +SVar:DBSeek:DB$ Seek | Num$ X | Type$ Card.Instant,Card.Sorcery | SubAbility$ DBCleanup | StackDescription$ SpellDescription | SpellDescription$ Seek an instant or sorcery card for each card exiled from your hand this way. SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True | ClearImprinted$ True SVar:NumInLib:Count$InYourLibrary SVar:NumInHand:Count$InYourHand diff --git a/forge-gui/res/cardsfolder/u/urzas_construction_drone.txt b/forge-gui/res/cardsfolder/u/urzas_construction_drone.txt index 2360461397e..39cbebc4e74 100644 --- a/forge-gui/res/cardsfolder/u/urzas_construction_drone.txt +++ b/forge-gui/res/cardsfolder/u/urzas_construction_drone.txt @@ -6,7 +6,7 @@ T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.S SVar:TrigConjure:DB$ MakeCard | Conjure$ True | Names$ Urza's Mine,Urza's Tower,Urza's Power Plant | Zone$ Library T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigSeek | TriggerDescription$ Whenever CARDNAME attacks or dies, seek an Urza's land card. T:Mode$ ChangesZone | ValidCard$ Card.Self | Origin$ Battlefield | Destination$ Graveyard | Execute$ TrigSeek | Secondary$ True | Execute$ TrigSeek | TriggerDescription$ Whenever CARDNAME attacks or dies, seek an Urza's land card. -SVar:TrigSeek:DB$ ChangeZone | Origin$ Library | Destination$ Hand | AtRandom$ True | NoShuffle$ True | Mandatory$ True | NoLooking$ True | NoReveal$ True | ChangeType$ Land.Urza's | ChangeNum$ 1 +SVar:TrigSeek:DB$ Seek | Type$ Card.Land+Urza's SVar:HasAttackEffect:TRUE DeckHas:Type$Urza's DeckHints:Type$Urza's diff --git a/forge-gui/res/cardsfolder/upcoming/blightwing_whelp.txt b/forge-gui/res/cardsfolder/upcoming/blightwing_whelp.txt index aabf877e1d3..6a9587ffae1 100644 --- a/forge-gui/res/cardsfolder/upcoming/blightwing_whelp.txt +++ b/forge-gui/res/cardsfolder/upcoming/blightwing_whelp.txt @@ -6,6 +6,6 @@ K:Flying K:Toxic:1 A:AB$ Pump | Cost$ B | KW$ Haste | Defined$ Self | SpellDescription$ CARDNAME gains haste until end of turn. T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | Execute$ TrigSeek | CombatDamage$ True | TriggerDescription$ Whenever CARDNAME deals combat damage to a player, seek a card with mana value equal to the number of poison counters that player has. -SVar:TrigSeek:DB$ ChangeZone | Origin$ Library | Destination$ Hand | AtRandom$ True | NoShuffle$ True | Mandatory$ True | NoLooking$ True | NoReveal$ True | ChangeType$ Card.cmcEQX | ChangeNum$ 1 +SVar:TrigSeek:DB$ Seek | Type$ Card.cmcEQX SVar:X:TriggeredTarget$PoisonCounters Oracle:Flying\nToxic 1\n{B}: Blightwing Whelp gains haste until end of turn.\nWhenever Blightwing Welp deals combat damage to a player, seek a card with mana value equal to the number of poison counters that player has. diff --git a/forge-gui/res/cardsfolder/upcoming/glistening_extractor.txt b/forge-gui/res/cardsfolder/upcoming/glistening_extractor.txt index 02a0d08c2ef..431a418c33b 100644 --- a/forge-gui/res/cardsfolder/upcoming/glistening_extractor.txt +++ b/forge-gui/res/cardsfolder/upcoming/glistening_extractor.txt @@ -3,7 +3,7 @@ ManaCost:2 U B Types:Artifact K:etbCounter:OIL:4 T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | IsPresent$ Card.Self+counters_GE1_OIL | Execute$ TrigSeek | TriggerZones$ Battlefield | TriggerDescription$ At the beginning of your upkeep, if there are one or more oil counters on CARDNAME, seek a card with mana value equal to the number of oil counters on CARDNAME, then remove an oil counter from CARDNAME. -SVar:TrigSeek:DB$ ChangeZone | Origin$ Library | Destination$ Hand | AtRandom$ True | NoShuffle$ True | Mandatory$ True | NoLooking$ True | NoReveal$ True | ChangeType$ Card.cmcEQX | ChangeNum$ 1 | SubAbility$ DBRemoveCounter +SVar:TrigSeek:DB$ Seek | Type$ Card.cmcEQX | SubAbility$ DBRemoveCounter SVar:DBRemoveCounter:DB$ RemoveCounter | CounterType$ OIL SVar:X:Count$CardCounters.OIL Oracle:Glistening Extractor enters the battlefield with four oil counters on it.\nAt the beginning of your upkeep, if there are one or more oil counters on Glistening Extractor, seek a card with mana value equal to the number of oil counters on Glistening Extractor, then remove an oil counter from Glistening Extractor. diff --git a/forge-gui/res/cardsfolder/upcoming/innovative_metatect.txt b/forge-gui/res/cardsfolder/upcoming/innovative_metatect.txt new file mode 100644 index 00000000000..dc8d8fb56e3 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/innovative_metatect.txt @@ -0,0 +1,9 @@ +Name:Innovative Metatect +ManaCost:W U +Types:Creature Phyrexian Artificer +PT:1/3 +T:Mode$ DamageDoneOnce | CombatDamage$ True | ValidSource$ Creature.Artifact+YouCtrl | TriggerZones$ Battlefield | ValidTarget$ Player | Execute$ TrigSeek | TriggerDescription$ Whenever one or more artifact creatures you control deal combat damage to a player, seek a nonland card with mana value 2 or less. +SVar:TrigSeek:DB$ Seek | Type$ Card.nonLand+cmcLE2 +DeckNeeds:Type$Artifact +AI:RemoveDeck:Random +Oracle:Whenever one or more artifact creatures you control deal combat damage to a player, seek a nonland card with mana value 2 or less. diff --git a/forge-gui/res/cardsfolder/upcoming/phyrexian_harvester.txt b/forge-gui/res/cardsfolder/upcoming/phyrexian_harvester.txt index c25ccbe2834..4c411f97692 100644 --- a/forge-gui/res/cardsfolder/upcoming/phyrexian_harvester.txt +++ b/forge-gui/res/cardsfolder/upcoming/phyrexian_harvester.txt @@ -4,7 +4,7 @@ Types:Creature Phyrexian Horror PT:5/5 K:Menace T:Mode$ DamageDone | ValidTarget$ Card.Self | Execute$ TrigSeek | TriggerDescription$ Whenever CARDNAME is dealt damage, seek that many nonland cards. At the beginning of your next end step, discard those cards. -SVar:TrigSeek:DB$ ChangeZone | Origin$ Library | Destination$ Hand | AtRandom$ True | NoShuffle$ True | Mandatory$ True | NoLooking$ True | NoReveal$ True | ChangeNum$ X | ChangeType$ Card.nonLand | RememberChanged$ True | SubAbility$ DBDelay +SVar:TrigSeek:DB$ Seek | Num$ X | Type$ Card.nonLand | RememberFound$ True | SubAbility$ DBDelay SVar:DBDelay:DB$ DelayedTrigger | Mode$ Phase | Phase$ End of Turn | Execute$ TrigDiscardExiled | SubAbility$ DBCleanup | RememberObjects$ Remembered | TriggerDescription$ At the beginning of the next end step, discard those cards. SVar:TrigDiscardExiled:DB$ Discard | Mode$ Defined | DefinedCards$ DelayTriggerRemembered SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True diff --git a/forge-gui/res/cardsfolder/upcoming/spawning_pod.txt b/forge-gui/res/cardsfolder/upcoming/spawning_pod.txt index faa2f916ee2..38a4add3702 100644 --- a/forge-gui/res/cardsfolder/upcoming/spawning_pod.txt +++ b/forge-gui/res/cardsfolder/upcoming/spawning_pod.txt @@ -1,8 +1,10 @@ Name:Spawning Pod ManaCost:2 G Types:Artifact -A:AB$ ChangeZone | Cost$ 1 T Sac<1/Creature> | Origin$ Library | Destination$ Battlefield | AtRandom$ True | NoShuffle$ True | Mandatory$ True | NoLooking$ True | NoReveal$ True | ChangeType$ Creature.cmcEQX | ChangeNum$ 1 | SorcerySpeed$ True | AILogic$ SacAndUpgrade | AnimateSubAbility$ DBAnimate | SpellDescription$ Seek a creature card with mana value equal to 1 plus the sacrificed creature's mana value and put that card onto the battlefield. That creature is a Phyrexian in addition to its other types. Activate only as a sorcery. +A:AB$ Seek | Cost$ 1 T Sac<1/Creature> | Type$ Creature.cmcEQX | SorcerySpeed$ True | AILogic$ SacAndUpgrade | ImprintFound$ True | SubAbility$ DBPut | SpellDescription$ Seek a creature card with mana value equal to 1 plus the sacrificed creature's mana value and put that card onto the battlefield. That creature is a Phyrexian in addition to its other types. Activate only as a sorcery. +SVar:DBPut:DB$ ChangeZone | Origin$ Hand | Destination$ Battlefield | Defined$ Imprinted | AnimateSubAbility$ DBAnimate | SubAbility$ DBCleanup SVar:DBAnimate:DB$ Animate | Defined$ Remembered | Types$ Phyrexian | Duration$ Permanent +SVar:DBCleanup:DB$ Cleanup | ClearImprinted$ True SVar:X:Sacrificed$CardManaCost/Plus.1 SVar:AIPreference:SacCost$Creature.nonToken DeckHas:Ability$Sacrifice & Type$Phyrexian diff --git a/forge-gui/res/cardsfolder/upcoming/vexyr_ich_tekiks_heir.txt b/forge-gui/res/cardsfolder/upcoming/vexyr_ich_tekiks_heir.txt new file mode 100644 index 00000000000..ab0839a80cf --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/vexyr_ich_tekiks_heir.txt @@ -0,0 +1,9 @@ +Name:Vexyr, Ich-Tekik's Heir +ManaCost:G W U +Types:Legendary Creature Phyrexian Artificer +PT:3/4 +T:Mode$ SeekAll | ValidPlayer$ You | Execute$ TrigToken | TriggerDescription$ Whenever you seek one or more cards, create a 3/3 colorless Phyrexian Golem artifact creature token. +SVar:TrigToken:DB$ Token | TokenScript$ c_3_3_a_phyrexian_golem +S:Mode$ Continuous | Affected$ Golem.YouCtrl | AddKeyword$ Vigilance | Description$ Golems you control have vigilance. +DeckHints:Type$Golem +Oracle:Whenever you seek one or more cards, create a 3/3 colorless Phyrexian Golem artifact creature token.\nGolems you control have vigilance. diff --git a/forge-gui/res/cardsfolder/v/vhal_eager_scholar.txt b/forge-gui/res/cardsfolder/v/vhal_eager_scholar.txt index b1f71fe00c2..8f0e27a5392 100644 --- a/forge-gui/res/cardsfolder/v/vhal_eager_scholar.txt +++ b/forge-gui/res/cardsfolder/v/vhal_eager_scholar.txt @@ -85,7 +85,7 @@ Types:Legendary Creature Human Wizard PT:4/4 T:Mode$ Specializes | ValidCard$ Card.Self | Execute$ TrigRemoveCounters | TriggerDescription$ When this creature specializes, remove all study counters from it. Seek two creature cards with mana value less than or equal to the number of study counters removed this way. Put one of them onto the battlefield and shuffle the other into your library. SVar:TrigRemoveCounters:DB$ RemoveCounter | CounterType$ STUDY | CounterNum$ All | RememberRemoved$ True | SubAbility$ DBSeek -SVar:DBSeek:DB$ ChangeZone | Origin$ Library | Destination$ Hand | AtRandom$ True | NoShuffle$ True | Mandatory$ True | NoLooking$ True | NoReveal$ True | ChangeNum$ 2 | ChangeType$ Creature.cmcLEX | RememberChanged$ True | SubAbility$ DBBattlefield +SVar:DBSeek:DB$ Seek | Type$ Card.Creature+cmcLEX | Num$ 2 | RememberFound$ True | SubAbility$ DBBattlefield SVar:DBBattlefield:DB$ ChangeZone | Origin$ Hand | Destination$ Battlefield | SelectPrompt$ Select one to put onto the battlefield | ChangeType$ Card.IsRemembered | ForgetChanged$ True | SubAbility$ DBShuffle SVar:DBShuffle:DB$ ChangeZone | Origin$ Hand | Destination$ Library | Shuffle$ True | Defined$ RememberedCard | SubAbility$ DBCleanup SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True diff --git a/forge-gui/res/cardsfolder/y/yotian_courier.txt b/forge-gui/res/cardsfolder/y/yotian_courier.txt index 43b466cfacb..f80772b7c14 100644 --- a/forge-gui/res/cardsfolder/y/yotian_courier.txt +++ b/forge-gui/res/cardsfolder/y/yotian_courier.txt @@ -6,7 +6,7 @@ K:Flying T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigCharm | TriggerDescription$ Whenever CARDNAME attacks, ABILITY SVar:TrigCharm:DB$ Charm | Choices$ Powerstone,Seek | ChoiceRestriction$ YourLastCombat SVar:Powerstone:DB$ Token | TokenTapped$ True | TokenScript$ c_a_powerstone | SpellDescription$ Create a tapped Powerstone token. -SVar:Seek:DB$ ChangeZone | Origin$ Library | Destination$ Hand | AtRandom$ True | NoShuffle$ True | NoLooking$ True | NoReveal$ True | ChangeNum$ 1 | ChangeType$ Artifact.cmcEQX | SpellDescription$ Seek an artifact card with mana value equal to the number of Powerstones you control. +SVar:Seek:DB$ Seek | Type$ Artifact.cmcEQX | SpellDescription$ Seek an artifact card with mana value equal to the number of Powerstones you control. SVar:X:Count$Valid Powerstone.YouCtrl DeckNeeds:Type$Artifact DeckHas:Ability$Token & Type$Artifact diff --git a/forge-gui/res/draft/rankings.txt b/forge-gui/res/draft/rankings.txt index c8679fca338..de0f8e3c4ab 100644 --- a/forge-gui/res/draft/rankings.txt +++ b/forge-gui/res/draft/rankings.txt @@ -1,264 +1,556 @@ //Rank|Name|Rarity|Set -#1|Nissa, Ascended Animist|M|ONE -#2|Kaya, Intangible Slayer|R|ONE -#3|Lukka, Bound to Ruin|M|ONE -#4|Phyrexian Vindicator|M|ONE -#5|Blue Sun's Twilight|R|ONE -#6|Tekuthal, Inquiry Dominus|M|ONE -#7|Vraska, Betrayal's Sting|M|ONE -#8|Thrun, Breaker of Silence|R|ONE -#9|Sword of Forge and Frontier|M|ONE -#10|Glissa Sunslayer|R|ONE -#11|The Eternal Wanderer|R|ONE -#12|Jace, the Perfected Mind|M|ONE -#13|Dragonwing Glider|R|ONE -#14|Bloated Contaminator|R|ONE -#15|Tyrranax Rex|M|ONE -#16|Kaito, Dancing Shadow|R|ONE -#17|Ovika, Enigma Goliath|R|ONE -#18|Black Sun's Twilight|R|ONE -#19|Zopandrel, Hunger Dominus|M|ONE -#20|Mondrak, Glory Dominus|M|ONE -#21|Mercurial Spelldancer|R|ONE -#22|Solphim, Mayhem Dominus|M|ONE -#23|Atraxa, Grand Unifier|M|ONE -#24|Ezuri, Stalker of Spheres|R|ONE -#25|Argentum Masticore|R|ONE -#26|Elesh Norn, Mother of Machines|M|ONE -#27|White Sun's Twilight|R|ONE -#28|Phyrexian Obliterator|M|ONE +#1|Archangel Avacyn|M|SIR +#2|Sorin, Grim Nemesis|M|SIR +#3|Arlinn Kord|M|SIR +#4|Descend upon the Sinful|M|SIR +#5|Jace, Unraveler of Secrets|M|SIR +#6|Decimator of the Provinces|M|SIR +#7|Docent of Perfection|R|SIR +#8|Liliana, the Last Hope|M|SIR +#9|Sigarda, Heron's Grace|M|SIR +#10|Gisela, the Broken Blade|M|SIR +#11|Ishkanah, Grafwidow|M|SIR +#12|Nahiri, the Harbinger|M|SIR +#13|Olivia, Mobilized for War|M|SIR +#14|Tamiyo, Field Researcher|M|SIR +#15|Ulrich of the Krallenhorde|R|SIR +#16|Dark Salvation|R|SIR +#17|Tireless Tracker|R|SIR +#18|Always Watching|R|SIR +#19|Avacyn's Judgment|R|SIR +#20|Collective Effort|R|SIR +#21|Heron's Grace Champion|R|SIR +#22|Thalia, Heretic Cathar|R|SIR +#23|Collective Defiance|R|SIR +#24|Emrakul, the Promised End|M|SIR +#25|Nahiri's Wrath|M|SIR +#26|Spell Queller|R|SIR +#27|Bloodhall Priest|R|SIR +#28|Bygone Bishop|R|SIR +#29|Gisa and Geralf|M|SIR +#30|Goldnight Castigator|M|SIR +#31|Mindwrack Demon|M|SIR +#32|Odric, Lunarch Marshal|R|SIR +#33|Voldaren Pariah|R|SIR +#34|Wharf Infiltrator|R|SIR +#35|Bruna, the Fading Light|R|SIR +#36|Burn from Within|R|SIR +#37|Devils' Playground|R|SIR +#38|Distended Mindbender|R|SIR +#39|Elder Deep-Fiend|R|SIR +#40|Grim Flayer|R|SIR +#41|Startled Awake|M|SIR +#42|Westvale Abbey|R|SIR +#43|Assembled Alphas|R|SIR +#44|Geralf's Masterpiece|R|SIR +#45|Hanweir Garrison|R|SIR +#46|Mirrorwing Dragon|M|SIR +#47|Stromkirk Condemned|R|SIR +#48|Altered Ego|R|SIR +#49|Declaration in Stone|R|SIR +#50|Forgotten Creation|R|SIR +#51|Noosegraf Mob|R|SIR +#52|Selfless Spirit|R|SIR +#53|Sin Prodder|R|SIR +#54|Spirit of the Hunt|R|SIR +#55|Anguished Unmaking|U|SIR +#56|Clear Shot|U|SIR +#57|Collective Brutality|R|SIR +#58|Duskwatch Recruiter|U|SIR +#59|Relentless Dead|M|SIR +#60|Triskaidekaphobia|R|SIR +#61|Diregraf Colossus|R|SIR +#62|Flameblade Angel|R|SIR +#63|Bedlam Reveler|R|SIR +#64|Bound by Moonsilver|C|SIR +#65|Erdwal Illuminator|U|SIR +#66|Fiery Temper|U|SIR +#67|Geier Reach Bandit|U|SIR +#68|Lightning Axe|U|SIR +#69|Stromkirk Occultist|U|SIR +#70|Tree of Perdition|R|SIR +#71|Ulvenwald Hydra|R|SIR +#72|Accursed Witch|U|SIR +#73|Galvanic Bombardment|C|SIR +#74|Incendiary Flow|C|SIR +#75|Ongoing Investigation|U|SIR +#76|Tamiyo's Journal|R|SIR +#77|Thalia's Lancers|R|SIR +#78|Ulvenwald Captive|C|SIR +#79|Dead Weight|C|SIR +#80|Mad Prophet|U|SIR +#81|Mournwillow|U|SIR +#82|Nebelgast Herald|U|SIR +#83|Pack Guardian|U|SIR +#84|Prized Amalgam|R|SIR +#85|Rabid Bite|C|SIR +#86|Sigardian Priest|C|SIR +#87|Veteran Cathar|U|SIR +#88|Alchemist's Greeting|C|SIR +#89|Angelic Purge|C|SIR +#90|Call the Bloodline|U|SIR +#91|Deathcap Cultivator|U|SIR +#92|Kindly Stranger|U|SIR +#93|Rattlechains|R|SIR +#94|Shrill Howler|U|SIR +#95|Ulrich's Kindred|U|SIR +#96|Advanced Stitchwing|U|SIR +#97|Cryptolith Fragment|U|SIR +#98|Drunau Corpse Trawler|U|SIR +#99|Gisa's Bidding|C|SIR +#100|Haunted Dead|U|SIR +#101|Ingenious Skaab|C|SIR +#102|Nearheath Chaplain|U|SIR +#103|Obsessive Skinner|C|SIR +#104|Slayer's Plate|R|SIR +#105|Ulvenwald Mysteries|U|SIR +#106|Conduit of Storms|C|SIR +#107|Courageous Outrider|U|SIR +#108|Gnarlwood Dryad|C|SIR +#109|Graf Mole|U|SIR +#110|Olivia's Bloodsworn|U|SIR +#111|Scourge Wolf|U|SIR +#112|Bloodbriar|C|SIR +#113|Compelling Deterrence|U|SIR +#114|Dauntless Cathar|C|SIR +#115|Imprisoned in the Moon|C|SIR +#116|Insatiable Gorgers|C|SIR +#117|Noose Constrictor|U|SIR +#118|Pore Over the Pages|U|SIR +#119|Puncturing Light|C|SIR +#120|Topplegeist|U|SIR +#121|Blessed Alliance|U|SIR +#122|Certain Death|C|SIR +#123|Daring Sleuth|U|SIR +#124|Deranged Whelp|C|SIR +#125|Drag Under|C|SIR +#126|Lone Rider|U|SIR +#127|Seasons Past|M|SIR +#128|Spectral Shepherd|U|SIR +#129|Subjugator Angel|U|SIR +#130|Thraben Inspector|C|SIR +#131|Bloodmad Vampire|C|SIR +#132|Briarbridge Patrol|C|SIR +#133|Choked Estuary|U|SIR +#134|Crow of Dark Tidings|C|SIR +#135|Drownyard Behemoth|U|SIR +#136|Drownyard Explorers|C|SIR +#137|Ever After|R|SIR +#138|Foreboding Ruins|U|SIR +#139|Fortified Village|U|SIR +#140|Furyblade Vampire|U|SIR +#141|Game Trail|U|SIR +#142|Geier Reach Sanitarium|R|SIR +#143|Geist of the Archives|C|SIR +#144|Gryff's Boon|U|SIR +#145|Hinterland Logger|C|SIR +#146|Mercurial Geists|U|SIR +#147|Olivia's Dragoon|C|SIR +#148|Port Town|U|SIR +#149|Reaper of Flight Moonsilver|U|SIR +#150|Ride Down|U|SIR +#151|Thermo-Alchemist|U|SIR +#152|Thraben Foulbloods|C|SIR +#153|Town Gossipmonger|U|SIR +#154|Traverse the Ulvenwald|R|SIR +#155|Wretched Gryff|C|SIR +#156|Apothecary Geist|C|SIR +#157|Ember-Eye Wolf|C|SIR +#158|Fevered Visions|R|SIR +#159|Forsaken Sanctuary|U|SIR +#160|Foul Orchard|U|SIR +#161|Groundskeeper|U|SIR +#162|Hamlet Captain|U|SIR +#163|Highland Lake|U|SIR +#164|Howlpack Wolf|C|SIR +#165|Midnight Scavengers|U|SIR +#166|Ruthless Disposal|U|SIR +#167|Stone Quarry|U|SIR +#168|Woodland Stream|U|SIR +#169|Byway Courier|C|SIR +#170|Curious Homunculus|U|SIR +#171|Eternal Scourge|R|SIR +#172|Ghoulcaller's Accomplice|C|SIR +#173|Graf Rats|C|SIR +#174|Guardian of Pilgrims|C|SIR +#175|Hanweir Battlements|R|SIR +#176|Pyre Hound|C|SIR +#177|Ravenous Bloodseeker|C|SIR +#178|Rise from the Grave|U|SIR +#179|Steadfast Cathar|C|SIR +#180|Stitcher's Graft|R|SIR +#181|Stormrider Spirit|C|SIR +#182|Confirm Suspicions|R|SIR +#183|Dawn Gryff|C|SIR +#184|Devilthorn Fox|C|SIR +#185|Eldritch Evolution|R|SIR +#186|Exultant Cultist|C|SIR +#187|Faith Unbroken|U|SIR +#188|Falkenrath Gorger|R|SIR +#189|Gatstaf Arsonists|C|SIR +#190|Intrepid Provisioner|C|SIR +#191|Neglected Heirloom|U|SIR +#192|Rush of Adrenaline|C|SIR +#193|Sage of Ancient Lore|R|SIR +#194|Thing in the Ice|R|SIR +#195|Vessel of Nascency|U|SIR +#196|Village Messenger|U|SIR +#197|Weirded Vampire|C|SIR +#198|Cryptolith Rite|R|SIR +#199|Drogskol Shieldmate|C|SIR +#200|Gavony Unhallowed|C|SIR +#201|Insolent Neonate|C|SIR +#202|Liliana's Elite|C|SIR +#203|Magnifying Glass|C|SIR +#204|Mausoleum Wanderer|R|SIR +#205|Morkrut Necropod|C|SIR +#206|Permeating Mass|R|SIR +#207|Sanitarium Skeleton|C|SIR +#208|Swift Spinner|C|SIR +#209|Tattered Haunter|C|SIR +#210|Tormenting Voice|C|SIR +#211|Dusk Feaster|U|SIR +#212|Explosive Apparatus|C|SIR +#213|Field Creeper|C|SIR +#214|Grapple with the Past|C|SIR +#215|Humble the Brute|U|SIR +#216|Jace's Scrutiny|C|SIR +#217|Moonlight Hunt|C|SIR +#218|Strength of Arms|C|SIR +#219|Thornhide Wolves|C|SIR +#220|Weirding Wood|C|SIR +#221|Abundant Maw|U|SIR +#222|Epitaph Golem|C|SIR +#223|Fogwalker|C|SIR +#224|Graf Harvest|U|SIR +#225|Ironclad Slayer|U|SIR +#226|Laboratory Brute|C|SIR +#227|Make Mischief|C|SIR +#228|Mockery of Nature|U|SIR +#229|Rise from the Tides|U|SIR +#230|Borrowed Grace|C|SIR +#231|Borrowed Malevolence|C|SIR +#232|Confront the Unknown|C|SIR +#233|Grotesque Mutation|C|SIR +#234|Harvest Hand|U|SIR +#235|Lupine Prototype|U|SIR +#236|Spontaneous Mutation|C|SIR +#237|Aim High|C|SIR +#238|Biting Rain|U|SIR +#239|Borrowed Hostility|C|SIR +#240|Fiend Binder|C|SIR +#241|Fleeting Memories|U|SIR +#242|Macabre Waltz|C|SIR +#243|Murderer's Axe|U|SIR +#244|Summary Dismissal|R|SIR +#245|Terrarion|C|SIR +#246|True-Faith Censer|C|SIR +#247|Uncaged Fury|U|SIR +#248|Wild-Field Scarecrow|C|SIR +#249|Blood Mist|U|SIR +#250|Convolute|C|SIR +#251|Crawling Sensation|U|SIR +#252|Epiphany at the Drownyard|R|SIR +#253|Hope Against Hope|U|SIR +#254|Howlpack Resurgence|U|SIR +#255|Lunarch Mantle|C|SIR +#256|Magmatic Chasm|C|SIR +#257|Faithbearer Paladin|C|SIR +#258|Merciless Resolve|C|SIR +#259|Shreds of Sanity|U|SIR +#260|Soul Separator|U|SIR +#261|Take Inventory|C|SIR +#262|Indulgent Aristocrat|U|SIR +#263|Stensia Masquerade|U|SIR +#264|Manic Scribe|U|SIR +#265|Pick the Brain|U|SIR +#266|Pieces of the Puzzle|U|SIR +#267|Splendid Reclamation|R|SIR +#268|Wolfkin Bond|C|SIR +#269|Deny Existence|C|SIR +#270|Essence Flux|C|SIR +#271|Second Harvest|R|SIR +#272|Mind's Dilation|M|SIR +#273|Alms of the Vein|C|SIR +#274|Invasive Surgery|U|SIR +#275|Sigarda's Aid|R|SIR +#276|Brain in a Jar|U|SIR +#277|Plains 1|C|SIR +#278|Island 1|C|SIR +#279|Swamp 1|C|SIR +#280|Mountain 1|C|SIR +#281|Forest 1|C|SIR +#282|Plains 2|C|SIR +#283|Island 2|C|SIR +#284|Swamp 2|C|SIR +#285|Mountain 2|C|SIR +#286|Forest 2|C|SIR +#287|Plains 3|C|SIR +#288|Island 3|C|SIR +#289|Swamp 3|C|SIR +#290|Mountain 3|C|SIR +#291|Forest 3|C|SIR +//Rank|Name|Rarity|Set +#1|The Eternal Wanderer|R|ONE +#2|White Sun's Twilight|R|ONE +#3|Nissa, Ascended Animist|M|ONE +#4|Kaya, Intangible Slayer|R|ONE +#5|Thrun, Breaker of Silence|R|ONE +#6|Glissa Sunslayer|R|ONE +#7|Blue Sun's Twilight|R|ONE +#8|Vraska, Betrayal's Sting|M|ONE +#9|Black Sun's Twilight|R|ONE +#10|Dragonwing Glider|R|ONE +#11|Atraxa, Grand Unifier|M|ONE +#12|Kaito, Dancing Shadow|R|ONE +#13|Lukka, Bound to Ruin|M|ONE +#14|Sword of Forge and Frontier|M|ONE +#15|Tekuthal, Inquiry Dominus|M|ONE +#16|Bloated Contaminator|R|ONE +#17|Tyrranax Rex|M|ONE +#18|Zopandrel, Hunger Dominus|M|ONE +#19|Jace, the Perfected Mind|M|ONE +#20|Archfiend of the Dross|R|ONE +#21|Solphim, Mayhem Dominus|M|ONE +#22|Elesh Norn, Mother of Machines|M|ONE +#23|Mondrak, Glory Dominus|M|ONE +#24|Ria Ivor, Bane of Bladehold|R|ONE +#25|Phyrexian Vindicator|M|ONE +#26|Mercurial Spelldancer|R|ONE +#27|Phyrexian Obliterator|M|ONE +#28|All Will Be One|M|ONE #29|Capricious Hellraiser|M|ONE -#30|Skrelv's Hive|R|ONE -#31|Unctus, Grand Metatect|R|ONE -#32|Archfiend of the Dross|R|ONE -#33|Drivnod, Carnage Dominus|M|ONE -#34|Drown in Ichor|U|ONE -#35|Nahiri, the Unforgiving|M|ONE -#36|Ria Ivor, Bane of Bladehold|R|ONE -#37|Vivisection Evangelist|U|ONE -#38|Ossification|U|ONE -#39|Evolved Spinoderm|R|ONE -#40|Jor Kadeen, First Goldwarden|R|ONE -#41|Migloz, Maze Crusher|R|ONE -#42|Venser, Corpse Puppet|R|ONE -#43|Infested Fleshcutter|U|ONE -#44|Skrelv, Defector Mite|R|ONE +#30|Evolved Spinoderm|R|ONE +#31|Cinderslash Ravager|U|ONE +#32|Migloz, Maze Crusher|R|ONE +#33|Ovika, Enigma Goliath|R|ONE +#34|Kemba, Kha Enduring|R|ONE +#35|Ossification|U|ONE +#36|Skrelv, Defector Mite|R|ONE +#37|Skrelv's Hive|R|ONE +#38|Unctus's Retrofitter|U|ONE +#39|Drown in Ichor|U|ONE +#40|Vraan, Executioner Thane|R|ONE +#41|Ezuri, Stalker of Spheres|R|ONE +#42|Trawler Drake|U|ONE +#43|Unctus, Grand Metatect|R|ONE +#44|Koth, Fire of Resistance|R|ONE #45|Rebel Salvo|U|ONE -#46|Venomous Brutalizer|U|ONE -#47|Tablet of Compleation|R|ONE -#48|Jawbone Duelist|U|ONE -#49|Kemba, Kha Enduring|R|ONE -#50|Serum Snare|U|ONE -#51|Annihilating Glare|C|ONE -#52|Vraan, Executioner Thane|R|ONE -#53|Hexgold Halberd|U|ONE -#54|Koth, Fire of Resistance|R|ONE -#55|Volt Charge|C|ONE -#56|Contagious Vorrac|C|ONE -#57|Infectious Bite|U|ONE -#58|Viral Spawning|U|ONE -#59|Voidwing Hybrid|U|ONE -#60|Annex Sentry|U|ONE -#61|Bladed Ambassador|U|ONE -#62|Planar Disruption|C|ONE -#63|Tamiyo's Immobilizer|U|ONE -#64|Nimraiser Paladin|U|ONE -#65|Scheming Aspirant|U|ONE -#66|Urabrask's Anointer|U|ONE -#67|Armored Scrapgorger|U|ONE -#68|Charforger|U|ONE -#69|Melira, the Living Cure|R|ONE -#70|Serum-Core Chimera|U|ONE -#71|Tainted Observer|U|ONE -#72|Mesmerizing Dose|C|ONE -#73|Thrummingbird|U|ONE -#74|Unctus's Retrofitter|U|ONE -#75|Anoint with Affliction|C|ONE -#76|Geth, Thane of Contracts|R|ONE -#77|Phyrexian Arena|R|ONE -#78|Magmatic Sprinter|U|ONE -#79|Urabrask's Forge|R|ONE -#80|Cankerbloom|U|ONE -#81|Evolving Adaptive|U|ONE -#82|Ruthless Predation|C|ONE -#83|Tyvar's Stand|U|ONE -#84|Bladehold War-Whip|U|ONE -#85|Cinderslash Ravager|U|ONE -#86|Malcator, Purity Overseer|R|ONE -#87|Necrogen Rotpriest|U|ONE -#88|Slaughter Singer|U|ONE -#89|The Filigree Sylex|R|ONE -#90|Surgical Skullbomb|C|ONE -#91|Hexgold Hoverwings|U|ONE -#92|Blade of Shared Souls|R|ONE -#93|Trawler Drake|U|ONE -#94|Necrosquito|U|ONE -#95|Sheoldred's Edict|U|ONE -#96|Hexgold Slash|C|ONE -#97|Resistance Skywarden|U|ONE -#98|Slobad, Iron Goblin|R|ONE -#99|Incubation Sac|U|ONE -#100|Oil-Gorger Troll|C|ONE -#101|Kethek, Crucible Goliath|R|ONE -#102|Tyvar, Jubilant Brawler|R|ONE -#103|Graaz, Unstoppable Juggernaut|R|ONE -#104|Ichorplate Golem|U|ONE -#105|Ribskiff|U|ONE -#106|Crawling Chorus|C|ONE -#107|Duelist of Deep Faith|C|ONE -#108|Flensing Raptor|C|ONE -#109|Mandible Justiciar|C|ONE -#110|Porcelain Zealot|U|ONE -#111|Atmosphere Surgeon|U|ONE -#112|Escaped Experiment|C|ONE -#113|Experimental Augury|C|ONE -#114|Malcator's Watcher|C|ONE -#115|Transplant Theorist|U|ONE -#116|Watchful Blisterzoa|U|ONE -#117|Bilious Skulldweller|U|ONE -#118|Karumonix, the Rat King|R|ONE -#119|Barbed Batterfist|C|ONE -#120|Chimney Rabble|C|ONE -#121|Churning Reservoir|U|ONE -#122|Furnace Punisher|U|ONE -#123|Kuldotha Cackler|C|ONE -#124|Molten Rebuke|C|ONE -#125|Vindictive Flamestoker|R|ONE -#126|Adaptive Sporesinger|C|ONE -#127|Branchblight Stalker|C|ONE -#128|Lattice-Blade Mantis|C|ONE -#129|Paladin of Predation|U|ONE -#130|Sylvok Battle-Chair|U|ONE -#131|Thirsting Roots|C|ONE -#132|Venerated Rotpriest|R|ONE -#133|Cephalopod Sentry|U|ONE -#134|Dross Skullbomb|C|ONE -#135|Mirrex|R|ONE -#136|Basilica Shepherd|C|ONE -#137|Leonin Lightbringer|C|ONE -#138|Norn's Wellspring|R|ONE -#139|Chrome Prowler|C|ONE -#140|Distorted Curiosity|U|ONE -#141|Gitaxian Raptor|C|ONE -#142|Quicksilver Fisher|C|ONE -#143|Reject Imperfection|U|ONE -#144|Ambulatory Edifice|U|ONE -#145|Chittering Skitterling|U|ONE -#146|Cutthroat Centurion|C|ONE -#147|Fleshless Gladiator|C|ONE -#148|Gulping Scraptrap|C|ONE -#149|Pestilent Syphoner|C|ONE -#150|Ravenous Necrotitan|U|ONE -#151|Stinging Hivemaster|C|ONE -#152|Vat Emergence|U|ONE -#153|Whisper of the Dross|C|ONE -#154|Awaken the Sleeper|U|ONE -#155|Axiom Engraver|C|ONE -#156|Bladegraft Aspirant|C|ONE -#157|Cacophony Scamp|U|ONE -#158|Exuberant Fuseling|U|ONE -#159|Forgehammer Centurion|C|ONE -#160|Oxidda Finisher|U|ONE -#161|Vulshok Splitter|C|ONE -#162|Green Sun's Twilight|R|ONE -#163|Ichorspit Basilisk|C|ONE -#164|Plague Nurse|C|ONE -#165|Tyrranax Atrocity|C|ONE -#166|Atraxa's Skitterfang|U|ONE -#167|Furnace Skullbomb|C|ONE -#168|Myr Convert|U|ONE -#169|Prophetic Prism|C|ONE -#170|The Autonomous Furnace|C|ONE -#171|The Dross Pits|C|ONE -#172|The Fair Basilica|C|ONE -#173|The Hunter Maze|C|ONE -#174|The Surgical Bay|C|ONE -#175|Apostle of Invasion|U|ONE -#176|Charge of the Mites|C|ONE -#177|Compleat Devotion|C|ONE -#178|Goldwarden's Helm|C|ONE -#179|Indoctrination Attendant|C|ONE -#180|Mirran Bardiche|C|ONE -#181|Sinew Dancer|C|ONE -#182|Swooping Lookout|U|ONE -#183|Bring the Ending|C|ONE -#184|Font of Progress|U|ONE -#185|Gitaxian Anatomist|C|ONE -#186|Meldweb Curator|C|ONE -#187|Tamiyo's Logbook|U|ONE -#188|Vivisurgeon's Insight|C|ONE -#189|Blightbelly Rat|C|ONE -#190|Bonepicker Skirge|C|ONE -#191|Cruel Grimnarch|C|ONE -#192|Feed the Infection|U|ONE -#193|Infectious Inquiry|C|ONE -#194|Necrogen Communion|U|ONE -#195|Sheoldred's Headcleaver|C|ONE -#196|Testament Bearer|C|ONE -#197|Vat of Rebirth|U|ONE -#198|All Will Be One|M|ONE -#199|Free from Flesh|C|ONE -#200|Furnace Strider|C|ONE -#201|Shrapnel Slinger|C|ONE -#202|Thrill of Possibility|C|ONE -#203|Conduit of Worlds|R|ONE -#204|Noxious Assault|U|ONE -#205|Predation Steward|C|ONE -#206|Rustvine Cultivator|C|ONE -#207|Skyscythe Engulfer|C|ONE -#208|Titanic Growth|C|ONE -#209|Unnatural Restoration|U|ONE -#210|Basilica Skullbomb|C|ONE -#211|Dune Mover|C|ONE -#212|Maze Skullbomb|C|ONE -#213|Phyrexian Atlas|C|ONE -#214|Prosthetic Injector|U|ONE -#215|Blackcleave Cliffs|R|ONE -#216|Copperline Gorge|R|ONE -#217|Darkslick Shores|R|ONE -#218|The Mycosynth Gardens|R|ONE -#219|Razorverge Thicket|R|ONE -#220|Seachrome Coast|R|ONE -#221|Terramorphic Expanse|C|ONE -#222|Against All Odds|U|ONE -#223|Incisor Glider|C|ONE -#224|Orthodoxy Enforcer|C|ONE -#225|Plated Onslaught|U|ONE -#226|Resistance Reunited|U|ONE -#227|Vanish into Eternity|C|ONE -#228|Eye of Malcator|C|ONE -#229|Glistener Seer|C|ONE -#230|Ichor Synthesizer|C|ONE -#231|Meldweb Strider|C|ONE -#232|Vraska's Fall|C|ONE -#233|Blazing Crescendo|C|ONE -#234|Nahiri's Sacrifice|U|ONE -#235|Sawblade Scamp|C|ONE -#236|Copper Longlegs|C|ONE -#237|Maze's Mantle|C|ONE -#238|Monument to Perfection|R|ONE -#239|Myr Custodian|C|ONE -#240|Myr Kinsmith|C|ONE -#241|Zenith Chronicler|R|ONE -#242|Veil of Assimilation|U|ONE -#243|Zealot's Conviction|C|ONE -#244|Aspirant's Ascent|C|ONE -#245|Prologue to Phyresis|C|ONE -#246|Offer Immortality|C|ONE -#247|Gleeful Demolition|U|ONE -#248|Hazardous Blast|C|ONE -#249|Red Sun's Twilight|R|ONE -#250|Expand the Sphere|U|ONE -#251|Staff of Compleation|M|ONE -#252|The Monumental Facade|R|ONE -#253|Ichormoon Gauntlet|M|ONE -#254|Mindsplice Apparatus|R|ONE -#255|The Seedcore|R|ONE -#256|Minor Misstep|U|ONE -#257|Duress|C|ONE -#258|Encroaching Mycosynth|R|ONE -#259|Carnivorous Canopy|C|ONE -#260|Soulless Jailer|R|ONE +#46|Viral Spawning|U|ONE +#47|Bladehold War-Whip|U|ONE +#48|Charforger|U|ONE +#49|Jor Kadeen, First Goldwarden|R|ONE +#50|Serum-Core Chimera|U|ONE +#51|Argentum Masticore|R|ONE +#52|Annex Sentry|U|ONE +#53|Jawbone Duelist|U|ONE +#54|Serum Snare|U|ONE +#55|Anoint with Affliction|C|ONE +#56|Drivnod, Carnage Dominus|M|ONE +#57|Nimraiser Paladin|U|ONE +#58|Scheming Aspirant|U|ONE +#59|Urabrask's Anointer|U|ONE +#60|Urabrask's Forge|R|ONE +#61|Armored Scrapgorger|U|ONE +#62|Evolving Adaptive|U|ONE +#63|Cephalopod Sentry|U|ONE +#64|Malcator, Purity Overseer|R|ONE +#65|Slaughter Singer|U|ONE +#66|Venser, Corpse Puppet|R|ONE +#67|Vivisection Evangelist|U|ONE +#68|The Filigree Sylex|R|ONE +#69|Planar Disruption|C|ONE +#70|Blade of Shared Souls|R|ONE +#71|Thrummingbird|U|ONE +#72|Churning Reservoir|U|ONE +#73|Volt Charge|C|ONE +#74|Cankerbloom|U|ONE +#75|Contagious Vorrac|C|ONE +#76|Incubation Sac|U|ONE +#77|Infectious Bite|U|ONE +#78|Tyvar's Stand|U|ONE +#79|Venomous Brutalizer|U|ONE +#80|Melira, the Living Cure|R|ONE +#81|Nahiri, the Unforgiving|M|ONE +#82|Tainted Observer|U|ONE +#83|Voidwing Hybrid|U|ONE +#84|Atraxa's Skitterfang|U|ONE +#85|Tablet of Compleation|R|ONE +#86|Bladed Ambassador|U|ONE +#87|Tamiyo's Immobilizer|U|ONE +#88|Transplant Theorist|U|ONE +#89|Annihilating Glare|C|ONE +#90|Bilious Skulldweller|U|ONE +#91|Necrosquito|U|ONE +#92|Hexgold Halberd|U|ONE +#93|Hexgold Slash|C|ONE +#94|Oil-Gorger Troll|C|ONE +#95|Ruthless Predation|C|ONE +#96|Necrogen Rotpriest|U|ONE +#97|Hexgold Hoverwings|U|ONE +#98|Mesmerizing Dose|C|ONE +#99|Quicksilver Fisher|C|ONE +#100|Chittering Skitterling|U|ONE +#101|Geth, Thane of Contracts|R|ONE +#102|Karumonix, the Rat King|R|ONE +#103|Phyrexian Arena|R|ONE +#104|Testament Bearer|C|ONE +#105|Vat Emergence|U|ONE +#106|Furnace Strider|C|ONE +#107|Magmatic Sprinter|U|ONE +#108|Oxidda Finisher|U|ONE +#109|Resistance Skywarden|U|ONE +#110|Sylvok Battle-Chair|U|ONE +#111|Graaz, Unstoppable Juggernaut|R|ONE +#112|Ichorplate Golem|U|ONE +#113|Prophetic Prism|C|ONE +#114|Ribskiff|U|ONE +#115|Surgical Skullbomb|C|ONE +#116|Duelist of Deep Faith|C|ONE +#117|Flensing Raptor|C|ONE +#118|Mandible Justiciar|C|ONE +#119|Atmosphere Surgeon|U|ONE +#120|Distorted Curiosity|U|ONE +#121|Experimental Augury|C|ONE +#122|Gitaxian Raptor|C|ONE +#123|Malcator's Watcher|C|ONE +#124|Reject Imperfection|U|ONE +#125|Watchful Blisterzoa|U|ONE +#126|Ambulatory Edifice|U|ONE +#127|Pestilent Syphoner|C|ONE +#128|Ravenous Necrotitan|U|ONE +#129|Sheoldred's Edict|U|ONE +#130|Stinging Hivemaster|C|ONE +#131|Axiom Engraver|C|ONE +#132|Chimney Rabble|C|ONE +#133|Exuberant Fuseling|U|ONE +#134|Free from Flesh|C|ONE +#135|Furnace Punisher|U|ONE +#136|Hazardous Blast|C|ONE +#137|Kuldotha Cackler|C|ONE +#138|Vindictive Flamestoker|R|ONE +#139|Green Sun's Twilight|R|ONE +#140|Lattice-Blade Mantis|C|ONE +#141|Paladin of Predation|U|ONE +#142|Plague Nurse|C|ONE +#143|Rustvine Cultivator|C|ONE +#144|Thirsting Roots|C|ONE +#145|Tyrranax Atrocity|C|ONE +#146|Kethek, Crucible Goliath|R|ONE +#147|Dross Skullbomb|C|ONE +#148|Furnace Skullbomb|C|ONE +#149|Myr Convert|U|ONE +#150|Mirrex|R|ONE +#151|Basilica Shepherd|C|ONE +#152|Charge of the Mites|C|ONE +#153|Compleat Devotion|C|ONE +#154|Incisor Glider|C|ONE +#155|Porcelain Zealot|U|ONE +#156|Swooping Lookout|U|ONE +#157|Bring the Ending|C|ONE +#158|Eye of Malcator|C|ONE +#159|Meldweb Curator|C|ONE +#160|Tamiyo's Logbook|U|ONE +#161|Vivisurgeon's Insight|C|ONE +#162|Blightbelly Rat|C|ONE +#163|Bonepicker Skirge|C|ONE +#164|Sheoldred's Headcleaver|C|ONE +#165|Vraska's Fall|C|ONE +#166|Barbed Batterfist|C|ONE +#167|Bladegraft Aspirant|C|ONE +#168|Cacophony Scamp|U|ONE +#169|Molten Rebuke|C|ONE +#170|Slobad, Iron Goblin|R|ONE +#171|Thrill of Possibility|C|ONE +#172|Branchblight Stalker|C|ONE +#173|Copper Longlegs|C|ONE +#174|Predation Steward|C|ONE +#175|Skyscythe Engulfer|C|ONE +#176|Unnatural Restoration|U|ONE +#177|Venerated Rotpriest|R|ONE +#178|Tyvar, Jubilant Brawler|R|ONE +#179|Basilica Skullbomb|C|ONE +#180|Dune Mover|C|ONE +#181|Maze Skullbomb|C|ONE +#182|The Autonomous Furnace|C|ONE +#183|The Dross Pits|C|ONE +#184|The Fair Basilica|C|ONE +#185|The Hunter Maze|C|ONE +#186|The Surgical Bay|C|ONE +#187|Terramorphic Expanse|C|ONE +#188|Apostle of Invasion|U|ONE +#189|Crawling Chorus|C|ONE +#190|Indoctrination Attendant|C|ONE +#191|Plated Onslaught|U|ONE +#192|Sinew Dancer|C|ONE +#193|Zealot's Conviction|C|ONE +#194|Chrome Prowler|C|ONE +#195|Escaped Experiment|C|ONE +#196|Glistener Seer|C|ONE +#197|Meldweb Strider|C|ONE +#198|Cruel Grimnarch|C|ONE +#199|Cutthroat Centurion|C|ONE +#200|Feed the Infection|U|ONE +#201|Fleshless Gladiator|C|ONE +#202|Gulping Scraptrap|C|ONE +#203|Infectious Inquiry|C|ONE +#204|Necrogen Communion|U|ONE +#205|Whisper of the Dross|C|ONE +#206|Awaken the Sleeper|U|ONE +#207|Blazing Crescendo|C|ONE +#208|Forgehammer Centurion|C|ONE +#209|Red Sun's Twilight|R|ONE +#210|Sawblade Scamp|C|ONE +#211|Shrapnel Slinger|C|ONE +#212|Vulshok Splitter|C|ONE +#213|Adaptive Sporesinger|C|ONE +#214|Carnivorous Canopy|C|ONE +#215|Ichorspit Basilisk|C|ONE +#216|Maze's Mantle|C|ONE +#217|Noxious Assault|U|ONE +#218|Titanic Growth|C|ONE +#219|Phyrexian Atlas|C|ONE +#220|Staff of Compleation|M|ONE +#221|Zenith Chronicler|R|ONE +#222|Blackcleave Cliffs|R|ONE +#223|Copperline Gorge|R|ONE +#224|Darkslick Shores|R|ONE +#225|The Monumental Facade|R|ONE +#226|The Mycosynth Gardens|R|ONE +#227|Razorverge Thicket|R|ONE +#228|Seachrome Coast|R|ONE +#229|The Seedcore|R|ONE +#230|Goldwarden's Helm|C|ONE +#231|Infested Fleshcutter|U|ONE +#232|Leonin Lightbringer|C|ONE +#233|Mirran Bardiche|C|ONE +#234|Orthodoxy Enforcer|C|ONE +#235|Resistance Reunited|U|ONE +#236|Vanish into Eternity|C|ONE +#237|Veil of Assimilation|U|ONE +#238|Aspirant's Ascent|C|ONE +#239|Gitaxian Anatomist|C|ONE +#240|Ichor Synthesizer|C|ONE +#241|Prologue to Phyresis|C|ONE +#242|Offer Immortality|C|ONE +#243|Vat of Rebirth|U|ONE +#244|Nahiri's Sacrifice|U|ONE +#245|Conduit of Worlds|R|ONE +#246|Expand the Sphere|U|ONE +#247|Monument to Perfection|R|ONE +#248|Myr Custodian|C|ONE +#249|Myr Kinsmith|C|ONE +#250|Prosthetic Injector|U|ONE +#251|Against All Odds|U|ONE +#252|Norn's Wellspring|R|ONE +#253|Font of Progress|U|ONE +#254|Gleeful Demolition|U|ONE +#255|Ichormoon Gauntlet|M|ONE +#256|Mindsplice Apparatus|R|ONE +#257|Minor Misstep|U|ONE +#258|Duress|C|ONE +#259|Soulless Jailer|R|ONE +#260|Encroaching Mycosynth|R|ONE #261|Mirran Safehouse|R|ONE #262|Plains 1|C|ONE #263|Island 1|C|ONE diff --git a/forge-gui/res/editions/March of the Machine Commander.txt b/forge-gui/res/editions/March of the Machine Commander.txt index 1dc91ca3ef3..5e9b3ea18a2 100644 --- a/forge-gui/res/editions/March of the Machine Commander.txt +++ b/forge-gui/res/editions/March of the Machine Commander.txt @@ -9,7 +9,7 @@ ScryfallCode=MOC 67 C Towashi @Kamila Szutenberg 147 C Isle of Vesuva @Zoltan Boros & Gabor Szikszai 158 C Spatial Merging @Gabor Szikszai -445 M Goro-Goro and Satoru @Johannes Mücke +445 M Goro-Goro and Satoru @Johannes Voss 446 M Katilda and Lier @Justyna Dura 447 M Slimefoot and Squee @Victor Adame Minguez 448 M Goro-Goro and Satoru @Yamada Rokkaku diff --git a/forge-gui/res/editions/March of the Machine.txt b/forge-gui/res/editions/March of the Machine.txt index 0813565cc8d..8718dae384c 100644 --- a/forge-gui/res/editions/March of the Machine.txt +++ b/forge-gui/res/editions/March of the Machine.txt @@ -23,7 +23,7 @@ ScryfallCode=MOM 270 C Jungle Hollow @Thomas Stoop 271 C Rugged Highlands @Thomas Stoop 272 C Scoured Barrens @Robin Olausson -273 M Swiftwater Cliffs @Julian Kok Joon Wen +273 C Swiftwater Cliffs @Julian Kok Joon Wen 274 C Thornwood Falls @Roman Kuteynikov 275 C Tranquil Cove @Chris Ostrowski 276 C Wind-Scarred Crag @Roman Kuteynikov @@ -38,4 +38,4 @@ ScryfallCode=MOM 352 R Faerie Mastermind @Joshua Raphael 358 R Breach the Multiverse @Liiga Smilshkalne 386 R Ghalta and Mavren @Betty Jiang -387 R Omnath, Locus of All @Jessica Rossier +387 R Omnath, Locus of All @Helge C. Balzer diff --git a/forge-gui/res/editions/Shadows over Innistrad Remastered.txt b/forge-gui/res/editions/Shadows over Innistrad Remastered.txt index 900a6c61d8f..8ba7ea1c6a5 100644 --- a/forge-gui/res/editions/Shadows over Innistrad Remastered.txt +++ b/forge-gui/res/editions/Shadows over Innistrad Remastered.txt @@ -3,6 +3,10 @@ Code=SIR Date=2023-03-21 Name=Shadows over Innistrad Remastered Type=Online +BoosterCovers=3 +Booster=10 Common:fromsheet("SIR cards"), 3 Uncommon:fromSheet("SIR cards"), 1 RareMythic:fromSheet("SIR cards"), 1 BasicLand:fromSheet("SIR cards") +Prerelease=6 Boosters, 1 RareMythic+ +BoosterBox=36 ScryfallCode=SIR [cards] diff --git a/forge-gui/res/sound/button_press.mp3 b/forge-gui/res/sound/button_press.mp3 new file mode 100644 index 00000000000..1f56bbde7ba Binary files /dev/null and b/forge-gui/res/sound/button_press.mp3 differ diff --git a/forge-gui/res/sound/coins_drop.mp3 b/forge-gui/res/sound/coins_drop.mp3 new file mode 100644 index 00000000000..44dbd60e00a Binary files /dev/null and b/forge-gui/res/sound/coins_drop.mp3 differ diff --git a/forge-gui/res/sound/flip_card.mp3 b/forge-gui/res/sound/flip_card.mp3 new file mode 100644 index 00000000000..7af06b29cf5 Binary files /dev/null and b/forge-gui/res/sound/flip_card.mp3 differ diff --git a/forge-gui/res/sound/take_shard.mp3 b/forge-gui/res/sound/take_shard.mp3 new file mode 100644 index 00000000000..14e6b85b385 Binary files /dev/null and b/forge-gui/res/sound/take_shard.mp3 differ diff --git a/forge-gui/src/main/java/forge/gamemodes/match/HostedMatch.java b/forge-gui/src/main/java/forge/gamemodes/match/HostedMatch.java index 2fd44a8cd74..870cfffa79d 100644 --- a/forge-gui/src/main/java/forge/gamemodes/match/HostedMatch.java +++ b/forge-gui/src/main/java/forge/gamemodes/match/HostedMatch.java @@ -62,6 +62,7 @@ public class HostedMatch { private Match match; private Game game; private String title; + private MusicPlaylist matchPlaylist = null; public HashMap gameControllers = null; private Runnable startGameHook = null; private Runnable endGameHook = null; @@ -97,12 +98,12 @@ public class HostedMatch { startMatch(getDefaultRules(gameType), appliedVariants, players, human, gui); } public void startMatch(final GameType gameType, final Set appliedVariants, final List players, final Map guis) { - startMatch(getDefaultRules(gameType), appliedVariants, players, guis); + startMatch(getDefaultRules(gameType), appliedVariants, players, guis, null); } public void startMatch(final GameRules gameRules, final Set appliedVariants, final List players, final RegisteredPlayer human, final IGuiGame gui) { - startMatch(gameRules, appliedVariants, players, human == null || gui == null ? null : ImmutableMap.of(human, gui)); + startMatch(gameRules, appliedVariants, players, human == null || gui == null ? null : ImmutableMap.of(human, gui), null); } - public void startMatch(final GameRules gameRules, final Set appliedVariants, final List players, final Map guis) { + public void startMatch(final GameRules gameRules, final Set appliedVariants, final List players, final Map guis, final MusicPlaylist playlist) { if (gameRules == null || gameRules.getGameType() == null || players == null || players.isEmpty()) { throw new IllegalArgumentException(); } @@ -135,6 +136,7 @@ public class HostedMatch { this.match = new Match(gameRules, sortedPlayers, title); this.match.subscribeToEvents(SoundSystem.instance); this.match.subscribeToEvents(visitor); + this.matchPlaylist = playlist; startGame(); } @@ -145,12 +147,12 @@ public class HostedMatch { public void restartMatch() { endCurrentGame(); - startMatch(match.getRules(), null, match.getPlayers(), this.guis); + startMatch(match.getRules(), null, match.getPlayers(), this.guis, this.matchPlaylist); } public void startGame() { nextGameDecisions.clear(); - SoundSystem.instance.setBackgroundMusic(MusicPlaylist.MATCH); + SoundSystem.instance.setBackgroundMusic(this.matchPlaylist == null ? MusicPlaylist.MATCH : this.matchPlaylist); game = match.createGame(); diff --git a/forge-gui/src/main/java/forge/gamemodes/quest/QuestUtil.java b/forge-gui/src/main/java/forge/gamemodes/quest/QuestUtil.java index ed1d39f9a2c..26bbf0fe0b9 100644 --- a/forge-gui/src/main/java/forge/gamemodes/quest/QuestUtil.java +++ b/forge-gui/src/main/java/forge/gamemodes/quest/QuestUtil.java @@ -612,7 +612,7 @@ public class QuestUtil { FThreads.invokeInEdtNowOrLater(new Runnable(){ @Override public void run() { - hostedMatch.startMatch(rules, variant, starter, ImmutableMap.of(humanStart, gui)); + hostedMatch.startMatch(rules, variant, starter, ImmutableMap.of(humanStart, gui), null); } }); } diff --git a/forge-gui/src/main/java/forge/sound/EventVisualizer.java b/forge-gui/src/main/java/forge/sound/EventVisualizer.java index 0f41ff1f5a0..709ca1dda58 100644 --- a/forge-gui/src/main/java/forge/sound/EventVisualizer.java +++ b/forge-gui/src/main/java/forge/sound/EventVisualizer.java @@ -16,6 +16,7 @@ import forge.game.event.GameEventCardDestroyed; import forge.game.event.GameEventCardPhased; import forge.game.event.GameEventCardRegenerated; import forge.game.event.GameEventCardSacrificed; +import forge.game.event.GameEventCardStatsChanged; import forge.game.event.GameEventCardTapped; import forge.game.event.GameEventDayTimeChanged; import forge.game.event.GameEventFlipCoin; @@ -77,6 +78,12 @@ public class EventVisualizer extends IGameEventVisitor.Base imp return to == ZoneType.Exile ? SoundEffectType.Exile : null; } + + @Override + public SoundEffectType visit(GameEventCardStatsChanged event) { + return event.transform ? SoundEffectType.FlipCard : null ; + } + @Override public SoundEffectType visit(final GameEventCardRegenerated event) { return SoundEffectType.Regen; } @Override diff --git a/forge-gui/src/main/java/forge/sound/MusicPlaylist.java b/forge-gui/src/main/java/forge/sound/MusicPlaylist.java index 5b6657bf28f..a884302fd2d 100644 --- a/forge-gui/src/main/java/forge/sound/MusicPlaylist.java +++ b/forge-gui/src/main/java/forge/sound/MusicPlaylist.java @@ -14,6 +14,7 @@ public enum MusicPlaylist { CASTLE ("castle/"), CAVE ("cave/"), TOWN ("town/"), + BOSS ("boss/"), MENUS ("menus/"), MATCH ("match/"); @@ -65,4 +66,27 @@ public enum MusicPlaylist { return SoundSystem.instance.getMusicDirectory() + subDir + filenames[mostRecentTrackIdx]; } + + public String getNewRandomFilename() { + String[] music; + try { + FilenameFilter filter = new FilenameFilter(){ + @Override + public boolean accept(File file, String name) { + return name.endsWith(".mp3") || name.endsWith(".wav") || name.endsWith(".m4a"); + } + }; + music = new File(SoundSystem.instance.getMusicDirectory() + subDir).list(filter); + if (music == null) + return null; + } + catch (Exception e) { + return null; + } + if (music.length == 0) + return null; + + int index = MyRandom.getRandom().nextInt(music.length); + return SoundSystem.instance.getMusicDirectory() + subDir + music[index]; + } } diff --git a/forge-gui/src/main/java/forge/sound/SoundEffectType.java b/forge-gui/src/main/java/forge/sound/SoundEffectType.java index b7f057c8645..c75d5431de9 100644 --- a/forge-gui/src/main/java/forge/sound/SoundEffectType.java +++ b/forge-gui/src/main/java/forge/sound/SoundEffectType.java @@ -48,6 +48,8 @@ public enum SoundEffectType { BlueBlackLand("blue_black_land.mp3", false), BlueBlackRedLand("blue_black_red_land.mp3", false), BlueLand("blue_land.mp3", false), + ButtonPress("button_press.mp3", false), + CoinsDrop("coins_drop.mp3", false), Creature("creature.mp3", false), Damage("damage.mp3", true), Daytime("daytime.mp3", true), @@ -58,6 +60,7 @@ public enum SoundEffectType { EndOfTurn("end_of_turn.mp3", false), Equip("equip.mp3", false), Exile("exile.mp3", false), + FlipCard("flip_card.mp3", false), FlipCoin("flip_coin.mp3", false), GreenBlackBlueLand("green_black_blue_land.mp3", false), GreenBlackLand("green_black_land.mp3", false), @@ -86,6 +89,7 @@ public enum SoundEffectType { ScriptedEffect("", false), // Plays the effect defined by SVar:SoundEffect Shuffle("shuffle.mp3", false), Sorcery("sorcery.mp3", false), + TakeShard("take_shard.mp3", false), StartDuel("start_duel.mp3",false), Tap("tap.mp3", false), Token("token.mp3", true),