From f73507f5c6960950915c3e9825fb24aaa053d66c Mon Sep 17 00:00:00 2001 From: funman300 Date: Tue, 14 Jul 2026 13:47:27 -0700 Subject: [PATCH] Frame suit and hand jokers with this run's actual deck and levels Buy-area tooltips on suit-tagged jokers now show the deck ratio ('Your deck: 18 of 52 cards are Hearts', from card.base.suit -- the field vanilla scores by) and hand-cluster jokers show the hand's level when it has been built past 1. Pure context: the pairwise score never reads the deck, the lines are capped at two, and iteration order is fixed so the tooltip is stable across hovers. Co-Authored-By: Claude Fable 5 --- main.lua | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ test.lua | 18 ++++++++++++++++++ 2 files changed, 66 insertions(+) diff --git a/main.lua b/main.lua index 0fd53a9..445ce82 100644 --- a/main.lua +++ b/main.lua @@ -325,6 +325,21 @@ local BOSS_KILLS = { } JCA.boss_kills = BOSS_KILLS +-- How much of the deck actually belongs to a suit (base suits, the field +-- vanilla sorts and scores by -- card.lua:145). Context for suit jokers: +-- the score never reads the deck, but the player deciding on Bloodstone +-- deserves to know whether it is 21 Hearts or 6. +function JCA.deck_suit_count(suit) + local n, total = 0, 0 + for _, c in ipairs(G.playing_cards or {}) do + if c.base and c.base.suit then + total = total + 1 + if c.base.suit == suit then n = n + 1 end + end + end + return n, total +end + -- The boss still ahead this ante, or nil once it is dealt with. Both fields -- live in G.GAME.round_resets (game.lua:2019, misc_functions.lua:398). function JCA.upcoming_boss() @@ -618,6 +633,39 @@ local function tooltip_rows(card) local caution = in_buy_area(card) and JCA.cautions[key] if caution then text_row('Caution: ' .. caution, G.C.RED) end + -- Run context: this deck, these hand levels. Facts that frame the tags, + -- never part of the score; capped at two lines so multi-suit jokers do + -- not flood the tooltip. Fixed iteration order keeps hovers stable. + if in_buy_area(card) then + local entry = JCA.db[key] + local ctx = 0 + if entry then + for _, s in ipairs({{ 'hearts', 'Hearts' }, { 'diamonds', 'Diamonds' }, + { 'spades', 'Spades' }, { 'clubs', 'Clubs' }}) do + if ctx < 2 and (entry.wants[s[1]] or entry.gives[s[1]]) then + local n, total = JCA.deck_suit_count(s[2]) + if total > 0 then + text_row(('Your deck: %d of %d cards are %s'):format(n, total, s[2])) + ctx = ctx + 1 + end + end + end + for _, h in ipairs({{ 'pair', 'Pair' }, { 'two_pair', 'Two Pair' }, + { 'three_kind', 'Three of a Kind' }, + { 'four_kind', 'Four of a Kind' }, + { 'straight', 'Straight' }, { 'flush', 'Flush' }}) do + if ctx < 2 and entry.wants[h[1]] then + local lvl = G.GAME and G.GAME.hands and G.GAME.hands[h[2]] + and G.GAME.hands[h[2]].level + if (lvl or 1) >= 2 then + text_row(('Your %s hand is level %d'):format(h[2], lvl)) + ctx = ctx + 1 + end + end + end + end + end + -- Boss caution: buying a joker whose card class the upcoming boss -- debuffs is paying for a dead ante. Warnings survive learning mode. if in_buy_area(card) then diff --git a/test.lua b/test.lua index 68f844f..024034b 100644 --- a/test.lua +++ b/test.lua @@ -415,6 +415,24 @@ per[2].ability = {perishable = true, perish_tally = 0} eq(JCA.weakest_link(), per[2], 'but a perished joker is the cut at any score - it will never work again') +-------------------------------------------------------------------------------- +section('Engine: deck context counts base suits') +-------------------------------------------------------------------------------- + +-- Counts card.base.suit, the field vanilla scores by (card.lua:145). The +-- score never reads these numbers; they only frame the tooltip. +G.playing_cards = { + {base = {suit = 'Hearts'}}, {base = {suit = 'Hearts'}}, + {base = {suit = 'Spades'}}, {base = {suit = 'Clubs'}}, +} +local n, deck_total = JCA.deck_suit_count('Hearts') +eq(n, 2, 'counts the cards of the asked suit') +eq(deck_total, 4, 'and the whole deck for the ratio') +eq(JCA.deck_suit_count('Diamonds'), 0, 'a missing suit counts as zero') +G.playing_cards = nil +n, deck_total = JCA.deck_suit_count('Hearts') +eq(deck_total, 0, 'no deck (menus, tests) reads as an empty deck') + -------------------------------------------------------------------------------- section('Engine: boss-blind cautions know who the boss silences') --------------------------------------------------------------------------------