From 9364603db16e4dc05a276ee1031d1dae96b4f3ae Mon Sep 17 00:00:00 2001 From: funman300 Date: Tue, 14 Jul 2026 15:23:16 -0700 Subject: [PATCH] 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 --- main.lua | 65 ++++++++++++++++++++++++++++++++++++++++---------------- test.lua | 35 ++++++++++++++++++++++++------ 2 files changed, 76 insertions(+), 24 deletions(-) diff --git a/main.lua b/main.lua index 1c39cd6..c55bdea 100644 --- a/main.lua +++ b/main.lua @@ -336,19 +336,42 @@ function JCA.is_perished(card) return not not (a and a.perishable and (a.perish_tally or 0) <= 0) end --- Boss-blind cautions: five bosses debuff a whole class of cards for the --- fight (game.lua P_BLINDS; applied in 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). --- Warning-only, like every trap: this never touches a score. +-- Boss-blind cautions: bosses that mechanically shut off a class of jokers +-- for the fight. Warning-only, like every trap: this never touches a score. +-- Each entry maps the boss to the catalog tags it silences and the factual +-- phrase the tooltip prints ("This ante: "). +-- +-- Five bosses debuff a whole class of cards (game.lua P_BLINDS; applied in +-- 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 = { - bl_club = {tag = 'clubs', what = 'Clubs'}, - bl_goad = {tag = 'spades', what = 'Spades'}, - bl_head = {tag = 'hearts', what = 'Hearts'}, - bl_window = {tag = 'diamonds', what = 'Diamonds'}, - bl_plant = {tag = 'faces', what = 'face cards'}, + bl_club = {tags = {clubs = true}, what = 'debuffs Clubs'}, + bl_goad = {tags = {spades = true}, what = 'debuffs Spades'}, + bl_head = {tags = {hearts = true}, what = 'debuffs Hearts'}, + bl_window = {tags = {diamonds = true}, what = 'debuffs Diamonds'}, + 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 @@ -734,16 +757,22 @@ local function tooltip_rows(card) end end - -- Boss caution: buying a joker whose card class the upcoming boss - -- debuffs is paying for a dead ante. Warnings survive learning mode. + -- Boss caution: buying a joker whose class the upcoming boss silences + -- is paying for a dead ante. Warnings survive learning mode. if in_buy_area(card) then local boss = JCA.upcoming_boss() local kill = boss and BOSS_KILLS[boss] local entry = JCA.db[key] - if kill and entry and (entry.wants[kill.tag] or entry.gives[kill.tag]) then - 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), - G.C.RED) + 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 + text_row(('This ante: %s %s'):format(bname or 'the boss', kill.what), + G.C.RED) + end end end diff --git a/test.lua b/test.lua index f55b796..2941e61 100644 --- a/test.lua +++ b/test.lua @@ -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') -------------------------------------------------------------------------------- --- The five class-killer bosses, verbatim from game.lua's P_BLINDS debuff --- configs. Every tag they reference must exist in the database, or the --- caution can never fire. +-- The class-killer bosses, verbatim from game.lua's P_BLINDS configs and the +-- blind.lua effects. Every tag they reference must exist in the database, +-- or the caution can never fire. 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 -- The Plant debuffs faces: it must catch both the payoff (Business Card -- wants faces) and the enabler (Pareidolia turns every card into one). 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_pareidolia.gives[plant.tag], 'and face enablers, whose conversion kills the deck') +ok(JCA.db.j_business.wants.faces and plant.tags.faces, + '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 -- is dealt with.