Respect the other two stickers: rentals bleed, perished jokers are dead
JCA.is_rental and JCA.is_perished read ability.rental and ability.perishable/perish_tally, the same flags vanilla uses (card.lua:684/676). The sell advisor now docks a rental 2 points (it drains $3 every round, game.lua:1957) and treats a perished joker -- tally 0, debuffed permanently per card.lua:716 -- as dead weight that outweighs any synergy score. Tooltips gain the mechanical facts: countdown on ticking perishables, drain rate on rentals (shop phrasing notes the $1 price), and 'Perished - it will never work again' instead of the misleading 'does nothing this blind' on permanently dead cards. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -258,6 +258,13 @@ end
|
|||||||
-- so it always breaks a tie against a clashing joker.
|
-- so it always breaks a tie against a clashing joker.
|
||||||
local CLASH_PENALTY = 3
|
local CLASH_PENALTY = 3
|
||||||
|
|
||||||
|
-- Sticker weights, same philosophy: mechanical facts only. A rental bleeds
|
||||||
|
-- $3 every round, so between two equally-scoring jokers, cut the rental. A
|
||||||
|
-- PERISHED joker (perishable, tally at 0) is debuffed forever -- dead weight
|
||||||
|
-- at any synergy score, so its penalty dwarfs every possible total.
|
||||||
|
local RENTAL_PENALTY = 2
|
||||||
|
local PERISHED_PENALTY = 1000
|
||||||
|
|
||||||
local function keep_score(card, cards)
|
local function keep_score(card, cards)
|
||||||
local _, total = JCA.partners_for(card)
|
local _, total = JCA.partners_for(card)
|
||||||
local key = card.config.center.key
|
local key = card.config.center.key
|
||||||
@@ -267,6 +274,8 @@ local function keep_score(card, cards)
|
|||||||
total = total - CLASH_PENALTY
|
total = total - CLASH_PENALTY
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
if JCA.is_rental(card) then total = total - RENTAL_PENALTY end
|
||||||
|
if JCA.is_perished(card) then total = total - PERISHED_PENALTY end
|
||||||
return total
|
return total
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -284,6 +293,22 @@ function JCA.is_eternal(card)
|
|||||||
return not not (card.ability and card.ability.eternal)
|
return not not (card.ability and card.ability.eternal)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Rental and Perishable are the other two stickers the advisor must respect,
|
||||||
|
-- and both are plain ability flags like eternal (card.lua:684, 676). A rental
|
||||||
|
-- drains G.GAME.rental_rate every round (card.lua:2646; $3, game.lua:1957).
|
||||||
|
-- A perishable joker counts perish_tally down each round (card.lua:2652) and
|
||||||
|
-- once it hits 0 the card is debuffed PERMANENTLY (card.lua:716) -- not "this
|
||||||
|
-- blind", forever. Eternal and perishable are mutually exclusive (set_perishable
|
||||||
|
-- bails on eternals), so a perished joker is always legal to sell.
|
||||||
|
function JCA.is_rental(card)
|
||||||
|
return not not (card.ability and card.ability.rental)
|
||||||
|
end
|
||||||
|
|
||||||
|
function JCA.is_perished(card)
|
||||||
|
local a = card.ability
|
||||||
|
return not not (a and a.perishable and (a.perish_tally or 0) <= 0)
|
||||||
|
end
|
||||||
|
|
||||||
function JCA.weakest_link()
|
function JCA.weakest_link()
|
||||||
if not (G.jokers and G.jokers.cards) then return nil end
|
if not (G.jokers and G.jokers.cards) then return nil end
|
||||||
local cards = G.jokers.cards
|
local cards = G.jokers.cards
|
||||||
@@ -567,13 +592,32 @@ local function tooltip_rows(card)
|
|||||||
local caution = in_buy_area(card) and JCA.cautions[key]
|
local caution = in_buy_area(card) and JCA.cautions[key]
|
||||||
if caution then text_row('Caution: ' .. caution, G.C.RED) end
|
if caution then text_row('Caution: ' .. caution, G.C.RED) end
|
||||||
|
|
||||||
|
-- Sticker facts (any area -- higher stakes put stickers on shop jokers
|
||||||
|
-- too). Mechanical numbers from the game source, not judgements, so
|
||||||
|
-- learning mode keeps them.
|
||||||
|
if card.ability and card.ability.perishable and not JCA.is_perished(card) then
|
||||||
|
local n = card.ability.perish_tally or 0
|
||||||
|
text_row(('Perishable - %d round%s before it dies')
|
||||||
|
:format(n, n == 1 and '' or 's'), G.C.RED)
|
||||||
|
end
|
||||||
|
if JCA.is_rental(card) then
|
||||||
|
local rate = (G.GAME and G.GAME.rental_rate) or 3
|
||||||
|
text_row(in_buy_area(card)
|
||||||
|
and ('Rental - $1 now, but $' .. rate .. ' every round after')
|
||||||
|
or ('Rental - drains $' .. rate .. ' every round'), G.C.RED)
|
||||||
|
end
|
||||||
|
|
||||||
-- Positional jokers: say what this one is doing to its neighbour RIGHT NOW.
|
-- Positional jokers: say what this one is doing to its neighbour RIGHT NOW.
|
||||||
-- The board order decides it, so only an owned joker has an answer. These are
|
-- The board order decides it, so only an owned joker has an answer. These are
|
||||||
-- explanations, not verdicts, so learning mode keeps them.
|
-- explanations, not verdicts, so learning mode keeps them.
|
||||||
if card.area == G.jokers then
|
if card.area == G.jokers then
|
||||||
-- A debuffed joker does nothing at all this blind, whatever its combos say.
|
-- A debuffed joker does nothing at all this blind, whatever its combos
|
||||||
|
-- say -- and a PERISHED one is debuffed for good (card.lua:716), which
|
||||||
|
-- deserves the honest tense.
|
||||||
if card.debuff then
|
if card.debuff then
|
||||||
text_row('Debuffed - does nothing this blind', G.C.RED)
|
text_row(JCA.is_perished(card)
|
||||||
|
and 'Perished - it will never work again'
|
||||||
|
or 'Debuffed - does nothing this blind', G.C.RED)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Copy jokers. A Blueprint in the wrong slot is a dead card that looks fine.
|
-- Copy jokers. A Blueprint in the wrong slot is a dead card that looks fine.
|
||||||
|
|||||||
@@ -382,6 +382,39 @@ ok(pick ~= et[1], 'but never an Eternal one, because it cannot be sold',
|
|||||||
pick and pick.config.center.key or 'nil')
|
pick and pick.config.center.key or 'nil')
|
||||||
eq(pick, et[2], 'it falls through to the next sellable candidate instead')
|
eq(pick, et[2], 'it falls through to the next sellable candidate instead')
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
section('Engine: the sell advisor weighs rentals and perished jokers')
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
-- ability.rental drains $3 a round (card.lua:2646, game.lua:1957); a perishable
|
||||||
|
-- joker whose tally ran out is debuffed FOREVER (card.lua:716). Both are flags
|
||||||
|
-- on card.ability, read the same way as eternal.
|
||||||
|
local plain = field('j_baron', 'j_joker')
|
||||||
|
eq(JCA.is_rental(plain[1]), false, 'no sticker reads as no rental')
|
||||||
|
plain[1].ability = {rental = true}
|
||||||
|
eq(JCA.is_rental(plain[1]), true, 'ability.rental reads as a rental')
|
||||||
|
plain[2].ability = {perishable = true, perish_tally = 3}
|
||||||
|
eq(JCA.is_perished(plain[2]), false, 'a ticking perishable has not perished yet')
|
||||||
|
plain[2].ability.perish_tally = 0
|
||||||
|
eq(JCA.is_perished(plain[2]), true, 'tally 0 means debuffed for good')
|
||||||
|
|
||||||
|
-- Three mutually inert jokers tie at 0, so nothing stands out to cut --
|
||||||
|
-- until one of them is a rental, which bleeds money every round.
|
||||||
|
local rent = field('j_joker', 'j_half', 'j_misprint')
|
||||||
|
G.jokers.config.card_limit = 3
|
||||||
|
eq(JCA.weakest_link(), nil, 'an all-tied board flags nobody')
|
||||||
|
rent[2].ability = {rental = true}
|
||||||
|
eq(JCA.weakest_link(), rent[2], 'the rental loses the tie: it drains $3 a round')
|
||||||
|
|
||||||
|
-- A perished joker is dead weight at ANY synergy score: it outweighs even a
|
||||||
|
-- famous-pair member against the board's zero-scorer.
|
||||||
|
local per = field('j_baron', 'j_mime', 'j_joker')
|
||||||
|
G.jokers.config.card_limit = 3
|
||||||
|
eq(JCA.weakest_link(), per[3], 'normally the zero-scorer is the cut')
|
||||||
|
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: Ceremonial Dagger names its victim')
|
section('Engine: Ceremonial Dagger names its victim')
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|||||||
Reference in New Issue
Block a user