Teach the boss cautions two silencers beyond the card killers

The Water removes every discard at blind start (blind.lua:208, returned
only after the fight), idling discard granters and payoffs alike; The
Eye blocks a repeated hand type outright (blind.lua:189/577), giving a
one-hand build exactly one shot. BOSS_KILLS entries now carry a tag SET
and their own factual phrase, since "debuffs X" stopped being the only
true sentence. The Arm and The Ox were chased and rejected -- level
drain does not touch the planet jokers, and The Ox fires on the
player's own hand choice, the same reasoning that rejected the Card
Sharp/Obelisk clash -- recorded in the BOSS_KILLS comment so nobody
re-adds them.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
funman300
2026-07-14 15:23:16 -07:00
parent 43e1ea2bc6
commit 9364603db1
2 changed files with 76 additions and 24 deletions
+45 -16
View File
@@ -336,19 +336,42 @@ function JCA.is_perished(card)
return not not (a and a.perishable and (a.perish_tally or 0) <= 0) return not not (a and a.perishable and (a.perish_tally or 0) <= 0)
end end
-- Boss-blind cautions: five bosses debuff a whole class of cards for the -- Boss-blind cautions: bosses that mechanically shut off a class of jokers
-- fight (game.lua P_BLINDS; applied in Blind:debuff_card, blind.lua:708): -- for the fight. Warning-only, like every trap: this never touches a score.
-- The Club/Goad/Head/Window each kill a suit, The Plant kills face cards. -- Each entry maps the boss to the catalog tags it silences and the factual
-- A debuffed card scores nothing and triggers nothing, so a joker that wants -- phrase the tooltip prints ("This ante: <boss> <what>").
-- that class is walking into a dead ante -- and a joker that GIVES it is --
-- worse (Pareidolia under The Plant makes every card a debuffed face). -- Five bosses debuff a whole class of cards (game.lua P_BLINDS; applied in
-- Warning-only, like every trap: this never touches a score. -- Blind:debuff_card, blind.lua:708): The Club/Goad/Head/Window each kill a
-- suit, The Plant kills face cards. A debuffed card scores nothing and
-- triggers nothing, so a joker that wants that class is walking into a dead
-- ante -- and a joker that GIVES it is worse (Pareidolia under The Plant
-- makes every card a debuffed face).
--
-- Two more silence a mechanic rather than a card class:
-- The Water removes every discard at blind start (blind.lua:208 eases
-- discards_left to 0; given back only after the fight, blind.lua:405), so
-- discard granters and discard payoffs both idle.
-- The Eye records each played hand type and BLOCKS a repeat outright
-- (blind.lua:189 builds the table, debuff_hand rejects at blind.lua:577),
-- so a build that spams one hand type gets exactly one shot at it.
--
-- Chased and REJECTED, so nobody re-adds them: The Arm lowers the played
-- hand's LEVEL (blind.lua:584) -- that drains hand-level investment, not the
-- planet-economy jokers, so warning them off would be wrong. The Ox fires
-- only when the player chooses to play their most played hand -- the same
-- "hand choice decides, not the effect" reasoning that rejected the Card
-- Sharp/Obelisk clash (see AUDIT.md).
local BOSS_KILLS = { local BOSS_KILLS = {
bl_club = {tag = 'clubs', what = 'Clubs'}, bl_club = {tags = {clubs = true}, what = 'debuffs Clubs'},
bl_goad = {tag = 'spades', what = 'Spades'}, bl_goad = {tags = {spades = true}, what = 'debuffs Spades'},
bl_head = {tag = 'hearts', what = 'Hearts'}, bl_head = {tags = {hearts = true}, what = 'debuffs Hearts'},
bl_window = {tag = 'diamonds', what = 'Diamonds'}, bl_window = {tags = {diamonds = true}, what = 'debuffs Diamonds'},
bl_plant = {tag = 'faces', what = 'face cards'}, bl_plant = {tags = {faces = true}, what = 'debuffs face cards'},
bl_water = {tags = {discards_up = true}, what = 'sets discards to 0'},
bl_eye = {tags = {pair = true, two_pair = true, three_kind = true,
four_kind = true, straight = true, flush = true},
what = 'blocks repeat hand types'},
} }
JCA.boss_kills = BOSS_KILLS JCA.boss_kills = BOSS_KILLS
@@ -734,18 +757,24 @@ local function tooltip_rows(card)
end end
end end
-- Boss caution: buying a joker whose card class the upcoming boss -- Boss caution: buying a joker whose class the upcoming boss silences
-- debuffs is paying for a dead ante. Warnings survive learning mode. -- is paying for a dead ante. Warnings survive learning mode.
if in_buy_area(card) then if in_buy_area(card) then
local boss = JCA.upcoming_boss() local boss = JCA.upcoming_boss()
local kill = boss and BOSS_KILLS[boss] local kill = boss and BOSS_KILLS[boss]
local entry = JCA.db[key] local entry = JCA.db[key]
if kill and entry and (entry.wants[kill.tag] or entry.gives[kill.tag]) then if kill and entry then
local hit
for t in pairs(kill.tags) do
if entry.wants[t] or entry.gives[t] then hit = true break end
end
if hit then
local bname = G.P_BLINDS and G.P_BLINDS[boss] and G.P_BLINDS[boss].name local bname = G.P_BLINDS and G.P_BLINDS[boss] and G.P_BLINDS[boss].name
text_row(('This ante: %s debuffs %s'):format(bname or 'the boss', kill.what), text_row(('This ante: %s %s'):format(bname or 'the boss', kill.what),
G.C.RED) G.C.RED)
end end
end end
end
-- Sticker facts (any area -- higher stakes put stickers on shop jokers -- Sticker facts (any area -- higher stakes put stickers on shop jokers
-- too). Mechanical numbers from the game source, not judgements, so -- too). Mechanical numbers from the game source, not judgements, so
+29 -6
View File
@@ -504,18 +504,41 @@ eq(deck_total, 0, 'no deck (menus, tests) reads as an empty deck')
section('Engine: boss-blind cautions know who the boss silences') section('Engine: boss-blind cautions know who the boss silences')
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
-- The five class-killer bosses, verbatim from game.lua's P_BLINDS debuff -- The class-killer bosses, verbatim from game.lua's P_BLINDS configs and the
-- configs. Every tag they reference must exist in the database, or the -- blind.lua effects. Every tag they reference must exist in the database,
-- caution can never fire. -- or the caution can never fire.
for boss, kill in pairs(JCA.boss_kills) do for boss, kill in pairs(JCA.boss_kills) do
ok(JCA.tag_label[kill.tag], ('boss %s kills a real catalog tag (%s)'):format(boss, kill.tag)) local n = 0
for tag in pairs(kill.tags) do
n = n + 1
ok(JCA.tag_label[tag], ('boss %s kills a real catalog tag (%s)'):format(boss, tag))
end
ok(n > 0, ('boss %s kills at least one tag'):format(boss))
ok(type(kill.what) == 'string' and #kill.what > 0,
('boss %s carries its tooltip phrase'):format(boss))
end end
-- The Plant debuffs faces: it must catch both the payoff (Business Card -- The Plant debuffs faces: it must catch both the payoff (Business Card
-- wants faces) and the enabler (Pareidolia turns every card into one). -- wants faces) and the enabler (Pareidolia turns every card into one).
local plant = JCA.boss_kills.bl_plant local plant = JCA.boss_kills.bl_plant
ok(JCA.db.j_business.wants[plant.tag], 'The Plant caution catches face payoffs') ok(JCA.db.j_business.wants.faces and plant.tags.faces,
ok(JCA.db.j_pareidolia.gives[plant.tag], 'and face enablers, whose conversion kills the deck') 'The Plant caution catches face payoffs')
ok(JCA.db.j_pareidolia.gives.faces, 'and face enablers, whose conversion kills the deck')
-- The Water removes every discard for the fight (blind.lua:208): both the
-- granters (Drunkard) and the payoffs (Hit the Road) must be caught.
local water = JCA.boss_kills.bl_water
ok(water.tags.discards_up and JCA.db.j_drunkard.gives.discards_up,
'The Water caution catches discard granters')
ok(JCA.db.j_hit_the_road.wants.discards_up, 'and discard payoffs')
-- The Eye blocks repeat hand types (blind.lua:577): every hand-type cluster
-- tag must be covered, so a one-hand build always hears about it.
local eye = JCA.boss_kills.bl_eye
for _, t in ipairs({'pair', 'two_pair', 'three_kind', 'four_kind', 'straight', 'flush'}) do
ok(eye.tags[t], ('The Eye covers the %s cluster'):format(t))
end
ok(not eye.tags.hearts, 'but The Eye does not touch suit tags (suits repeat fine)')
-- Upcoming-boss reading: warn while the boss is ahead, stay quiet once it -- Upcoming-boss reading: warn while the boss is ahead, stay quiet once it
-- is dealt with. -- is dealt with.