33--- @type BB_LOGGER
44local BB_LOGGER = assert (SMODS .load_file (" src/lua/utils/logger.lua" ))()
55
6+ -- Re-entrancy guard: prevents double-firing use_card when a previous
7+ -- pack selection is still being processed (e.g. Black Hole animations).
8+ local selection_in_progress = false
9+
610-- ==========================================================================
711-- Pack Select Endpoint Params
812-- ==========================================================================
@@ -110,6 +114,15 @@ return {
110114 return
111115 end
112116
117+ -- Block re-entrant calls while a previous selection is processing
118+ if selection_in_progress then
119+ send_response ({
120+ message = " Pack selection already in progress" ,
121+ name = BB_ERROR_NAMES .NOT_ALLOWED ,
122+ })
123+ return
124+ end
125+
113126 -- Validate pack_cards exists
114127 if not G .pack_cards or G .pack_cards .REMOVED then
115128 send_response ({
@@ -239,6 +252,7 @@ return {
239252
240253 local pack_choices_before = G .GAME .pack_choices or 0
241254
255+ selection_in_progress = true
242256 G .FUNCS .use_card (btn )
243257
244258 -- Wait for action to complete - check pack_choices to determine expected state
@@ -255,6 +269,7 @@ return {
255269 and G .STATE == G .STATES .SMODS_BOOSTER_OPENED
256270
257271 if pack_stable then
272+ selection_in_progress = false
258273 sendDebugMessage (" Return pack() after selection (more choices remain)" , " BB.ENDPOINTS" )
259274 send_response (BB_GAMESTATE .get_gamestate ())
260275 return true
@@ -265,10 +280,24 @@ return {
265280 local back_to_shop = G .STATE == G .STATES .SHOP
266281
267282 if pack_closed and back_to_shop then
283+ selection_in_progress = false
268284 sendDebugMessage (" Return pack() after selection" , " BB.ENDPOINTS" )
269285 send_response (BB_GAMESTATE .get_gamestate ())
270286 return true
271287 end
288+
289+ -- Debug: log what's blocking
290+ local state_name = " ?"
291+ if G .STATES then
292+ for name , value in pairs (G .STATES ) do
293+ if value == G .STATE then state_name = name break end
294+ end
295+ end
296+ sendDebugMessage (string.format (
297+ " pack() wait: closed=%s state=%s complete=%s choices=%s won=%s" ,
298+ tostring (pack_closed ), state_name , tostring (G .STATE_COMPLETE ),
299+ tostring (G .GAME .pack_choices ), tostring (G .GAME .won )
300+ ), " BB.ENDPOINTS" )
272301 end
273302 return false
274303 end ,
@@ -279,6 +308,7 @@ return {
279308
280309 -- Handle skip
281310 if args .skip then
311+ selection_in_progress = false -- Clear guard so skip can proceed after stuck selection
282312 local pack_count = G .pack_cards .config and G .pack_cards .config .card_count or 0
283313 sendDebugMessage (string.format (" Pack: skipping (%d cards remaining)" , pack_count ), " BB.ENDPOINTS" )
284314 G .FUNCS .skip_booster ({})
@@ -304,12 +334,10 @@ return {
304334 end
305335
306336 -- Wait for hand cards to load for Arcana and Spectral packs
307- local pack_key = G .pack_cards
308- and G .pack_cards .cards
309- and G .pack_cards .cards [1 ]
310- and G .pack_cards .cards [1 ].ability
311- and G .pack_cards .cards [1 ].ability .set
312- local needs_hand = pack_key == " Tarot" or pack_key == " Spectral"
337+ -- Check if hand cards are dealt (Arcana/Spectral packs deal hand cards).
338+ -- Don't infer pack type from the first card's set — Black Hole is
339+ -- set=Spectral but appears in Celestial packs, causing a false match.
340+ local needs_hand = G .hand and G .hand .cards and # G .hand .cards > 0
313341
314342 if needs_hand then
315343 -- Wait for hand cards to be fully loaded and positioned
0 commit comments