Give Perkeo its consumable wants; make theme fragility a decision
Perkeo duplicates a RANDOM held consumable (card.lua:2788), so Spectral and Planet supply feed it exactly like Tarot supply always did - and the spectral_gen theme gains the third member it needed (the Seance + Perkeo negative-spectral archetype, now discoverable three ways). The other five two-member themes (diamonds, hearts, four_kind, gold_gen, stone_gen) are vanilla reality: no third joker exists. They get FRAGILE_OK verdicts in audit.lua, rendered in AUDIT.md, and the audit now fails on a fragile theme with no verdict - or a stale verdict for a theme that grew - the same discipline as the silent-joker list. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -85,7 +85,7 @@ A tag with two is fragile: drop either joker and the theme dies.
|
||||
| `joker_gen` | 1 | 3 | 4 | yes |
|
||||
| `money` | 15 | 3 | 17 | yes |
|
||||
| `pair` | 3 | 3 | 3 | yes |
|
||||
| `planet` | 3 | 3 | 3 | yes |
|
||||
| `planet` | 3 | 4 | 4 | yes |
|
||||
| `probability` | 1 | 7 | 8 | yes |
|
||||
| `retrig_faces` | 1 | 10 | 11 | yes |
|
||||
| `retrig_held` | 1 | 4 | 5 | yes |
|
||||
@@ -93,7 +93,7 @@ A tag with two is fragile: drop either joker and the theme dies.
|
||||
| `retrig_scoring` | 4 | 17 | 21 | yes |
|
||||
| `sell_value` | 2 | 2 | 4 | yes |
|
||||
| `spades` | 2 | 3 | 3 | yes |
|
||||
| `spectral_gen` | 2 | 2 | **2** | yes |
|
||||
| `spectral_gen` | 2 | 3 | 3 | yes |
|
||||
| `stone_gen` | 1 | 1 | **2** | yes |
|
||||
| `straight` | 7 | 6 | 8 | yes |
|
||||
| `suit_flex` | 1 | 12 | 13 | yes |
|
||||
@@ -101,6 +101,16 @@ A tag with two is fragile: drop either joker and the theme dies.
|
||||
| `three_kind` | 4 | 3 | 4 | yes |
|
||||
| `two_pair` | 3 | 3 | 3 | yes |
|
||||
|
||||
### Fragile by design
|
||||
|
||||
Two-member themes reviewed and accepted: vanilla has no third joker to add.
|
||||
|
||||
- **`diamonds`** — Greedy Joker and Rough Gem are the only Diamond payoffs in vanilla.
|
||||
- **`four_kind`** — DNA enables it, The Family pays it; no other vanilla joker cares.
|
||||
- **`gold_gen`** — Midas Mask makes Gold, Golden Ticket cashes it - the whole economy.
|
||||
- **`hearts`** — Lusty Joker and Bloodstone are the only Heart payoffs in vanilla.
|
||||
- **`stone_gen`** — Marble adds Stones, Stone Joker counts them; Vampire eats them rather than wanting them.
|
||||
|
||||
## Load-bearing jokers
|
||||
|
||||
The jokers that appear in the most scoring relationships. If one of these is
|
||||
@@ -116,8 +126,8 @@ mis-tagged, the error is spread across the whole database.
|
||||
| `j_to_the_moon` | 16 |
|
||||
| `j_bootstraps` | 15 |
|
||||
| `j_bull` | 15 |
|
||||
| `j_seance` | 13 |
|
||||
| `j_four_fingers` | 12 |
|
||||
| `j_seance` | 12 |
|
||||
| `j_sock_and_buskin` | 12 |
|
||||
| `j_blueprint` | 11 |
|
||||
|
||||
|
||||
@@ -244,6 +244,18 @@ end
|
||||
w('')
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Two-member themes, reviewed and accepted: vanilla simply has no third joker.
|
||||
-- A fragile theme NOT in this table fails the audit -- either find a member or
|
||||
-- record why none exists. A stale entry (theme grew past two) also fails, so
|
||||
-- the table never drifts from the data.
|
||||
local FRAGILE_OK = {
|
||||
diamonds = 'Greedy Joker and Rough Gem are the only Diamond payoffs in vanilla.',
|
||||
hearts = 'Lusty Joker and Bloodstone are the only Heart payoffs in vanilla.',
|
||||
four_kind = 'DNA enables it, The Family pays it; no other vanilla joker cares.',
|
||||
gold_gen = 'Midas Mask makes Gold, Golden Ticket cashes it - the whole economy.',
|
||||
stone_gen = 'Marble adds Stones, Stone Joker counts them; Vampire eats them rather than wanting them.',
|
||||
}
|
||||
|
||||
w('## Tag health')
|
||||
w('')
|
||||
w('A tag with one member can never fire (it takes two jokers to make a synergy).')
|
||||
@@ -251,15 +263,34 @@ w('A tag with two is fragile: drop either joker and the theme dies.')
|
||||
w('')
|
||||
w('| tag | givers | wanters | jokers | theme? |')
|
||||
w('|---|---|---|---|---|')
|
||||
local fragile_unreviewed, fragile_stale = {}, {}
|
||||
local fragile_counts = {}
|
||||
for _, t in ipairs(sorted(members)) do
|
||||
if not ENGINE[t] then
|
||||
local n = 0
|
||||
for _ in pairs(members[t]) do n = n + 1 end
|
||||
fragile_counts[t] = n
|
||||
if data.theme_info[t] and n <= 2 and not FRAGILE_OK[t] then
|
||||
fragile_unreviewed[#fragile_unreviewed + 1] = t
|
||||
end
|
||||
w('| `%s` | %d | %d | %s | %s |', t, givers[t] or 0, wanters[t] or 0,
|
||||
n <= 2 and ('**' .. n .. '**') or tostring(n),
|
||||
data.theme_info[t] and 'yes' or '-')
|
||||
end
|
||||
end
|
||||
for t in pairs(FRAGILE_OK) do
|
||||
if (fragile_counts[t] or 0) > 2 then fragile_stale[#fragile_stale + 1] = t end
|
||||
end
|
||||
w('')
|
||||
w('### Fragile by design')
|
||||
w('')
|
||||
w('Two-member themes reviewed and accepted: vanilla has no third joker to add.')
|
||||
w('')
|
||||
for _, t in ipairs(sorted(FRAGILE_OK)) do
|
||||
if (fragile_counts[t] or 0) <= 2 then
|
||||
w('- **`%s`** — %s', t, FRAGILE_OK[t])
|
||||
end
|
||||
end
|
||||
w('')
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
@@ -312,3 +343,16 @@ if #buckets.unreviewed > 0 then
|
||||
:format(#buckets.unreviewed, n_jokers, table.concat(buckets.unreviewed, '\n ')))
|
||||
os.exit(1)
|
||||
end
|
||||
|
||||
-- A theme hanging on two jokers is a discovery achievement one rebalance away
|
||||
-- from impossible; that has to be a decision too.
|
||||
if #fragile_unreviewed > 0 then
|
||||
io.stderr:write(('\n%d fragile theme(s) (two members) have no FRAGILE_OK verdict:\n %s\n')
|
||||
:format(#fragile_unreviewed, table.concat(fragile_unreviewed, '\n ')))
|
||||
os.exit(1)
|
||||
end
|
||||
if #fragile_stale > 0 then
|
||||
io.stderr:write(('\nFRAGILE_OK verdict(s) for themes that are no longer fragile -- '
|
||||
.. 'delete them:\n %s\n'):format(table.concat(fragile_stale, '\n ')))
|
||||
os.exit(1)
|
||||
end
|
||||
|
||||
+5
-1
@@ -201,7 +201,11 @@ j('j_caino', {'xmult','copy_target'}, {'faces'})
|
||||
j('j_triboulet', {'xmult','copy_target'}, {'retrig_scoring','retrig_faces'})
|
||||
j('j_yorick', {'xmult','copy_target'}, {'discards_up'})
|
||||
j('j_chicot', {})
|
||||
j('j_perkeo', {'tarot_gen'}, {'tarot_gen'})
|
||||
-- Perkeo duplicates a RANDOM held consumable (pseudorandom_element over
|
||||
-- G.consumeables.cards, card.lua:2788), so every consumable economy feeds it:
|
||||
-- Tarot and Planet supply give it targets, and duplicating Spectrals is the
|
||||
-- famous negative-spectral archetype with Seance.
|
||||
j('j_perkeo', {'tarot_gen'}, {'tarot_gen','spectral_gen','planet'})
|
||||
|
||||
-- Famous explicit combos (flat bonus on top of tag matching), each with a
|
||||
-- short "why it works" line shown in the tooltip. Keep blurbs under ~34
|
||||
|
||||
Reference in New Issue
Block a user