Fix a backwards clash, and add 19 verified traps
Every entry here was checked against the running Steamodded source in Mods/lovely/dump, not from memory. The headline is a correction: the shipped CLASHES table warned that Smeared Joker + Flower Pot "cannot make all four" suits. It is backwards. Flower Pot fills its four suit slots with a greedy if/elseif chain (card.lua:4256) and SMODS.smeared_check makes Hearts answer for Diamonds and Spades for Clubs, so the second Heart falls through into the Diamond slot: any two red + two black cards fill the pot. It is one of the strongest combos in the game and the mod was steering players away from it -- while simultaneously scoring the pair +2 via suit_flex, which should have been the tell. It is now a famous pair. New clashes (4 -> 22), all traced to the mechanism: * Burglar zeroes discards_left on blind select (card.lua:2905), which switches off every discard-gated joker for the rest of the run: Banner, Delayed Gratification, Castle, Yorick, Hit the Road, Burnt, Mail-In Rebate, Faceless, Trading Card, and it wipes the discards Drunkard and Merry Andy hand you. Delayed Gratification is the cruellest -- "no discards used" reads like a synergy, but the code also requires discards_left > 0, so it pays exactly $0. * Vampire strips enhancements in the `before` pass, ahead of the per-card `individual` pass where enhancement payoffs are read, so it eats what Golden Ticket, Glass, Stone Joker, Marble and Driver's License are counting. * Joker Stencil scales on EMPTY slots, so Riff-Raff and Abstract Joker fight it. * Splash makes every played card score, so a face card that used to be a harmless kicker now resets Ride the Bus. New cautions (3 -> 15): the positional traps (Blueprint dead in the rightmost slot, Brainstorm in the leftmost), Mime doing nothing without a held-card payoff, and the decay timers, whose numbers are exact from game.lua (Ice Cream 100/5 = 20 hands, Popcorn 20/4 = 5 rounds). Also corrects the stale game path in CLAUDE.md. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -46,9 +46,9 @@ To poke at the engine by hand, copy the stub block from the top of `test.lua`.
|
|||||||
`~/.local/share/Balatro/Mods/JokerComboAdvisor -> ~/Documents/JokerComboAdvisor`
|
`~/.local/share/Balatro/Mods/JokerComboAdvisor -> ~/Documents/JokerComboAdvisor`
|
||||||
(this repo). Edits here go live on next game launch — do not copy files anywhere.
|
(this repo). Edits here go live on next game launch — do not copy files anywhere.
|
||||||
Lovely reads that folder as `C:\users\steamuser\AppData\Roaming\Balatro\Mods`.
|
Lovely reads that folder as `C:\users\steamuser\AppData\Roaming\Balatro\Mods`.
|
||||||
- Game: Steam/Proton at `/mnt/games/Steam/steamapps/common/Balatro` (note: second
|
- Game: Steam/Proton at `~/.local/share/Steam/steamapps/common/Balatro`. Lovely
|
||||||
Steam library, not the default paths). Lovely injector + Steamodded 1.0.0-beta
|
injector + Steamodded 1.0.0-beta are already installed; mods are managed via
|
||||||
are already installed; mods are managed via Balatro Mod Manager.
|
Balatro Mod Manager.
|
||||||
- Crash/load logs: `~/.local/share/Balatro/Mods/lovely/log/` (newest file).
|
- Crash/load logs: `~/.local/share/Balatro/Mods/lovely/log/` (newest file).
|
||||||
- Remote: `https://git.aleshym.co/funman300/JokerComboAdvisor` (private, user's
|
- Remote: `https://git.aleshym.co/funman300/JokerComboAdvisor` (private, user's
|
||||||
Gitea). Pushes authenticate via the repo-local credential helper, which
|
Gitea). Pushes authenticate via the repo-local credential helper, which
|
||||||
@@ -165,5 +165,16 @@ Three-layer split; `JCA` is the single global namespace:
|
|||||||
`CLASHES` (pairwise, red "Clashes -" tooltip line vs owned jokers) and
|
`CLASHES` (pairwise, red "Clashes -" tooltip line vs owned jokers) and
|
||||||
`CAUTIONS` (per-joker, buy-area "Caution:" line) in `synergies.lua`, same
|
`CAUTIONS` (per-joker, buy-area "Caution:" line) in `synergies.lua`, same
|
||||||
~34-char blurb budget as `PAIRS`. Learning mode keeps warnings visible.
|
~34-char blurb budget as `PAIRS`. Learning mode keeps warnings visible.
|
||||||
|
**Verify every new trap against the dump before adding it** — a warning that
|
||||||
|
is merely plausible is worse than none. The mod once shipped a `j_smeared` +
|
||||||
|
`j_flower_pot` clash that was exactly backwards: Flower Pot fills its four
|
||||||
|
suit slots with a greedy `if/elseif` chain (`card.lua:4256`) and Smeared makes
|
||||||
|
Hearts answer for Diamonds, so any two red + two black cards fill the pot. It
|
||||||
|
is one of the best combos in the game, and the mod was warning players off it.
|
||||||
|
Most traps hinge on the scoring-pipeline order in `functions/state_events.lua`
|
||||||
|
(`before` → per-card `individual` → `joker_main`): Vampire strips enhancements
|
||||||
|
in `before`, so every enhancement payoff that reads them in `individual` —
|
||||||
|
Golden Ticket, Glass, Stone, Driver's License — is looking at cards it has
|
||||||
|
already eaten.
|
||||||
- The UI hooks are the only untested-in-game surface; if a tooltip regression is
|
- The UI hooks are the only untested-in-game surface; if a tooltip regression is
|
||||||
reported, suspect the `aut.info` entry format first and check the lovely log.
|
reported, suspect the `aut.info` entry format first and check the lovely log.
|
||||||
|
|||||||
+62
-3
@@ -229,6 +229,12 @@ local PAIRS = {
|
|||||||
{'j_bull', 'j_to_the_moon', 'interest piles up, chips follow'},
|
{'j_bull', 'j_to_the_moon', 'interest piles up, chips follow'},
|
||||||
{'j_marble', 'j_hologram', 'every added Stone grows Hologram'},
|
{'j_marble', 'j_hologram', 'every added Stone grows Hologram'},
|
||||||
{'j_egg', 'j_campfire', 'sell the grown Egg for xMult'},
|
{'j_egg', 'j_campfire', 'sell the grown Egg for xMult'},
|
||||||
|
-- Flower Pot fills its four suit slots with a greedy if/elseif chain
|
||||||
|
-- (card.lua:4256) and Smeared makes Hearts answer for Diamonds and Spades
|
||||||
|
-- for Clubs, so the second Heart falls through into the Diamond slot: any
|
||||||
|
-- two red + two black cards fill the pot. It is a top-tier combo, and this
|
||||||
|
-- mod used to warn against it.
|
||||||
|
{'j_smeared', 'j_flower_pot', 'any 2 red + 2 black fill it'},
|
||||||
}
|
}
|
||||||
|
|
||||||
-- Known traps: pairs that actively hurt each other. Warning-only — they
|
-- Known traps: pairs that actively hurt each other. Warning-only — they
|
||||||
@@ -236,9 +242,40 @@ local PAIRS = {
|
|||||||
-- a red "Clashes" line. Keep warnings under ~34 chars (one tooltip row).
|
-- a red "Clashes" line. Keep warnings under ~34 chars (one tooltip row).
|
||||||
local CLASHES = {
|
local CLASHES = {
|
||||||
{'j_ride_the_bus', 'j_pareidolia', 'every card counts as a face'},
|
{'j_ride_the_bus', 'j_pareidolia', 'every card counts as a face'},
|
||||||
{'j_vampire', 'j_steel_joker', 'drains the Steel it counts'},
|
|
||||||
{'j_vampire', 'j_lucky_cat', 'strips Lucky cards before they pay'},
|
-- Burglar sets discards_left to 0 when the blind is selected
|
||||||
{'j_smeared', 'j_flower_pot', 'merged suits cannot make all four'},
|
-- (`ease_discard(-discards_left)`, card.lua:2905), so every joker that
|
||||||
|
-- reads a discard is switched off for the whole run.
|
||||||
|
{'j_burglar', 'j_banner', 'no discards left to count'},
|
||||||
|
{'j_burglar', 'j_delayed_grat', 'pays per discard; you get 0'},
|
||||||
|
{'j_burglar', 'j_castle', 'no discards, never grows'},
|
||||||
|
{'j_burglar', 'j_yorick', 'no discards, never grows'},
|
||||||
|
{'j_burglar', 'j_hit_the_road', 'no discards, never grows'},
|
||||||
|
{'j_burglar', 'j_burnt', 'no discards to level a hand'},
|
||||||
|
{'j_burglar', 'j_mail', 'no discards, no rebate'},
|
||||||
|
{'j_burglar', 'j_faceless', 'no discards, no payout'},
|
||||||
|
{'j_burglar', 'j_trading', 'no discards to trade in'},
|
||||||
|
{'j_burglar', 'j_drunkard', 'its extra discards get wiped'},
|
||||||
|
{'j_burglar', 'j_merry_andy', 'its extra discards get wiped'},
|
||||||
|
|
||||||
|
-- Vampire strips enhancements in the `before` pass (card.lua:3851/3906),
|
||||||
|
-- which runs ahead of the per-card `individual` pass where the enhancement
|
||||||
|
-- payoffs are read — so it eats the cards they are counting, permanently.
|
||||||
|
{'j_vampire', 'j_steel_joker', 'drains the Steel it counts'},
|
||||||
|
{'j_vampire', 'j_lucky_cat', 'strips Lucky cards before they pay'},
|
||||||
|
{'j_vampire', 'j_ticket', 'eats Gold before Ticket pays'},
|
||||||
|
{'j_vampire', 'j_glass', 'strips Glass before it shatters'},
|
||||||
|
{'j_vampire', 'j_drivers_license', 'strips the 16 enhanced cards'},
|
||||||
|
{'j_vampire', 'j_stone', 'eats the Stone cards it counts'},
|
||||||
|
{'j_vampire', 'j_marble', 'eats the Stones Marble adds'},
|
||||||
|
|
||||||
|
-- Joker Stencil's xMult is the count of EMPTY joker slots.
|
||||||
|
{'j_stencil', 'j_riff_raff', 'fills the slots Stencil needs'},
|
||||||
|
{'j_stencil', 'j_abstract', 'one wants jokers, one wants slots'},
|
||||||
|
|
||||||
|
-- Splash makes every played card score, so a face card that used to be a
|
||||||
|
-- harmless kicker now lands in the scoring hand and resets the counter.
|
||||||
|
{'j_splash', 'j_ride_the_bus', 'any played face card resets it'},
|
||||||
}
|
}
|
||||||
|
|
||||||
-- Per-joker cautions for the buy-area tooltip: the joker is fine on its
|
-- Per-joker cautions for the buy-area tooltip: the joker is fine on its
|
||||||
@@ -248,6 +285,28 @@ local CAUTIONS = {
|
|||||||
j_ceremonial = 'eats the joker to its right',
|
j_ceremonial = 'eats the joker to its right',
|
||||||
j_madness = 'destroys a random joker each blind',
|
j_madness = 'destroys a random joker each blind',
|
||||||
j_stencil = 'xMult grows with EMPTY joker slots',
|
j_stencil = 'xMult grows with EMPTY joker slots',
|
||||||
|
|
||||||
|
-- Positional traps: both copy a neighbour, and neither says so on the card.
|
||||||
|
j_blueprint = 'dead in the rightmost slot',
|
||||||
|
j_brainstorm = 'dead in the leftmost slot',
|
||||||
|
j_riff_raff = 'needs free joker slots',
|
||||||
|
|
||||||
|
-- Does nothing on its own: Mime retriggers held-card abilities, so with no
|
||||||
|
-- Steel/Gold cards and no Baron/Shoot the Moon it retriggers nothing.
|
||||||
|
j_mime = 'dead without held-card payoffs',
|
||||||
|
|
||||||
|
-- Board-wide side effects the card text buries.
|
||||||
|
j_burglar = 'wipes ALL discards each blind',
|
||||||
|
j_vampire = 'permanently eats enhancements',
|
||||||
|
j_obelisk = 'resets on your most played hand',
|
||||||
|
j_stuntman = 'costs you 2 hand size',
|
||||||
|
|
||||||
|
-- Decay: the numbers are exact (chips 100 / chip_mod 5, mult 20 / extra 4,
|
||||||
|
-- h_size 5 / h_mod 1, odds 6 -- all from game.lua).
|
||||||
|
j_ice_cream = 'melts to nothing in 20 hands',
|
||||||
|
j_popcorn = 'decays to nothing in 5 rounds',
|
||||||
|
j_turtle_bean = 'hand size shrinks back each round',
|
||||||
|
j_gros_michel = '1 in 6 to self-destruct each round',
|
||||||
}
|
}
|
||||||
|
|
||||||
-- How to phrase a tag link in the tooltip, from the partner's perspective:
|
-- How to phrase a tag link in the tooltip, from the partner's perspective:
|
||||||
|
|||||||
Reference in New Issue
Block a user