From b6c0d869455fd00c6404714ccac178fe26a2a8ed Mon Sep 17 00:00:00 2001 From: Fulgur14 <54345051+Fulgur14@users.noreply.github.com> Date: Fri, 11 Jul 2025 17:29:53 +0200 Subject: [PATCH 1/8] Sami's Curiosity (EOE) (#8005) --- forge-gui/res/cardsfolder/upcoming/bioengineered_future.txt | 4 ++-- forge-gui/res/cardsfolder/upcoming/samis_curiosity.txt | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 forge-gui/res/cardsfolder/upcoming/samis_curiosity.txt diff --git a/forge-gui/res/cardsfolder/upcoming/bioengineered_future.txt b/forge-gui/res/cardsfolder/upcoming/bioengineered_future.txt index e0069f3c006..45ce7c8c1d7 100644 --- a/forge-gui/res/cardsfolder/upcoming/bioengineered_future.txt +++ b/forge-gui/res/cardsfolder/upcoming/bioengineered_future.txt @@ -1,10 +1,10 @@ Name:Bioengineered Future ManaCost:1 G G Types:Enchantment -T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigToken | TriggerDescription$ When this enchantment enters, create a Lander token. +T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigToken | TriggerDescription$ When this enchantment enters, create a Lander token. (It's an artifact with "{2}, {T}, Sacrifice this token: Search your library for a basic land card, put it onto the battlefield tapped, then shuffle.") SVar:TrigToken:DB$ Token | TokenAmount$ 1 | TokenScript$ c_a_lander_sac_search | TokenOwner$ You K:ETBReplacement:Other:AddExtraCounter:Mandatory:Battlefield:Creature.YouCtrl SVar:AddExtraCounter:DB$ PutCounter | ETB$ True | Defined$ ReplacedCard | CounterType$ P1P1 | CounterNum$ X | SpellDescription$ Each creature you control enters with an additional +1/+1 counter on it for each land that entered the battlefield under your control this turn. SVar:X:Count$ThisTurnEntered_Battlefield_Land.YouCtrl DeckHas:Ability$Counters -Oracle:When this enchantment enters, create a Lander token.\nEach creature you control enters with an additional +1/+1 counter on it for each land that entered the battlefield under your control this turn. \ No newline at end of file +Oracle:When this enchantment enters, create a Lander token. (It's an artifact with "{2}, {T}, Sacrifice this token: Search your library for a basic land card, put it onto the battlefield tapped, then shuffle.")\nEach creature you control enters with an additional +1/+1 counter on it for each land that entered the battlefield under your control this turn. diff --git a/forge-gui/res/cardsfolder/upcoming/samis_curiosity.txt b/forge-gui/res/cardsfolder/upcoming/samis_curiosity.txt new file mode 100644 index 00000000000..2ff4f175bfe --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/samis_curiosity.txt @@ -0,0 +1,6 @@ +Name:Sami's Curiosity +ManaCost:G +Types:Instant +A:SP$ GainLife | LifeAmount$ 2 | SubAbility$ DBToken | SpellDescription$ You gain 2 life. Create a Lander token. (It's an artifact with "{2}, {T}, Sacrifice this token: Search your library for a basic land card, put it onto the battlefield tapped, then shuffle.") +SVar:DBToken:DB$ Token | TokenAmount$ 1 | TokenScript$ c_a_lander_sac_search | TokenOwner$ You +Oracle:You gain 2 life. Create a Lander token. (It's an artifact with "{2}, {T}, Sacrifice this token: Search your library for a basic land card, put it onto the battlefield tapped, then shuffle.") From 891a098d2ac82c5bff81a45725660555c108a301 Mon Sep 17 00:00:00 2001 From: Jetz Date: Tue, 1 Jul 2025 09:03:48 -0400 Subject: [PATCH 2/8] Per-plane configs --- forge-gui-mobile/src/forge/adventure/util/Config.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/forge-gui-mobile/src/forge/adventure/util/Config.java b/forge-gui-mobile/src/forge/adventure/util/Config.java index c9a55d71215..9e4238cd49f 100644 --- a/forge-gui-mobile/src/forge/adventure/util/Config.java +++ b/forge-gui-mobile/src/forge/adventure/util/Config.java @@ -111,9 +111,12 @@ public class Config { currentConfig = this; if (FModel.getPreferences() != null) Lang = FModel.getPreferences().getPref(ForgePreferences.FPref.UI_LANGUAGE); + FileHandle file = new FileHandle(prefix + "config.json"); + //TODO: Plane's config file should be merged with the common config file. + if(!file.exists()) + file = new FileHandle(commonPrefix + "config.json"); try { - configData = new Json().fromJson(ConfigData.class, new FileHandle(commonPrefix + "config.json")); - + configData = new Json().fromJson(ConfigData.class, file); } catch (Exception e) { e.printStackTrace(); configData = new ConfigData(); From 40f168bf1ef7a7ab650ba68db2b21d4379355bc9 Mon Sep 17 00:00:00 2001 From: Jetz Date: Tue, 1 Jul 2025 09:07:08 -0400 Subject: [PATCH 3/8] Add restrictedEvents support to config. --- .../adventure/data/AdventureEventData.java | 36 +++++++++---------- .../src/forge/adventure/data/ConfigData.java | 1 + forge-gui/res/adventure/common/config.json | 12 ++++++- 3 files changed, 29 insertions(+), 20 deletions(-) diff --git a/forge-gui-mobile/src/forge/adventure/data/AdventureEventData.java b/forge-gui-mobile/src/forge/adventure/data/AdventureEventData.java index eafd98fb022..7186ace20c2 100644 --- a/forge-gui-mobile/src/forge/adventure/data/AdventureEventData.java +++ b/forge-gui-mobile/src/forge/adventure/data/AdventureEventData.java @@ -323,24 +323,31 @@ public class AdventureEventData implements Serializable { private CardBlock pickWeightedCardBlock() { CardEdition.Collection editions = FModel.getMagicDb().getEditions(); + ConfigData configData = Config.instance().getConfigData(); Iterable src = FModel.getBlocks(); //all blocks Predicate filter = CardEdition.Predicates.CAN_MAKE_BOOSTER.and(selectSetPool()); + + if(configData.restrictedEvents != null) { + //Temporary restriction until rewards are more diverse - don't want to award restricted cards so these editions need different rewards added. + //Also includes sets that use conspiracy or commander drafts. + Set restrictedEvents = Set.of(configData.restrictedEvents); + filter = filter.and((q) -> !restrictedEvents.contains(q.getCode())); + } + if (configData.allowedEditions != null) { + Set allowed = Set.of(configData.allowedEditions); + filter = filter.and(q -> allowed.contains(q.getName())); + } else { + List restrictedList = Arrays.asList(configData.restrictedEditions); + Set restricted = new HashSet<>(restrictedList); //Would use Set.of but that throws an error if there's any duplicates, and users edit these lists all the time. + filter = filter.and(q -> !restricted.contains(q.getName())); + } + List allEditions = new ArrayList<>(); StreamUtil.stream(editions) .filter(filter) .filter(CardEdition::hasBoosterTemplate) .forEach(allEditions::add); - //Temporary restriction until rewards are more diverse - don't want to award restricted cards so these editions need different rewards added. - List restrictedDrafts = new ArrayList<>(); - restrictedDrafts.add("LEA"); - restrictedDrafts.add("LEB"); - restrictedDrafts.add("2ED"); - restrictedDrafts.add("30A"); - restrictedDrafts.add("CNS"); - restrictedDrafts.add("CN2"); - allEditions.removeIf(q -> restrictedDrafts.contains(q.getCode())); - List legalBlocks = new ArrayList<>(); for (CardBlock b : src) { // for each block if (b.getSets().isEmpty() || (b.getCntBoostersDraft() < 1)) @@ -383,15 +390,6 @@ public class AdventureEventData implements Serializable { } } - ConfigData configData = Config.instance().getConfigData(); - if (configData.allowedEditions != null) { - List allowed = Arrays.asList(configData.allowedEditions); - legalBlocks.removeIf(q -> !allowed.contains(q.getName())); - } else { - for (String restricted : configData.restrictedEditions) { - legalBlocks.removeIf(q -> q.getName().equals(restricted)); - } - } return legalBlocks.isEmpty() ? null : Aggregates.random(legalBlocks); } diff --git a/forge-gui-mobile/src/forge/adventure/data/ConfigData.java b/forge-gui-mobile/src/forge/adventure/data/ConfigData.java index 453affb632e..12623ce5b97 100644 --- a/forge-gui-mobile/src/forge/adventure/data/ConfigData.java +++ b/forge-gui-mobile/src/forge/adventure/data/ConfigData.java @@ -23,4 +23,5 @@ public class ConfigData { public String[] restrictedCards; public String[] restrictedEditions; public String[] allowedEditions; + public String[] restrictedEvents; } diff --git a/forge-gui/res/adventure/common/config.json b/forge-gui/res/adventure/common/config.json index 53bcaf76a99..09f97b41f22 100644 --- a/forge-gui/res/adventure/common/config.json +++ b/forge-gui/res/adventure/common/config.json @@ -85,9 +85,19 @@ "UND", "PUST", "DA1", - "UST", "UNF" ], + "restrictedEvents": [ + "LEA", + "LEB", + "2ED", + "30A", + "CNS", + "CN2", + "CMR", + "CLB", + "CMM" + ], "difficulties": [ { "name": "Easy", From 89d1cffc122960fc8f356c685bb899556021a77d Mon Sep 17 00:00:00 2001 From: Jetz Date: Tue, 1 Jul 2025 09:07:35 -0400 Subject: [PATCH 4/8] Add allowedJumpstart support to config. --- .../src/forge/adventure/data/AdventureEventData.java | 8 ++++++-- forge-gui-mobile/src/forge/adventure/data/ConfigData.java | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/forge-gui-mobile/src/forge/adventure/data/AdventureEventData.java b/forge-gui-mobile/src/forge/adventure/data/AdventureEventData.java index 7186ace20c2..d1dc0a99830 100644 --- a/forge-gui-mobile/src/forge/adventure/data/AdventureEventData.java +++ b/forge-gui-mobile/src/forge/adventure/data/AdventureEventData.java @@ -403,8 +403,12 @@ public class AdventureEventData implements Serializable { } } ConfigData configData = Config.instance().getConfigData(); - if (configData.allowedEditions != null) { - List allowed = Arrays.asList(configData.allowedEditions); + if (configData.allowedJumpstart != null) { + Set allowed = Set.of(configData.allowedJumpstart); + legalBlocks.removeIf(q -> !allowed.contains(q.getName())); + } + else if (configData.allowedEditions != null) { + Set allowed = Set.of(configData.allowedEditions); legalBlocks.removeIf(q -> !allowed.contains(q.getName())); } else { for (String restricted : configData.restrictedEditions) { diff --git a/forge-gui-mobile/src/forge/adventure/data/ConfigData.java b/forge-gui-mobile/src/forge/adventure/data/ConfigData.java index 12623ce5b97..c5b2a78ba32 100644 --- a/forge-gui-mobile/src/forge/adventure/data/ConfigData.java +++ b/forge-gui-mobile/src/forge/adventure/data/ConfigData.java @@ -24,4 +24,5 @@ public class ConfigData { public String[] restrictedEditions; public String[] allowedEditions; public String[] restrictedEvents; + public String[] allowedJumpstart; } From eea9890f9d71472f1732c1b79c166a49445c6786 Mon Sep 17 00:00:00 2001 From: Jetz Date: Wed, 2 Jul 2025 08:57:19 -0400 Subject: [PATCH 5/8] Change allowedJumpstart to override default selection. --- .../adventure/data/AdventureEventData.java | 32 +++++++++++-------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/forge-gui-mobile/src/forge/adventure/data/AdventureEventData.java b/forge-gui-mobile/src/forge/adventure/data/AdventureEventData.java index d1dc0a99830..efff7e2c473 100644 --- a/forge-gui-mobile/src/forge/adventure/data/AdventureEventData.java +++ b/forge-gui-mobile/src/forge/adventure/data/AdventureEventData.java @@ -396,23 +396,29 @@ public class AdventureEventData implements Serializable { private CardBlock pickJumpstartCardBlock() { Iterable src = FModel.getBlocks(); //all blocks List legalBlocks = new ArrayList<>(); - for (CardBlock b : src) { // for each block - //I hate doing this, but it seems like the simplest way to reliably filter out prereleases - if (b.getName().toUpperCase().contains("JUMPSTART")) { - legalBlocks.add(b); - } - } ConfigData configData = Config.instance().getConfigData(); if (configData.allowedJumpstart != null) { Set allowed = Set.of(configData.allowedJumpstart); - legalBlocks.removeIf(q -> !allowed.contains(q.getName())); + for (CardBlock b : src) { // for each block + if (allowed.contains(b.getName())) { + legalBlocks.add(b); + } + } } - else if (configData.allowedEditions != null) { - Set allowed = Set.of(configData.allowedEditions); - legalBlocks.removeIf(q -> !allowed.contains(q.getName())); - } else { - for (String restricted : configData.restrictedEditions) { - legalBlocks.removeIf(q -> q.getName().equals(restricted)); + else { + for (CardBlock b : src) { // for each block + //I hate doing this, but it seems like the simplest way to reliably filter out prereleases + if (b.getName().toUpperCase().contains("JUMPSTART")) { + legalBlocks.add(b); + } + } + if (configData.allowedEditions != null) { + Set allowed = Set.of(configData.allowedEditions); + legalBlocks.removeIf(q -> !allowed.contains(q.getName())); + } else { + for (String restricted : configData.restrictedEditions) { + legalBlocks.removeIf(q -> q.getName().equals(restricted)); + } } } return legalBlocks.isEmpty() ? null : Aggregates.random(legalBlocks); From 6fec40522ee5491beaffdb0355d81bb755e03bbf Mon Sep 17 00:00:00 2001 From: Jetz Date: Fri, 4 Jul 2025 09:39:52 -0400 Subject: [PATCH 6/8] Use code instead of name for filtering drafts --- .../src/forge/adventure/data/AdventureEventData.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/forge-gui-mobile/src/forge/adventure/data/AdventureEventData.java b/forge-gui-mobile/src/forge/adventure/data/AdventureEventData.java index efff7e2c473..98f0b603833 100644 --- a/forge-gui-mobile/src/forge/adventure/data/AdventureEventData.java +++ b/forge-gui-mobile/src/forge/adventure/data/AdventureEventData.java @@ -335,11 +335,11 @@ public class AdventureEventData implements Serializable { } if (configData.allowedEditions != null) { Set allowed = Set.of(configData.allowedEditions); - filter = filter.and(q -> allowed.contains(q.getName())); + filter = filter.and(q -> allowed.contains(q.getCode())); } else { List restrictedList = Arrays.asList(configData.restrictedEditions); Set restricted = new HashSet<>(restrictedList); //Would use Set.of but that throws an error if there's any duplicates, and users edit these lists all the time. - filter = filter.and(q -> !restricted.contains(q.getName())); + filter = filter.and(q -> !restricted.contains(q.getCode())); } List allEditions = new ArrayList<>(); From 4e42963033727698c12ee9c3ce95289ff57f3b2f Mon Sep 17 00:00:00 2001 From: Jetz Date: Fri, 4 Jul 2025 09:56:32 -0400 Subject: [PATCH 7/8] Add fantasyBlock support for allowedJumpstart --- .../src/forge/adventure/data/AdventureEventData.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/forge-gui-mobile/src/forge/adventure/data/AdventureEventData.java b/forge-gui-mobile/src/forge/adventure/data/AdventureEventData.java index 98f0b603833..a602a929111 100644 --- a/forge-gui-mobile/src/forge/adventure/data/AdventureEventData.java +++ b/forge-gui-mobile/src/forge/adventure/data/AdventureEventData.java @@ -404,6 +404,11 @@ public class AdventureEventData implements Serializable { legalBlocks.add(b); } } + for (CardBlock b : FModel.getFantasyBlocks()) { + if (allowed.contains(b.getName())) { + legalBlocks.add(b); + } + } } else { for (CardBlock b : src) { // for each block From f2ab574a3b1c21f9c23e2886fa5915f399c3da8c Mon Sep 17 00:00:00 2001 From: Fulgur14 <54345051+Fulgur14@users.noreply.github.com> Date: Fri, 11 Jul 2025 21:22:40 +0200 Subject: [PATCH 8/8] Weftwalking and Monoist Circuit-Feeder (EOE) (#8007) --- .../cardsfolder/upcoming/monoist_circuit_feeder.txt | 11 +++++++++++ forge-gui/res/cardsfolder/upcoming/weftwalking.txt | 9 +++++++++ 2 files changed, 20 insertions(+) create mode 100644 forge-gui/res/cardsfolder/upcoming/monoist_circuit_feeder.txt create mode 100644 forge-gui/res/cardsfolder/upcoming/weftwalking.txt diff --git a/forge-gui/res/cardsfolder/upcoming/monoist_circuit_feeder.txt b/forge-gui/res/cardsfolder/upcoming/monoist_circuit_feeder.txt new file mode 100644 index 00000000000..9edf469710a --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/monoist_circuit_feeder.txt @@ -0,0 +1,11 @@ +Name:Monoist Circuit-Feeder +ManaCost:4 B B +Types:Artifact Creature Nautilus +PT:4/4 +K:Flying +T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigPump | TriggerDescription$ When this creature enters, until end of turn, target creature you control gets +X/+0 and target creature an opponent controls gets -0/-X, where X is the number of artifacts you control. +SVar:TrigPump:DB$ Pump | ValidTgts$ Creature.YouCtrl | TgtPrompt$ Select target creature you control | NumAtt$ +X | SubAbility$ DBPump +SVar:DBPump:DB$ Pump | ValidTgts$ Creature.OppCtrl | TgtPrompt$ Select target creature an opponent controls | NumDef$ -X | IsCurse$ True +SVar:X:Count$Valid Artifact.YouCtrl +SVar:PlayMain1:TRUE +Oracle:Flying\nWhen this creature enters, until end of turn, target creature you control gets +X/+0 and target creature an opponent controls gets -0/-X, where X is the number of artifacts you control. diff --git a/forge-gui/res/cardsfolder/upcoming/weftwalking.txt b/forge-gui/res/cardsfolder/upcoming/weftwalking.txt new file mode 100644 index 00000000000..02382a1f0ea --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/weftwalking.txt @@ -0,0 +1,9 @@ +Name:Weftwalking +ManaCost:4 U U +Types:Enchantment +T:Mode$ ChangesZone | ValidCard$ Card.wasCastByYou+Self | Destination$ Battlefield | Execute$ TrigChangeAll | TriggerDescription$ When this enchantment enters, if you cast it, shuffle your hand and graveyard into your library, then draw seven cards. +SVar:TrigChangeAll:DB$ ChangeZoneAll | Origin$ Graveyard,Hand | Destination$ Library | ChangeType$ Card.YouOwn | Shuffle$ True | SubAbility$ DBDraw +SVar:DBDraw:DB$ Draw | Defined$ You | NumCards$ 7 +S:Mode$ Continuous | Affected$ Card.nonLand+ControlledBy Player.Active | MayPlayPlayer$ Player.Active | MayPlay$ True | MayPlayWithoutManaCost$ True | MayPlayDontGrantZonePermissions$ True | AffectedZone$ All | CheckSVar$ Y | SVarCompare$ EQ0 | Description$ The first spell each player casts during each of their turns may be cast without paying its mana cost. +SVar:Y:Count$ThisTurnCast_Card.ControlledBy Player.Active +Oracle:When this enchantment enters, if you cast it, shuffle your hand and graveyard into your library, then draw seven cards.\nThe first spell each player casts during each of their turns may be cast without paying its mana cost.