diff --git a/lovely/history.toml b/lovely/history.toml index ad8249e..0d6009e 100644 --- a/lovely/history.toml +++ b/lovely/history.toml @@ -1,5 +1,5 @@ [manifest] -version = "1.0" +version = "1.1" dump_lua = true priority = 5 @@ -7,38 +7,25 @@ priority = 5 [patches.copy] target = "globals.lua" position = "append" -sources = [ - "src/Init.lua" -] +sources = [ "src/Init.lua" ] [[patches]] [patches.copy] target = "main.lua" position = "append" -sources = [ - "src/RunHistory.lua", - "src/RunStorage.lua", - "src/Utils.lua" -] +sources = [ "src/RunHistory.lua", "src/RunStorage.lua", "src/Utils.lua" ] [[patches]] [patches.copy] target = "functions/UI_definitions.lua" position = "append" -sources = [ - "src/UI/BaseUI.lua", - "src/UI/RunHistoryUI.lua", - "src/UI/RunStorageUI.lua" -] +sources = [ "src/UI/BaseUI.lua", "src/UI/RunHistoryUI.lua", "src/UI/RunStorageUI.lua" ] [[patches]] [patches.copy] target = "functions/button_callbacks.lua" position = "append" -sources = [ - "src/UI/ButtonCallbacks.lua" -] - +sources = [ "src/UI/ButtonCallbacks.lua" ] [[patches]] [patches.pattern] target = "functions/UI_definitions.lua" @@ -57,9 +44,6 @@ match_indent = true overwrite = false payload = "DV.HIST.queue_save_manager()" -# Below are extensions to engine/save_manager.lua; -# special considerations are needed, because the save manager runs on a thread. - [[patches]] [patches.module] source = "src/SaveManager.lua" @@ -67,13 +51,10 @@ before = "engine/save_manager.lua" name = "DV" load_now = true -# TODO: `load_now` above is a stopgap solution to the lazy module loading introduced in Lovely v0.6.0 -# My hunch is that lazy loading breaks something due to the fact that save manager runs on a thread. - [[patches]] [patches.pattern] target = "engine/save_manager.lua" -pattern = "compress_and_save(prefix_profile..'save.jkr', request.save_table)" +pattern = "tal_compress_and_save(prefix_profile..'save.jkr', request.save_table, request.talisman)" position = "after" match_indent = true overwrite = false diff --git a/lovely/settings.toml b/lovely/settings.toml index 24c90e0..a7ce902 100644 --- a/lovely/settings.toml +++ b/lovely/settings.toml @@ -1,16 +1,8 @@ [manifest] -version = "1.0" +version = "1.1" dump_lua = true priority = 10 -[[patches]] -[patches.copy] -target = "game.lua" -position = "append" -sources = [ - "lib/Balatro-Settings/src/Settings.lua" -] - [[patches]] [patches.pattern] target = "functions/UI_definitions.lua" @@ -18,21 +10,4 @@ pattern = "local t = create_UIBox_generic_options({back_func = 'options',content position = "before" match_indent = true overwrite = false -payload = ''' -if not DV.settings_tab then - tabs[#tabs+1] = DV.create_settings_tab() - DV.settings_tab = true -end -''' - -[[patches]] -[patches.regex] -target = "functions/UI_definitions.lua" -pattern = '''tab_alignment = 'tm',\n\s+snap_to_nav = true}\n\s+\)}}\)\n''' -position = "after" -match_indent = true -overwrite = false -# Reset for next UI create/update -payload = ''' -DV.settings_tab = false -''' +payload = "tabs[#tabs+1] = DV.create_settings_tab(#tabs)" diff --git a/metadata.json b/metadata.json index c5710b9..8f71b19 100644 --- a/metadata.json +++ b/metadata.json @@ -1,19 +1,20 @@ { - "id": "DVHistory", - "name": "Divvy's History", - "author": ["Divvy C."], - "description": "Save and load any number of runs! Also, view the history of your played hands and shop purchases!", - "prefix": "dvhistory", - "main_file": "lib/steamodded.lua", - "priority": 0, - "badge_colour": "6495ED", - "badge_text_colour": "FFFFFF", - "version": "3.0.0", - "dependencies": [ - "Lovely (>=0.6)" - ], - "conflicts": [ - "Talisman (>=0.0)" - ], - "dump_loc": false + "id": "DVHistory", + "name": "Divvy's History (Fixed Update)", + "author": [ + "Divvy C.", + "Community" + ], + "description": "Save and load any number of runs! Also, view the history of your played hands and shop purchases! Fixed for Talisman and modern Lovely.", + "prefix": "dvhistory", + "main_file": "lib/steamodded.lua", + "priority": 0, + "badge_colour": "6495ED", + "badge_text_colour": "FFFFFF", + "version": "1.1", + "dependencies": [ + "Lovely (>=0.15)" + ], + "conflicts": [], + "dump_loc": false } diff --git a/src/Init.lua b/src/Init.lua index 6a213a7..ce563ff 100644 --- a/src/Init.lua +++ b/src/Init.lua @@ -4,8 +4,6 @@ if not DV then DV = {} end -if DV.HIST then error("Cannot load Divvy's History multiple times!") end - DV.HIST = { -- TODO: Move key data into `G.GAME.DV`? history = {}, @@ -40,19 +38,83 @@ DV.HIST._start_up = Game.start_up function Game:start_up() DV.HIST._start_up(self) + -- Initialize settings framework (from DVSettings) if not G.SETTINGS.DV then G.SETTINGS.DV = {} end + if not G.DV then G.DV = {} end + if not G.DV.options then G.DV.options = {} end + if not G.SETTINGS.DV.HIST then G.SETTINGS.DV.HIST = true - G.SETTINGS.DV.autosave = true G.SETTINGS.DV.autosaves_per_run = 5 G.SETTINGS.DV.autosaves_total = 10 end - if not DV.settings then error("Divvy's History requires Divvy's Setting tools; re-install Divvy's History mod and double-check that there is a 'DVSettings' folder") end + DV.settings = true G.DV.options["Autosaves"] = "get_history_settings_page" + + -- Settings UI callback (from DVSettings) + function G.FUNCS.dv_settings_change(args) + if not args or not args.cycle_config then return end + local callback_args = args.cycle_config.opt_args + local page_object = callback_args.ui + local page_wrap = page_object.parent + local new_option_idx = args.to_key + local new_option_def = callback_args.indexed_options[new_option_idx] + page_wrap.config.object:remove() + page_wrap.config.object = UIBox({ + definition = DV[G.DV.options[new_option_def]](), + config = { parent = page_wrap, type = "cm" } + }) + page_wrap.UIBox:recalculate() + end +end + +-- Settings Tab Logic (from DVSettings) +function DV.create_settings_tab(num_tabs) + if num_tabs > 4 then return nil end + return { + label = "Other", + tab_definition_function = DV.get_settings_tab, + } end +function DV.get_settings_tab() + local options = {} + local first_option_def = nil + for option_name, option_def in pairs(G.DV.options) do + if #options == 0 then first_option_def = option_def end + table.insert(options, option_name) + end + local first_page = UIBox({ + definition = DV[first_option_def](), + config = {type = "cm"} + }) + if #options == 1 then + return + {n=G.UIT.ROOT, config={align="cm", padding = 0.1, r = 0.1, colour = G.C.CLEAR}, nodes={ + {n=G.UIT.O, config={object = first_page}} + }} + end + return + {n=G.UIT.ROOT, config={align = "cm", padding = 0.1, r = 0.1, colour = G.C.CLEAR}, nodes={ + {n=G.UIT.C, config={align = "cm"}, nodes={ + {n=G.UIT.R, config={align = "tm", minh = 5.5}, nodes={ + {n=G.UIT.O, config={object = first_page}} + }}, + {n=G.UIT.R, config={align = "bm"}, nodes={ + create_option_cycle({ + options = options, + current_option = 1, + opt_callback = "dv_settings_change", + opt_args = {ui = first_page, indexed_options = options}, + w = 5, colour = G.C.RED, cycle_shoulders = false}) + }} + }} + }} +end + + DV.HIST._start_run = Game.start_run function Game:start_run(args) DV.HIST._start_run(self, args) @@ -70,14 +132,34 @@ function Game:start_run(args) ante = 0, } else - -- Loaded run, so extract mod data from loaded data: - DV.HIST.history = G.GAME.DV.history - DV.HIST.latest = G.GAME.DV.latest + -- Loaded run -- G.GAME.DV may be absent if the save predates DVHistory: + if not G.GAME.DV then G.GAME.DV = {} end + -- Generate a run_id if missing (needed by SaveManager to avoid a thread crash): + if not G.GAME.DV.run_id then G.GAME.DV.run_id = DV.HIST.simple_uuid() end + DV.HIST.history = G.GAME.DV.history or {} + DV.HIST.latest = G.GAME.DV.latest or { rel_round = 0, abs_round = 0, ante = 0 } + + -- If history is empty the current blind slot was never recorded (select_blind already + -- fired before this continue). Build a minimal slot from the live game state so that + -- shop hooks (get_shop_entry) don't crash on history[ante][round] = nil: + if DV.HIST.latest.ante == 0 then + local ante = (G.GAME.round_resets and G.GAME.round_resets.ante) or 1 + local states = (G.GAME.round_resets and G.GAME.round_resets.blind_states) or {} + local rel_round = (states["Small"] == "Current" and 1) + or (states["Big"] == "Current" and 2) + or 3 + DV.HIST.latest.ante = ante + DV.HIST.latest.rel_round = rel_round + DV.HIST.latest.abs_round = (ante - 1) * 3 + rel_round + if not DV.HIST.history[ante] then DV.HIST.history[ante] = {} end + if not DV.HIST.history[ante][rel_round] then DV.HIST.history[ante][rel_round] = {} end + end end end DV.HIST._save_run = save_run function save_run() + if not G.GAME.DV then G.GAME.DV = {} end G.GAME.DV.history = DV.HIST.history G.GAME.DV.latest = DV.HIST.latest DV.HIST._save_run() diff --git a/src/RunHistory.lua b/src/RunHistory.lua index 41ef4d0..ea85810 100644 --- a/src/RunHistory.lua +++ b/src/RunHistory.lua @@ -116,12 +116,6 @@ function G.FUNCS.buy_from_shop(e) elseif card.ability.set == "Tarot" or card.ability.set == "Planet" or card.ability.set == "Spectral" then table.insert(shop_entry.consumables, DV.HIST.get_consumable_data(card)) elseif card.ability.set == "Default" or card.ability.set == "Enhanced" then - -- If player bought the Magic Trick voucher and a playing card - -- *in the same shop*, then there would be no `play_cards` field. - -- TODO: Consider a better place/way of doing this: - if not shop_entry.play_cards and G.GAME.playing_card_rate > 0 then - shop_entry.play_cards = {} - end table.insert(shop_entry.play_cards, DV.HIST.get_card_data(card)) end end diff --git a/src/RunStorage.lua b/src/RunStorage.lua index af06d04..12dd7fa 100644 --- a/src/RunStorage.lua +++ b/src/RunStorage.lua @@ -38,6 +38,7 @@ function DV.HIST.store_run(store_type) STATE = G.STATE, ACTION = G.action or nil, BLIND = G.GAME.blind:save(), + SCORING_CALC = G.GAME.current_scoring_calculation and G.GAME.current_scoring_calculation:save() or nil, BACK = G.GAME.selected_back:save(), HISTORY = history_data, VERSION = G.VERSION @@ -58,7 +59,8 @@ function DV.HIST.queue_save_manager() profile_num = G.SETTINGS.profile, dv_settings = G.SETTINGS.DV, dv_paths = DV.HIST.PATHS, - dv_types = DV.HIST.STORAGE_TYPE + dv_types = DV.HIST.STORAGE_TYPE, + talisman = (Talisman and Talisman.config_file and Talisman.config_file.break_infinity) }) end @@ -77,15 +79,8 @@ function Game:update_shop(dt) if DV.HIST.autosave then G.E_MANAGER:add_event(Event({ -- This event is queued after all shop events; - -- however, shop events queue more (nested) events, so triggering - -- a save in this event will actually run before most shop events! - trigger = "after", - -- The delay in only necessary to allow some shop events to take place, such as the Coupon tag - -- TODO: Figure out a better way to do this: - -- either combine some shop condition with top-level `if` here, - -- or trigger run storage at a slightly different time? - delay = 1.5, - -- + -- however, shop events queue more events, so triggering a save + -- in this event will actually run before most shop events! func = function() G.E_MANAGER:add_event(Event({ -- Hence, this event is queued after all shop events are queued: @@ -128,13 +123,32 @@ end function DV.HIST.is_game_over() local round_beat = false - if G.GAME.chips - G.GAME.blind.chips >= 0 then + + local function _compare(a, b) + if to_big then + a = to_big(a) + b = to_big(b) + return a >= b + end + return a >= b + end + + local function _compare_ratio(a, b, ratio) + if to_big then + a = to_big(a) + b = to_big(b) + return a / b >= to_big(ratio) + end + return a / b >= ratio + end + + if _compare(G.GAME.chips, G.GAME.blind.chips) then round_beat = true else -- Check for any saving graces: -- TODO: Need a more generic way that doesn't have side-effects (for other mod effects) for _, joker_obj in ipairs(G.jokers.cards) do - if joker_obj.ability.name == "Mr. Bones" and G.GAME.chips/G.GAME.blind.chips >= 0.25 then + if joker_obj.ability.name == "Mr. Bones" and _compare_ratio(G.GAME.chips, G.GAME.blind.chips, 0.25) then round_beat = true end end diff --git a/src/SaveManager.lua b/src/SaveManager.lua index 7046c6c..b9869ec 100644 --- a/src/SaveManager.lua +++ b/src/SaveManager.lua @@ -35,7 +35,7 @@ function DV.HIST.execute_save_manager(request) save_path = DV.HIST.manage_save(request, history_dir, file_name) end - compress_and_save(save_path, request.save_table) + tal_compress_and_save(save_path, request.save_table, request.talisman) end function DV.HIST.manage_save(request, history_dir, file_name) @@ -114,7 +114,7 @@ end function DV.HIST.get_run_name(save_table) local seed = save_table.GAME.pseudorandom.seed - local runid = save_table.GAME.DV.run_id + local runid = save_table.GAME.DV.run_id or "unknown" return seed .."_".. runid end diff --git a/src/UI/BaseUI.lua b/src/UI/BaseUI.lua index 5e1c099..92c940d 100644 --- a/src/UI/BaseUI.lua +++ b/src/UI/BaseUI.lua @@ -126,3 +126,4 @@ function create_popup_UIBox_tooltip(tooltip) end return DV.HIST._create_tooltip(tooltip) end + diff --git a/src/UI/ButtonCallbacks.lua b/src/UI/ButtonCallbacks.lua index e638092..3c75443 100644 --- a/src/UI/ButtonCallbacks.lua +++ b/src/UI/ButtonCallbacks.lua @@ -116,6 +116,16 @@ function G.FUNCS.dv_hist_update_runs_page(args) runs_wrap.UIBox:recalculate() end +function G.FUNCS.dv_hist_delete_run(e) + if not e then return end + + local path_to_delete = (G.SETTINGS.profile or 1) .."/DVHistory/".. e.config.ref_table.run_path + love.filesystem.remove(path_to_delete) + + -- Refresh the UI view + G.FUNCS.dv_hist_select_run(e) +end + function G.FUNCS.dv_hist_load_run(e) if not e then return end diff --git a/src/UI/RunHistoryUI.lua b/src/UI/RunHistoryUI.lua index 57ee73c..42d049b 100644 --- a/src/UI/RunHistoryUI.lua +++ b/src/UI/RunHistoryUI.lua @@ -315,7 +315,7 @@ function DV.HIST.get_cards_area(norm_width, cards) local card_obj = DV.HIST.create_card(G.P_CARDS[card.id], G.P_CENTERS[card.type], card_scale) if card.edition then card_obj:set_edition(card.edition, true, true) end - if card.seal then card_obj:set_seal(card.seal, true, true) end + if card.seal then card_obj:set_seal(card.seal, true) end if not card.scoring then card_obj.greyed = true end cards_area:emplace(card_obj) diff --git a/src/UI/RunStorageUI.lua b/src/UI/RunStorageUI.lua index babbc54..170f813 100644 --- a/src/UI/RunStorageUI.lua +++ b/src/UI/RunStorageUI.lua @@ -76,8 +76,14 @@ function DV.HIST.get_stored_runs_page(args) for i = 1, actual_runs_on_page do local next_idx = offset + i - local run_data = get_compressed(G.SETTINGS.profile .."/DVHistory/".. run_paths[next_idx]) - if run_data ~= nil then run_data = STR_UNPACK(run_data) end + local run_data_str = get_compressed(G.SETTINGS.profile .."/DVHistory/".. run_paths[next_idx]) + local run_data = nil + if run_data_str ~= nil then + if string.find(run_data_str, "%{GAME % = %{won = true%}%}") then + run_data_str = string.gsub(run_data_str, "if.-return.-%{GAME.-won.-=.-true.-%}.-end", "") + end + run_data = STR_UNPACK(run_data_str) + end table.insert(run_nodes, DV.HIST.get_stored_run_node(run_paths[next_idx], run_data)) end @@ -105,9 +111,17 @@ function DV.HIST.get_stored_run_node(run_path, run_data) local tooltip = {dv=true, filler={func = DV.HIST.get_run_overlay, args = run_data}} return - {n=G.UIT.R, config={align = "cm", padding = 0.05}, nodes={ - {n=G.UIT.R, config={button = "dv_hist_load_run", ref_table = {run_path = run_path, run_data = run_data}, align = "cl", colour = G.C.RED, minw = 9.6, padding = 0.1, r = 0.1, on_demand_tooltip = tooltip, hover = true, shadow = true}, nodes={ - {n=G.UIT.T, config={text = run_name, colour=G.C.UI.TEXT_LIGHT, scale = 0.45}} + {n=G.UIT.R, config={align = "cm", padding = 0.05, minw = 11}, nodes={ + {n=G.UIT.C, config={align = "cl"}, nodes={ + {n=G.UIT.R, config={button = "dv_hist_load_run", ref_table = {run_path = run_path, run_data = run_data}, align = "cl", colour = G.C.RED, minw = 8.6, padding = 0.1, r = 0.1, on_demand_tooltip = tooltip, hover = true, shadow = true}, nodes={ + {n=G.UIT.T, config={text = run_name, colour=G.C.UI.TEXT_LIGHT, scale = 0.45}} + }} + }}, + {n=G.UIT.C, config={align = "cr", minw = 0.4}, nodes={}}, + {n=G.UIT.C, config={align = "cm"}, nodes={ + {n=G.UIT.R, config={button = "dv_hist_delete_run", ref_table = {run_path = run_path}, align = "cm", colour = G.C.RED, minw = 0.8, minh = 0.7, r = 0.1, hover = true, shadow = true}, nodes={ + {n=G.UIT.T, config={text = "X", colour=G.C.UI.TEXT_LIGHT, scale = 0.45}} + }} }} }} end @@ -125,10 +139,10 @@ function DV.HIST.get_run_overlay(run) -- Seed in the top-left, and save date in the top-right: {n=G.UIT.R, config={align = "cm"}, nodes={ {n=G.UIT.C, config={align = "cl", minw = ov_width/2.2}, nodes={ - {n=G.UIT.T, config={text = "Seed: " .. run.GAME.pseudorandom.seed, align = "cl", colour = G.C.UI.TEXT_LIGHT, scale = 0.25}} + {n=G.UIT.T, config={text = "Seed: " .. tostring((run.GAME.pseudorandom and run.GAME.pseudorandom.seed) or "Unknown"), align = "cl", colour = G.C.UI.TEXT_LIGHT, scale = 0.25}} }}, {n=G.UIT.C, config={align = "cr", minw = ov_width/2.2}, nodes={ - {n=G.UIT.T, config={text = (run.date_str or ""), align = "cr", colour = G.C.UI.TEXT_LIGHT, scale = 0.25}} + {n=G.UIT.T, config={text = tostring(run.date_str or ""), align = "cr", colour = G.C.UI.TEXT_LIGHT, scale = 0.25}} }} }}, @@ -136,7 +150,7 @@ function DV.HIST.get_run_overlay(run) (run.GAME.challenge and {n=G.UIT.R, config={minh = 0.05}, nodes={}} or nil), (run.GAME.challenge and {n=G.UIT.R, config={align = "cm"}, nodes={ - {n=G.UIT.T, config={text = "'"..run.GAME.challenge_tab.name.."' Challenge", align = "cm", colour = G.C.UI.TEXT_LIGHT, scale = scale}} + {n=G.UIT.T, config={text = "'"..tostring(run.GAME.challenge_tab.name).."' Challenge", align = "cm", colour = G.C.UI.TEXT_LIGHT, scale = scale}} }} or nil), -- Main info: @@ -171,7 +185,9 @@ function DV.HIST.get_run_summary_deck(run_data) {card_limit = 1, type = "deck", highlight_limit = 0, deck_height = 0.6, thin_draw = 1} ) - G.GAME.viewed_back:change_to(G.P_CENTERS[run_data.BACK.key]) + if run_data.BACK and run_data.BACK.key then + G.GAME.viewed_back:change_to(G.P_CENTERS[run_data.BACK.key]) + end -- Populate deck, to add volume to its sprite: for i = 1, 10 do @@ -201,25 +217,35 @@ function DV.HIST.get_run_summary_data(run_data, text_scale) local value_node = {n=G.UIT.C, config={align = "cl", minw = w_num}, nodes={ (label == "Stake") - and {n=G.UIT.O, config={object = get_stake_sprite(run_data.GAME.stake, 0.4)}} + and {n=G.UIT.O, config={object = get_stake_sprite(run_data.GAME.stake or 1, 0.4)}} or {n=G.UIT.T, config={text = value, align = "cl", colour = value_colour, scale = text_scale}} }} return {n=G.UIT.R, config={align = "cm"}, nodes={label_node, value_node}} end + local ante = run_data.GAME.round_resets and run_data.GAME.round_resets.ante or "?" -- Assuming that the parent node has `n=G.UIT.C`; -- use as: `{..., nodes = DV.HIST.get_run_summary_data(..)}` return { - get_label_and_value("Round", run_data.GAME.round, G.C.RED), - get_label_and_value("Ante", run_data.GAME.round_resets.ante, G.C.BLUE), - get_label_and_value("Money", "$"..run_data.GAME.dollars, G.C.MONEY), + get_label_and_value("Round", tostring(run_data.GAME.round or "?"), G.C.RED), + get_label_and_value("Ante", tostring(ante), G.C.BLUE), + get_label_and_value("Money", "$"..(DV.HIST.format_number(run_data.GAME.dollars or 0, 1e8)), G.C.MONEY), {n=G.UIT.R, config={minh = 0.1}, nodes={}}, get_label_and_value("Stake", nil, nil) } end function DV.HIST.get_run_summary_blind(run_data, text_scale) + -- round_resets may be absent from old snapshots; skip the blind section if so: + if not run_data.GAME.round_resets or not run_data.GAME.round_resets.blind_states then + return { + {n=G.UIT.R, config={align = "cm", r = 0.1}, nodes={ + {n=G.UIT.T, config={text = "Upcoming: Unknown", colour = G.C.UI.TEXT_LIGHT, scale = text_scale}} + }} + } + end + local next_blind_key = DV.HIST.get_next_blind_key(run_data) local next_blind = G.P_BLINDS[next_blind_key] @@ -283,7 +309,7 @@ function DV.HIST.get_run_summary_blind_description(run_data, next_blind_key, tex }}, {n=G.UIT.C, config={minw = 0.05}, nodes={}}, {n=G.UIT.C, config={align = "cl"}, nodes={ - {n=G.UIT.T, config={text = blind_chips, colour = G.C.RED, scale = text_scale}} + {n=G.UIT.T, config={text = DV.HIST.format_number(blind_chips, 1e8), colour = G.C.RED, scale = text_scale}} }} }} }} @@ -314,9 +340,10 @@ function DV.HIST.get_run_summary_jokers(run_data) local joker_scale = 0.5 local joker_area = DV.HIST.create_cardarea(5, joker_scale) - for _, joker_data in ipairs(run_data.cardAreas.jokers.cards) do + local joker_cards = run_data.cardAreas and run_data.cardAreas.jokers and run_data.cardAreas.jokers.cards or {} + for _, joker_data in ipairs(joker_cards) do local c = DV.HIST.create_card(G.P_CARDS.empty, G.P_CENTERS[joker_data.save_fields.center], joker_scale) - c:set_edition(joker_data.edition, true, true) + c:set_edition(joker_data.edition) joker_area:emplace(c) end return joker_area @@ -326,7 +353,8 @@ function DV.HIST.get_run_summary_consumables(run_data) local consumable_scale = 0.5 local consumable_area = DV.HIST.create_cardarea(3, consumable_scale) - for _, consumable_data in ipairs(run_data.cardAreas.consumeables.cards) do + local consumable_cards = run_data.cardAreas and run_data.cardAreas.consumeables and run_data.cardAreas.consumeables.cards or {} + for _, consumable_data in ipairs(consumable_cards) do local c = DV.HIST.create_card(G.P_CARDS.empty, G.P_CENTERS[consumable_data.save_fields.center], consumable_scale) consumable_area:emplace(c) end @@ -337,7 +365,7 @@ function DV.HIST.get_run_summary_vouchers(run_data) local voucher_scale = 0.5 local voucher_area = DV.HIST.create_cardarea(3, voucher_scale) - for voucher_key, _ in pairs(run_data.GAME.used_vouchers) do + for voucher_key, _ in pairs(run_data.GAME.used_vouchers or {}) do local c = DV.HIST.create_card(G.P_CARDS.empty, G.P_CENTERS[voucher_key], voucher_scale) voucher_area:emplace(c) end diff --git a/src/Utils.lua b/src/Utils.lua index cd7253b..292c23a 100644 --- a/src/Utils.lua +++ b/src/Utils.lua @@ -105,7 +105,12 @@ function DV.HIST.get_blind_chips(run_data, blind_key) end function DV.HIST.format_number(num, switch_point) - if not num or type(num) ~= 'number' then return num or '' end + if not num then return '' end + if type(num) == 'table' then + -- Pass Talisman BigNumbers directly to the modded number formatter + return tostring(number_format(num)) + end + if type(num) ~= 'number' then return num or '' end -- Start using e-notation earlier to reduce number length: if num >= switch_point then local x = string.format("%.4g",num)