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 <noreply@anthropic.com>
This commit is contained in:
funman300
2026-07-14 13:47:27 -07:00
parent 445171dc0b
commit f73507f5c6
2 changed files with 66 additions and 0 deletions
+48
View File
@@ -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
+18
View File
@@ -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')
--------------------------------------------------------------------------------