From 8c8c8a779bb6b765b42b2ddcebd7c88d00d6f9f9 Mon Sep 17 00:00:00 2001 From: Jetz Date: Fri, 7 Jun 2024 21:36:10 -0400 Subject: [PATCH] AttractionsYouVisitedThisTurn and Squirrel Squatters Untangled some oracle text methods in Card and CardState Sly Spy, Everythingamajig, and two Garbage Elementals Visit card text fix. 2 more Attractions --- .../src/main/java/forge/card/CardEdition.java | 2 +- .../java/forge/game/ability/AbilityUtils.java | 4 ++ .../game/ability/effects/RollDiceEffect.java | 9 ++- .../src/main/java/forge/game/card/Card.java | 18 ++--- .../java/forge/game/card/CardFactory.java | 10 +-- .../main/java/forge/game/card/CardState.java | 11 +++ .../main/java/forge/game/card/CardView.java | 4 +- .../res/cardsfolder/c/clown_extruder.txt | 10 +++ .../res/cardsfolder/c/concession_stand.txt | 10 +++ .../res/cardsfolder/e/everythingamajig.txt | 10 +++ .../res/cardsfolder/g/garbage_elemental.txt | 16 +++++ forge-gui/res/cardsfolder/s/sly_spy.txt | 9 +++ .../res/cardsfolder/s/squirrel_squatters.txt | 11 +++ forge-gui/res/editions/Unstable.txt | 72 +++++++++---------- 14 files changed, 136 insertions(+), 60 deletions(-) create mode 100644 forge-gui/res/cardsfolder/c/clown_extruder.txt create mode 100644 forge-gui/res/cardsfolder/c/concession_stand.txt create mode 100644 forge-gui/res/cardsfolder/e/everythingamajig.txt create mode 100644 forge-gui/res/cardsfolder/g/garbage_elemental.txt create mode 100644 forge-gui/res/cardsfolder/s/sly_spy.txt create mode 100644 forge-gui/res/cardsfolder/s/squirrel_squatters.txt diff --git a/forge-core/src/main/java/forge/card/CardEdition.java b/forge-core/src/main/java/forge/card/CardEdition.java index afee93adf4b..3ae67fddc5d 100644 --- a/forge-core/src/main/java/forge/card/CardEdition.java +++ b/forge-core/src/main/java/forge/card/CardEdition.java @@ -577,7 +577,7 @@ public final class CardEdition implements Comparable { * functional variant name - grouping #9 */ // "(^(.?[0-9A-Z]+.?))?(([SCURML]) )?(.*)$" - "(^(.?[0-9A-Z]+\\S?[A-Z]*)\\s)?(([SCURML])\\s)?([^@#]*)( @([^\\$]*))?( \\$(.+))?$" + "(^(.?[0-9A-Z]+\\S?[A-Z]*)\\s)?(([SCURML])\\s)?([^@\\$]*)( @([^\\$]*))?( \\$(.+))?$" ); ListMultimap cardMap = ArrayListMultimap.create(); 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 1dc538ead80..49ee3d67ffa 100644 --- a/forge-game/src/main/java/forge/game/ability/AbilityUtils.java +++ b/forge-game/src/main/java/forge/game/ability/AbilityUtils.java @@ -2649,6 +2649,10 @@ public class AbilityUtils { return game.getPhaseHandler().getPlanarDiceSpecialActionThisTurn(); } + if (sq[0].startsWith("AttractionsYouVisitedThisTurn")) { + return doXMath(player.getAttractionsVisitedThisTurn(), expr, c, ctb); + } + if (sq[0].equals("AllTypes")) { List cards = getDefinedCards(c, sq[1], ctb); diff --git a/forge-game/src/main/java/forge/game/ability/effects/RollDiceEffect.java b/forge-game/src/main/java/forge/game/ability/effects/RollDiceEffect.java index 08555f6345e..57b01dd5670 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/RollDiceEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/RollDiceEffect.java @@ -221,6 +221,12 @@ public class RollDiceEffect extends SpellAbilityEffect { List rolls = new ArrayList<>(); int total = rollDiceForPlayer(sa, player, amount, sides, ignore, modifier, rolls); + if (sa.hasParam("UseHighestRoll")) { + total = Collections.max(rolls); + } else if (sa.hasParam("UseDifferenceBetweenRolls")) { + total = Collections.max(rolls) - Collections.min(rolls); + } + if (sa.hasParam("StoreResults")) { host.addStoredRolls(rolls); } @@ -243,9 +249,6 @@ public class RollDiceEffect extends SpellAbilityEffect { sa.setSVar(sa.getParam("OtherSVar"), Integer.toString(other)); } } - if (sa.hasParam("UseHighestRoll")) { - total = Collections.max(rolls); - } if (sa.hasParam("SubsForEach")) { for (Integer roll : rolls) { 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 e5871c6fffc..4c0d1d085a2 100644 --- a/forge-game/src/main/java/forge/game/card/Card.java +++ b/forge-game/src/main/java/forge/game/card/Card.java @@ -277,8 +277,6 @@ public class Card extends GameEntity implements Comparable, IHasSVars { private Table> newPT = TreeBasedTable.create(); // Layer 7b private Table> boostPT = TreeBasedTable.create(); // Layer 7c - private String oracleText = ""; - private final Map assignedDamageMap = Maps.newTreeMap(); private Map damage = Maps.newHashMap(); private boolean hasBeenDealtDeathtouchDamage; @@ -2506,7 +2504,7 @@ public class Card extends GameEntity implements Comparable, IHasSVars { || keyword.startsWith("Class") || keyword.startsWith("Blitz") || keyword.startsWith("Specialize") || keyword.equals("Ravenous") || keyword.equals("For Mirrodin") || keyword.startsWith("Craft") - || keyword.startsWith("Landwalk")) { + || keyword.startsWith("Landwalk") || keyword.startsWith("Visit")) { // keyword parsing takes care of adding a proper description } else if (keyword.equals("Read ahead")) { sb.append(Localizer.getInstance().getMessage("lblReadAhead")).append(" (").append(Localizer.getInstance().getMessage("lblReadAheadDesc")); @@ -3498,7 +3496,7 @@ public class Card extends GameEntity implements Comparable, IHasSVars { public final void setCopiedPermanent(final Card c) { if (copiedPermanent == c) { return; } copiedPermanent = c; - currentState.getView().updateOracleText(this); + currentState.setOracleText(c.getOracleText()); } public final boolean isCopiedSpell() { @@ -7244,7 +7242,6 @@ public class Card extends GameEntity implements Comparable, IHasSVars { public void setRules(CardRules r) { cardRules = r; currentState.getView().updateRulesText(r, getType()); - currentState.getView().updateOracleText(this); } public boolean isCommander() { @@ -7573,15 +7570,10 @@ public class Card extends GameEntity implements Comparable, IHasSVars { } public String getOracleText() { - CardRules rules = cardRules; - if (copiedPermanent != null) { //return oracle text of copied permanent if applicable - rules = copiedPermanent.getRules(); - } - return rules != null ? rules.getOracleText() : oracleText; + return currentState.getOracleText(); } - public void setOracleText(final String oracleText0) { - oracleText = oracleText0; - currentState.getView().updateOracleText(this); + public void setOracleText(final String oracleText) { + currentState.setOracleText(oracleText); } @Override diff --git a/forge-game/src/main/java/forge/game/card/CardFactory.java b/forge-game/src/main/java/forge/game/card/CardFactory.java index a2411251419..100adcc6030 100644 --- a/forge-game/src/main/java/forge/game/card/CardFactory.java +++ b/forge-game/src/main/java/forge/game/card/CardFactory.java @@ -346,9 +346,9 @@ public class CardFactory { card.setColor(combinedColor); card.setType(new CardType(rules.getType())); - // Combined text based on Oracle text - might not be necessary, temporarily disabled. - //String combinedText = String.format("%s: %s\n%s: %s", rules.getMainPart().getName(), rules.getMainPart().getOracleText(), rules.getOtherPart().getName(), rules.getOtherPart().getOracleText()); - //card.setText(combinedText); + // Combined text based on Oracle text - might not be necessary + String combinedText = String.format("(%s) %s\r\n\r\n(%s) %s", rules.getMainPart().getName(), rules.getMainPart().getOracleText(), rules.getOtherPart().getName(), rules.getOtherPart().getOracleText()); + card.getState(CardStateName.Original).setOracleText(combinedText); } return card; } @@ -377,7 +377,7 @@ public class CardFactory { c.getCurrentState().setBaseLoyalty(face.getInitialLoyalty()); c.getCurrentState().setBaseDefense(face.getDefense()); - c.setOracleText(face.getOracleText()); + c.getCurrentState().setOracleText(face.getOracleText()); // Super and 'middle' types should use enums. c.setType(new CardType(face.getType())); @@ -454,7 +454,7 @@ public class CardFactory { c.getCurrentState().setBaseDefense(variant.getDefense()); if (variant.getOracleText() != null) - c.setOracleText(variant.getOracleText()); + c.getCurrentState().setOracleText(variant.getOracleText()); if (variant.getType() != null) { for(String type : variant.getType()) diff --git a/forge-game/src/main/java/forge/game/card/CardState.java b/forge-game/src/main/java/forge/game/card/CardState.java index 90c1303228d..895b92b37ed 100644 --- a/forge-game/src/main/java/forge/game/card/CardState.java +++ b/forge-game/src/main/java/forge/game/card/CardState.java @@ -58,6 +58,7 @@ public class CardState extends GameObject implements IHasSVars { private CardType type = new CardType(false); private ManaCost manaCost = ManaCost.NO_COST; private byte color = MagicColor.COLORLESS; + private String oracleText = ""; private int basePower = 0; private int baseToughness = 0; private String basePowerString = null; @@ -194,6 +195,15 @@ public class CardState extends GameObject implements IHasSVars { view.updateColors(card); } + public String getOracleText() { + return oracleText; + } + public void setOracleText(final String oracleText) { + this.oracleText = oracleText; + view.setOracleText(oracleText); + } + + public final int getBasePower() { return basePower; } @@ -595,6 +605,7 @@ public class CardState extends GameObject implements IHasSVars { setType(source.type); setManaCost(source.getManaCost()); setColor(source.getColor()); + setOracleText(source.getOracleText()); setBasePower(source.getBasePower()); setBaseToughness(source.getBaseToughness()); setBaseLoyalty(source.getBaseLoyalty()); diff --git a/forge-game/src/main/java/forge/game/card/CardView.java b/forge-game/src/main/java/forge/game/card/CardView.java index 21ca73a61ff..de32b0573c7 100644 --- a/forge-game/src/main/java/forge/game/card/CardView.java +++ b/forge-game/src/main/java/forge/game/card/CardView.java @@ -1298,8 +1298,8 @@ public class CardView extends GameEntityView { public String getOracleText() { return get(TrackableProperty.OracleText); } - void updateOracleText(Card c) { - set(TrackableProperty.OracleText, c.getOracleText().replace("\\n", "\r\n\r\n").trim()); + void setOracleText(String oracleText) { + set(TrackableProperty.OracleText, oracleText.replace("\\n", "\r\n\r\n").trim()); } public String getRulesText() { diff --git a/forge-gui/res/cardsfolder/c/clown_extruder.txt b/forge-gui/res/cardsfolder/c/clown_extruder.txt new file mode 100644 index 00000000000..fc52d1f353c --- /dev/null +++ b/forge-gui/res/cardsfolder/c/clown_extruder.txt @@ -0,0 +1,10 @@ +Name:Clown Extruder +ManaCost:no cost +Types:Artifact Attraction +Variant:A:Lights:2 6 +Variant:B:Lights:3 6 +Variant:C:Lights:4 6 +Variant:D:Lights:5 6 +K:Visit:TrigToken +SVar:TrigToken:DB$ Token | TokenScript$ w_1_1_a_clown_robot | TokenOwner$ You | SpellDescription$ Create a 1/1 white Clown Robot artifact creature token. +Oracle:Visit — Create a 1/1 white Clown Robot artifact creature token. \ No newline at end of file diff --git a/forge-gui/res/cardsfolder/c/concession_stand.txt b/forge-gui/res/cardsfolder/c/concession_stand.txt new file mode 100644 index 00000000000..cec38a48620 --- /dev/null +++ b/forge-gui/res/cardsfolder/c/concession_stand.txt @@ -0,0 +1,10 @@ +Name:Concession Stand +ManaCost:no cost +Types:Artifact Attraction +Variant:A:Lights:2 6 +Variant:B:Lights:3 6 +Variant:C:Lights:4 6 +Variant:D:Lights:5 6 +K:Visit:TrigFood +SVar:TrigFood:DB$ Token | TokenScript$ c_a_food_sac | TokenOwner$ You | SpellDescription$ Create a Food token. +Oracle:Visit — Create a Food token. (It’s an artifact with “{2}, {T}, Sacrifice this artifact: You gain 3 life.”) \ No newline at end of file diff --git a/forge-gui/res/cardsfolder/e/everythingamajig.txt b/forge-gui/res/cardsfolder/e/everythingamajig.txt new file mode 100644 index 00000000000..ecc98832f31 --- /dev/null +++ b/forge-gui/res/cardsfolder/e/everythingamajig.txt @@ -0,0 +1,10 @@ +Name:Everythingamajig +ManaCost:5 +Types:Artifact +Variant:C:A:AB$ FlipACoin | Cost$ 1 | WinSubAbility$ DBAddMana | InstantSpeed$ True | SpellDescription$ Flip a coin. If you win the flip, add {C}{C}. +Variant:C:SVar:DBAddMana:DB$ Mana | Produced$ C | Amount$ 2 +Variant:C:A:AB$ Discard | Cost$ 3 T | ValidTgts$ Player | NumCards$ 1 | Mode$ TgtChoose | PlayerTurn$ True | SpellDescription$ Target player discards a card. +Variant:C:A:AB$ Animate | Cost$ X | Defined$ Self | Power$ X | Toughness$ X | Types$ Creature,Artifact,Construct | RemoveCreatureTypes$ True | SpellDescription$ CARDNAME becomes an X/X Construct artifact creature until end of turn. +Variant:C:SVar:X:Count$xPaid +Oracle: +Variant:C:Oracle:{1}: Flip a coin. If you win the flip, add {C}{C}. Activate only as an instant.\n{3}, {T}: Target player discards a card. Activate only during your turn.\n{X}: Everythingamajig becomes an X/X Construct artifact creature until end of turn. \ No newline at end of file diff --git a/forge-gui/res/cardsfolder/g/garbage_elemental.txt b/forge-gui/res/cardsfolder/g/garbage_elemental.txt new file mode 100644 index 00000000000..534aa324f76 --- /dev/null +++ b/forge-gui/res/cardsfolder/g/garbage_elemental.txt @@ -0,0 +1,16 @@ +Name:Garbage Elemental +ManaCost:4 R +Types:Creature Elemental +Variant:C:PT:3/2 +Variant:C:K:Battle cry +Variant:C:T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigRoll | TriggerDescription$ When CARDNAME enters the battlefield, roll two six-sided dice. Create a number of 1/1 red Goblin creature tokens equal to the difference between those results. +Variant:C:SVar:TrigRoll:DB$ RollDice | ResultSVar$ Result | Sides$ 6 | Amount$ 2 | UseDifferenceBetweenRolls$ True | SubAbility$ DBToken +Variant:C:SVar:DBToken:DB$ Token | TokenScript$ r_1_1_goblin | TokenAmount$ Result +Variant:D:PT:3/3 +Variant:D:K:Cascade +Variant:D:T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigRoll | TriggerDescription$ When CARDNAME enters the battlefield, roll a six-sided die. CARDNAME deals damage equal to the result to target opponent or planeswalker. +Variant:D:SVar:TrigRoll:DB$ RollDice | ResultSVar$ Result | SubAbility$ DBDamage +Variant:D:SVar:DBDamage:DB$ DealDamage | ValidTgts$ Opponent,Planeswalker | TgtPrompt$ Select target opponent or planeswalker | NumDmg$ Result +Oracle: +Variant:C:Oracle:Battle cry (Whenever this creature attacks, each other attacking creature gets +1/+0 until end of turn.)\nWhen Garbage Elemental enters the battlefield, roll two six-sided dice. Create a number of 1/1 red Goblin creature tokens equal to the difference between those results. +Variant:D:Oracle:Cascade (When you cast this spell, exile cards from the top of your library until you exile a nonland card that costs less. You may cast it without paying its mana cost. Put the exiled cards on the bottom of your library in a random order.)\nWhen Garbage Elemental enters the battlefield, roll a six-sided die. Garbage Elemental deals damage equal to the result to target opponent or planeswalker. \ No newline at end of file diff --git a/forge-gui/res/cardsfolder/s/sly_spy.txt b/forge-gui/res/cardsfolder/s/sly_spy.txt new file mode 100644 index 00000000000..981f8e0114a --- /dev/null +++ b/forge-gui/res/cardsfolder/s/sly_spy.txt @@ -0,0 +1,9 @@ +Name:Sly Spy +ManaCost:2 B +Types:Creature Human Spy +PT:2/2 +Variant:F:T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | CombatDamage$ True | Execute$ TrigRoll | TriggerDescription$ Whenever CARDNAME deals combat damage to a player, roll a six-sided die. That player loses life equal to the result. +Variant:F:SVar:TrigRoll:DB$ RollDice | ResultSVar$ Result | SubAbility$ DBLoseLife +Variant:F:SVar:DBLoseLife:DB$ LoseLife | Defined$ TriggeredTarget | LifeAmount$ Result +Oracle: +Variant:F:Oracle:Whenever Sly Spy deals combat damage to a player, roll a six-sided die. That player loses life equal to the result. \ No newline at end of file diff --git a/forge-gui/res/cardsfolder/s/squirrel_squatters.txt b/forge-gui/res/cardsfolder/s/squirrel_squatters.txt new file mode 100644 index 00000000000..855c49333bc --- /dev/null +++ b/forge-gui/res/cardsfolder/s/squirrel_squatters.txt @@ -0,0 +1,11 @@ +Name:Squirrel Squatters +ManaCost:3 G G +Types:Creature Squirrel +PT:4/4 +T:Mode$ ChangesZone | ValidCard$ Card.Self | Origin$ Any | Destination$ Battlefield | Execute$ TrigOpenAttraction | TriggerDescription$ When CARDNAME enters the battlefield, open an Attraction. +SVar:TrigOpenAttraction:DB$ OpenAttraction +T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigToken | TriggerDescription$ Whenever CARDNAME attacks, create a 1/1 green Squirrel creature token that's tapped and attacking for each Attraction you've visited this turn. +SVar:TrigToken:DB$ Token | TokenAmount$ X | TokenScript$ g_1_1_squirrel | TokenOwner$ You | TokenTapped$ True | TokenAttacking$ True +SVar:X:Count$AttractionsYouVisitedThisTurn +SVar:HasAttackEffect:TRUE +Oracle:When Squirrel Squatters enters the battlefield, open an Attraction. (Put the top card of your Attraction deck onto the battlefield.)\nWhenever Squirrel Squatters attacks, create a 1/1 green Squirrel creature token that’s tapped and attacking for each Attraction you’ve visited this turn. \ No newline at end of file diff --git a/forge-gui/res/editions/Unstable.txt b/forge-gui/res/editions/Unstable.txt index 999424045dd..cd1b746fc20 100644 --- a/forge-gui/res/editions/Unstable.txt +++ b/forge-gui/res/editions/Unstable.txt @@ -20,12 +20,12 @@ ScryfallCode=UST 9 U Half-Kitten, Half- 10 C Humming- 11 R Jackknight -12a U Knight of the Kitchen Sink A -12b U Knight of the Kitchen Sink B -12c U Knight of the Kitchen Sink C -12d U Knight of the Kitchen Sink D -12e U Knight of the Kitchen Sink E -12f U Knight of the Kitchen Sink F +12a U Knight of the Kitchen Sink $A +12b U Knight of the Kitchen Sink $B +12c U Knight of the Kitchen Sink $C +12d U Knight of the Kitchen Sink $D +12e U Knight of the Kitchen Sink $E +12f U Knight of the Kitchen Sink $F 13 U Knight of the Widget 14 U Midlife Upgrade 15 R Oddly Uneven @@ -65,12 +65,12 @@ ScryfallCode=UST 46 U Spy Eye 47 U Suspicious Nanny 48 C Time Out -49a R Very Cryptic Command A -49b R Very Cryptic Command B -49c R Very Cryptic Command C -49d R Very Cryptic Command D -49e R Very Cryptic Command E -49f R Very Cryptic Command F +49a R Very Cryptic Command $A +49b R Very Cryptic Command $B +49c R Very Cryptic Command $C +49d R Very Cryptic Command $D +49e R Very Cryptic Command $E +49f R Very Cryptic Command $F 50 C Wall of Fortune 51 C Big Boa Constrictor 52 C capital offense @@ -91,12 +91,12 @@ ScryfallCode=UST 64 U Overt Operative 65 U "Rumors of My Death..." 66 U Skull Saucer -67a U Sly Spy A -67b U Sly Spy B -67c U Sly Spy C -67d U Sly Spy D -67e U Sly Spy E -67f U Sly Spy F +67a U Sly Spy $A +67b U Sly Spy $B +67c U Sly Spy $C +67d U Sly Spy $D +67e U Sly Spy $E +67f U Sly Spy $F 68 C Snickering Squirrel 69 R Spike, Tournament Grinder 70 U Squirrel-Powered Scheme @@ -111,12 +111,12 @@ ScryfallCode=UST 79 C Common Iguana 80 R The Countdown Is at One 81 C Feisty Stegosaurus -82a U Garbage Elemental A -82b U Garbage Elemental B -82c U Garbage Elemental C -82d U Garbage Elemental D -82e U Garbage Elemental E -82f U Garbage Elemental F +82a U Garbage Elemental $A +82b U Garbage Elemental $B +82c U Garbage Elemental $C +82d U Garbage Elemental $D +82e U Garbage Elemental $E +82f U Garbage Elemental $F 83 U Goblin Haberdasher 84 U Half-Orc, Half- 85 C Hammer Helper @@ -153,12 +153,12 @@ ScryfallCode=UST 110 U Ground Pounder 111 U Half-Squirrel, Half- 112 R Hydradoodle -113a R Ineffable Blessing A -113b R Ineffable Blessing B -113c R Ineffable Blessing C -113d R Ineffable Blessing D -113e R Ineffable Blessing E -113f R Ineffable Blessing F +113a R Ineffable Blessing $A +113b R Ineffable Blessing $B +113c R Ineffable Blessing $C +113d R Ineffable Blessing $D +113e R Ineffable Blessing $E +113f R Ineffable Blessing $F 114 C Joyride Rigger 115 U Monkey- 116 C Mother Kangaroo @@ -195,12 +195,12 @@ ScryfallCode=UST 145c C Despondent Killbot 145d C Enraged Killbot 146 U Entirely Normal Armchair -147a R Everythingamajig A -147b R Everythingamajig B -147c R Everythingamajig C -147d R Everythingamajig D -147e R Everythingamajig E -147f R Everythingamajig F +147a R Everythingamajig $A +147b R Everythingamajig $B +147c R Everythingamajig $C +147d R Everythingamajig $D +147e R Everythingamajig $E +147f R Everythingamajig $F 148 C Gnome-Made Engine 149 R Handy Dandy Clone Machine 150 R Kindslaver