The buy and pack endpoints reject valid purchases of Negative-edition jokers/consumables when inventory is full. The game allows them because a Negative card brings its own slot. Verified against vendors/lovely/dump/ and confirmed empirically.
Bug
Both endpoints use a plain count >= limit check:
src/lua/endpoints/buy.lua:134 (jokers), buy.lua:149 (consumables)
src/lua/endpoints/pack.lua:142 (jokers)
The game uses a more permissive formula that accounts for the card's own slot capacity. Live source:
check_for_buy_space (functions/button_callbacks.lua:2427): #G.jokers.cards < G.jokers.config.card_limit + card.ability.card_limit - card.ability.extra_slots_used
can_select_card (functions/button_callbacks.lua:2114, SMODS-patched in smods/lovely/booster.toml:333 "Support negative-ish on Jokers"): same card_limit math
Empirical: added a Negative joker to a full inventory (5/5) → count went 6/6 (limit +1). The Negative edition grants card.ability.card_limit = 1, so the game allows the purchase/selection; balatrobot blocks it with "joker slots are full".
Fix
Replicate the game formula. For jokers:
-- instead of: if count >= limit
if #G.jokers.cards >= G.jokers.config.card_limit + (card.ability.card_limit or 0) - (card.ability.extra_slots_used or 0)
Same for consumables (G.consumeables). Read the shop/pack card's ability.card_limit/extra_slots_used from the live card object (G.shop_jokers.cards[pos] / G.pack_cards.cards[pos]), not the formatted gamestate.
PoC test
def test_buy_negative_joker_when_full(self, client):
"""Negative joker can be bought even when joker slots are full."""
gamestate = load_fixture(client, "buy",
"state-SHOP--jokers.count-5--shop.cards[0].key-j_joker--shop.cards[0].edition-e_negative")
assert gamestate["jokers"]["count"] == 5
assert gamestate["jokers"]["limit"] == 5
assert gamestate["shop"]["cards"][0]["modifier"]["edition"] == "e_negative"
# Game allows: negative brings +1 slot. balatrobot currently blocks.
response = api(client, "buy", {"card": 0})
after = assert_gamestate_response(response)
assert after["jokers"]["count"] == 6
assert after["jokers"]["limit"] == 6
Fixture note: placing a Negative joker in the shop requires either a seed hunt or extending add to place jokers/consumables into G.shop_jokers/G.consumeables (it currently only adds packs/vouchers to shop areas).
Sibling of #202–#206.
The
buyandpackendpoints reject valid purchases of Negative-edition jokers/consumables when inventory is full. The game allows them because a Negative card brings its own slot. Verified againstvendors/lovely/dump/and confirmed empirically.Bug
Both endpoints use a plain
count >= limitcheck:src/lua/endpoints/buy.lua:134(jokers),buy.lua:149(consumables)src/lua/endpoints/pack.lua:142(jokers)The game uses a more permissive formula that accounts for the card's own slot capacity. Live source:
check_for_buy_space(functions/button_callbacks.lua:2427):#G.jokers.cards < G.jokers.config.card_limit + card.ability.card_limit - card.ability.extra_slots_usedcan_select_card(functions/button_callbacks.lua:2114, SMODS-patched insmods/lovely/booster.toml:333"Support negative-ish on Jokers"): samecard_limitmathEmpirical: added a Negative joker to a full inventory (5/5) → count went 6/6 (limit +1). The Negative edition grants
card.ability.card_limit = 1, so the game allows the purchase/selection; balatrobot blocks it with "joker slots are full".Fix
Replicate the game formula. For jokers:
Same for consumables (
G.consumeables). Read the shop/pack card'sability.card_limit/extra_slots_usedfrom the live card object (G.shop_jokers.cards[pos]/G.pack_cards.cards[pos]), not the formatted gamestate.PoC test
Fixture note: placing a Negative joker in the shop requires either a seed hunt or extending
addto place jokers/consumables intoG.shop_jokers/G.consumeables(it currently only adds packs/vouchers to shop areas).Sibling of #202–#206.