diff --git a/lovely/blind.toml b/lovely/blind.toml index 9d1771fa1..f2f916b81 100644 --- a/lovely/blind.toml +++ b/lovely/blind.toml @@ -462,44 +462,6 @@ payload = ''' {n=G.UIT.O, config={object = DynaText({string = localize(target), colours = {G.C.WHITE},shadow = true, float = true,maxw = 2.2, scale = 0.45})}} ''' -# get_new_boss() -[[patches]] -[patches.pattern] -target = 'functions/common_events.lua' -pattern = ''' -if not v.boss then - -elseif not v.boss.showdown and (v.boss.min <= math.max(1, G.GAME.round_resets.ante) and ((math.max(1, G.GAME.round_resets.ante))%G.GAME.win_ante ~= 0 or G.GAME.round_resets.ante < 2)) then - eligible_bosses[k] = true -elseif v.boss.showdown and (G.GAME.round_resets.ante)%G.GAME.win_ante == 0 and G.GAME.round_resets.ante >= 2 then - eligible_bosses[k] = true -end -''' -match_indent = true -position = 'at' -payload = ''' -local res, options = SMODS.add_to_pool(v) -options = options or {} -if not v.boss then - -elseif options.ignore_showdown_check then - eligible_bosses[k] = res and true or nil -elseif v.in_pool and type(v.in_pool) == 'function' then - if - ( - ((G.GAME.round_resets.ante)%G.GAME.win_ante == 0 and G.GAME.round_resets.ante >= 2) == - (v.boss.showdown or false) - ) - then - eligible_bosses[k] = res and true or nil - end -elseif not v.boss.showdown and (v.boss.min <= math.max(1, G.GAME.round_resets.ante) and ((math.max(1, G.GAME.round_resets.ante))%G.GAME.win_ante ~= 0 or G.GAME.round_resets.ante < 2)) then - eligible_bosses[k] = res and true or nil -elseif v.boss.showdown and (G.GAME.round_resets.ante)%G.GAME.win_ante == 0 and G.GAME.round_resets.ante >= 2 then - eligible_bosses[k] = res and true or nil -end -''' - # G.UIDEF.challenge_description_tab [[patches]] [patches.pattern] diff --git a/lovely/blind_tree.toml b/lovely/blind_tree.toml new file mode 100644 index 000000000..435055c83 --- /dev/null +++ b/lovely/blind_tree.toml @@ -0,0 +1,28 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = -5 + +# Game:start_run() +[[patches]] +[patches.pattern] +target = 'game.lua' +match_indent = true +position = 'at' +pattern = ''' + self:prep_stage(G.STAGES.RUN, saveTable and saveTable.STATE or G.STATES.BLIND_SELECT) +''' +payload = ''' +self:prep_stage(G.STAGES.RUN, saveTable and saveTable.STATE or SMODS.STATES.BLIND_SELECT) +''' +[[patches]] +[patches.pattern] +target = 'game.lua' +match_indent = true +position = 'at' +pattern = ''' + self:prep_stage(G.STAGES.RUN, saveTable and saveTable.STATE or G.STATES.BLIND_SELECT) +''' +payload = ''' +self:prep_stage(G.STAGES.RUN, saveTable and saveTable.STATE or SMODS.STATES.BLIND_SELECT) +''' \ No newline at end of file diff --git a/lovely/booster.toml b/lovely/booster.toml index 169e3dbb7..c997fbaef 100644 --- a/lovely/booster.toml +++ b/lovely/booster.toml @@ -33,7 +33,7 @@ position = "at" payload = """ booster_obj = self.config.center if booster_obj and SMODS.Centers[booster_obj.key] then - G.STATE = G.STATES.SMODS_BOOSTER_OPENED + G.STATE = SMODS.STATES.BOOSTER_OPENED SMODS.OPENED_BOOSTER = self end G.GAME.pack_choices = math.min((self.ability.choose or self.config.center.config.choose or 1) + (G.GAME.modifiers.booster_choice_mod or 0), self.ability.extra and math.max(1, self.ability.extra + (G.GAME.modifiers.booster_size_mod or 0)) or self.config.center.extra and math.max(1, self.config.center.extra + (G.GAME.modifiers.booster_size_mod or 0)) or 1) @@ -90,32 +90,6 @@ payload = ''' SMODS.calculate_context({modify_booster_card = true, booster = self, card = card, index = i}) ''' -# Game:set_globals -[[patches]] -[patches.regex] -target = "globals.lua" -pattern = '''(?[\t ]*)self\.STATES = \{''' -position = "after" -payload = ''' - - SMODS_BOOSTER_OPENED = 999, - SMODS_REDEEM_VOUCHER = 998,''' -line_prepend = '$indent' - -# Game:update -[[patches]] -[patches.regex] -target = "game.lua" -pattern = '''(?[\t ]*)if self\.STATE == self\.STATES\.TAROT_PACK then''' -position = "before" -payload = ''' -if G.STATE == G.STATES.SMODS_BOOSTER_OPENED then - SMODS.OPENED_BOOSTER.config.center:update_pack(dt) -end - -''' -line_prepend = '$indent' - # G.FUNC.can_skip_booster # TODO customize whether pack can be skipped [[patches]] @@ -123,7 +97,7 @@ line_prepend = '$indent' target = "functions/button_callbacks.lua" pattern = '''(?[\t ]*)\(G\.STATE == G\.STATES\.PLANET_PACK or G\.STATE == G\.STATES\.STANDARD_PACK''' position = "at" -payload = '''(G.STATE == G.STATES.SMODS_BOOSTER_OPENED or G.STATE == G.STATES.PLANET_PACK or G.STATE == G.STATES.STANDARD_PACK''' +payload = '''(G.STATE == SMODS.STATES.BOOSTER_OPENED or G.STATE == G.STATES.PLANET_PACK or G.STATE == G.STATES.STANDARD_PACK''' # CardArea:draw() [[patches]] @@ -132,7 +106,7 @@ target = "cardarea.lua" pattern = "(self.config.type == 'deck' and self ~= G.deck) or" position = "before" payload = ''' -(self.config.type == 'hand' and state == G.STATES.SMODS_BOOSTER_OPENED) or''' +(self.config.type == 'hand' and state == SMODS.STATES.BOOSTER_OPENED) or''' match_indent = true # G.FUNCS.use_card @@ -142,7 +116,7 @@ target = "functions/button_callbacks.lua" pattern = "prev_state == G.STATES.SPECTRAL_PACK or prev_state == G.STATES.STANDARD_PACK or" position = "after" payload = ''' -prev_state == G.STATES.SMODS_BOOSTER_OPENED or''' +prev_state == SMODS.STATES.BOOSTER_OPENED or''' match_indent = true # CardArea:align_cards() @@ -151,7 +125,7 @@ match_indent = true target = "cardarea.lua" pattern = "if self.config.type == 'hand' and (G.STATE == G.STATES.TAROT_PACK or G.STATE == G.STATES.SPECTRAL_PACK or G.STATE == G.STATES.PLANET_PACK) then" position = "at" -payload = "if self.config.type == 'hand' and (G.STATE == G.STATES.TAROT_PACK or G.STATE == G.STATES.SPECTRAL_PACK or G.STATE == G.STATES.PLANET_PACK or G.STATE == G.STATES.SMODS_BOOSTER_OPENED) then" +payload = "if self.config.type == 'hand' and (G.STATE == G.STATES.TAROT_PACK or G.STATE == G.STATES.SPECTRAL_PACK or G.STATE == G.STATES.PLANET_PACK or G.STATE == SMODS.STATES.BOOSTER_OPENED) then" match_indent = true # CardArea:align_cards() @@ -160,7 +134,7 @@ match_indent = true target = "cardarea.lua" pattern = "if self.config.type == 'hand' and not (G.STATE == G.STATES.TAROT_PACK or G.STATE == G.STATES.SPECTRAL_PACK or G.STATE == G.STATES.PLANET_PACK) then" position = "at" -payload = "if self.config.type == 'hand' and not (G.STATE == G.STATES.TAROT_PACK or G.STATE == G.STATES.SPECTRAL_PACK or G.STATE == G.STATES.PLANET_PACK or G.STATE == G.STATES.SMODS_BOOSTER_OPENED) then" +payload = "if self.config.type == 'hand' and not (G.STATE == G.STATES.TAROT_PACK or G.STATE == G.STATES.SPECTRAL_PACK or G.STATE == G.STATES.PLANET_PACK or G.STATE == SMODS.STATES.BOOSTER_OPENED) then" match_indent = true # Card:can_use_consumable() @@ -169,7 +143,7 @@ match_indent = true target = "card.lua" pattern = "if G.STATE == G.STATES.SELECTING_HAND or G.STATE == G.STATES.TAROT_PACK or G.STATE == G.STATES.SPECTRAL_PACK or G.STATE == G.STATES.PLANET_PACK then" position = "at" -payload = "if G.STATE == G.STATES.SELECTING_HAND or G.STATE == G.STATES.TAROT_PACK or G.STATE == G.STATES.SPECTRAL_PACK or G.STATE == G.STATES.PLANET_PACK or G.STATE == G.STATES.SMODS_BOOSTER_OPENED then" +payload = "if G.STATE == G.STATES.SELECTING_HAND or G.STATE == G.STATES.TAROT_PACK or G.STATE == G.STATES.SPECTRAL_PACK or G.STATE == G.STATES.PLANET_PACK or G.STATE == SMODS.STATES.BOOSTER_OPENED then" match_indent = true # G.FUNCS.use_card() @@ -184,7 +158,7 @@ if nc then play_sound('cardSlide2', nil, 0.3) dont_dissolve = true end -if (G.STATE == G.STATES.TAROT_PACK or G.STATE == G.STATES.PLANET_PACK or G.STATE == G.STATES.SPECTRAL_PACK or G.STATE == G.STATES.SMODS_BOOSTER_OPENED) then""" +if (G.STATE == G.STATES.TAROT_PACK or G.STATE == G.STATES.PLANET_PACK or G.STATE == G.STATES.SPECTRAL_PACK or G.STATE == SMODS.STATES.BOOSTER_OPENED) then""" match_indent = true # G.FUNC.use_card() @@ -204,7 +178,7 @@ target = "functions/button_callbacks.lua" pattern = '''if prev_state == G.STATES.TAROT_PACK then inc_career_stat('c_tarot_reading_used', 1) end''' position = 'at' match_indent = true -payload = '''if prev_state == G.STATES.SMODS_BOOSTER_OPENED and booster_obj.name:find('Arcana') then inc_career_stat('c_tarot_reading_used', 1) end''' +payload = '''if prev_state == SMODS.STATES.BOOSTER_OPENED and booster_obj.name:find('Arcana') then inc_career_stat('c_tarot_reading_used', 1) end''' # G.FUNC.use_card() [[patches]] @@ -213,7 +187,7 @@ target = "functions/button_callbacks.lua" pattern = '''if prev_state == G.STATES.PLANET_PACK then inc_career_stat('c_planetarium_used', 1) end''' position = 'at' match_indent = true -payload = '''if prev_state == G.STATES.SMODS_BOOSTER_OPENED and booster_obj.name:find('Celestial') then inc_career_stat('c_planetarium_used', 1) end''' +payload = '''if prev_state == SMODS.STATES.BOOSTER_OPENED and booster_obj.name:find('Celestial') then inc_career_stat('c_planetarium_used', 1) end''' # G.FUNC.use_card() [[patches]] @@ -221,7 +195,7 @@ payload = '''if prev_state == G.STATES.SMODS_BOOSTER_OPENED and booster_obj.name target = "functions/button_callbacks.lua" pattern = "(G.STATE == G.STATES.BUFFOON_PACK and G.STATES.BUFFOON_PACK) or" position = "before" -payload = "(G.STATE == G.STATES.SMODS_BOOSTER_OPENED and G.STATES.SMODS_BOOSTER_OPENED) or" +payload = "(G.STATE == SMODS.STATES.BOOSTER_OPENED and SMODS.STATES.BOOSTER_OPENED) or" match_indent = true # G.FUNC.use_card() @@ -230,7 +204,7 @@ match_indent = true target = "functions/state_events.lua" pattern = "if not (G.STATE == G.STATES.TAROT_PACK or G.STATE == G.STATES.SPECTRAL_PACK) and" position = "at" -payload = "if not (G.STATE == G.STATES.TAROT_PACK or G.STATE == G.STATES.SPECTRAL_PACK or G.STATE == G.STATES.SMODS_BOOSTER_OPENED) and" +payload = "if not (G.STATE == G.STATES.TAROT_PACK or G.STATE == G.STATES.SPECTRAL_PACK or G.STATE == SMODS.STATES.BOOSTER_OPENED) and" match_indent = true # Card:use_consumeable() @@ -240,8 +214,8 @@ target = "card.lua" pattern = '''(?[\t ]*)align = \(G\.STATE[\s\S]*and -0\.2 or 0},''' position = "at" payload = ''' -align = (G.STATE == G.STATES.TAROT_PACK or G.STATE == G.STATES.SPECTRAL_PACK or G.STATE == G.STATES.SMODS_BOOSTER_OPENED) and 'tm' or 'cm', -offset = {x = 0, y = (G.STATE == G.STATES.TAROT_PACK or G.STATE == G.STATES.SPECTRAL_PACK or G.STATE == G.STATES.SMODS_BOOSTER_OPENED) and -0.2 or 0},''' +align = (G.STATE == G.STATES.TAROT_PACK or G.STATE == G.STATES.SPECTRAL_PACK or G.STATE == SMODS.STATES.BOOSTER_OPENED) and 'tm' or 'cm', +offset = {x = 0, y = (G.STATE == G.STATES.TAROT_PACK or G.STATE == G.STATES.SPECTRAL_PACK or G.STATE == SMODS.STATES.BOOSTER_OPENED) and -0.2 or 0},''' line_prepend = '$indent' # G.FUNCS.use_card() @@ -463,7 +437,7 @@ target = 'card.lua' match_indent = true position = 'after' pattern = '''if self.shop_voucher then G.GAME.current_round.voucher = nil end''' -payload = '''G.STATE = G.STATES.SMODS_REDEEM_VOUCHER''' +payload = '''G.STATE = SMODS.STATES.REDEEM_VOUCHER''' # G.FUNCS.use_card() # Consumables in areas other than the consumable don't count diff --git a/lovely/compact_cashout.toml b/lovely/compact_cashout.toml index 98676f316..699c237e1 100644 --- a/lovely/compact_cashout.toml +++ b/lovely/compact_cashout.toml @@ -20,46 +20,4 @@ payload = ''' if total_cashout_rows > 7 then return end''' -match_indent = true - -# Reset rows amount - -[[patches]] -[patches.regex] -target = "functions/state_events.lua" -pattern = 'G\.FUNCS\.evaluate_round = function\(\)' -position = "after" -payload = ''' - - total_cashout_rows = 0''' - -# Add UI row with total rows hidden - -[[patches]] -[patches.pattern] -target = "functions/state_events.lua" -pattern = "add_round_eval_row({name = 'bottom', dollars = dollars})" -position = "before" -payload = ''' -if total_cashout_rows > 7 then - local total_hidden = total_cashout_rows - 7 - - G.E_MANAGER:add_event(Event({ - trigger = 'before',delay = 0.38, - func = function() - local hidden = {n=G.UIT.R, config={align = "cm"}, nodes={ - {n=G.UIT.O, config={object = DynaText({ - string = {localize{type = 'variable', key = 'cashout_hidden', vars = {total_hidden}}}, - colours = {G.C.WHITE}, shadow = true, float = false, - scale = 0.45, - font = G.LANGUAGES['en-us'].font, pop_in = 0 - })}} - }} - - G.round_eval:add_child(hidden, G.round_eval:get_UIE_by_ID('bonus_round_eval')) - return true - end - })) -end''' -match_indent = true - +match_indent = true \ No newline at end of file diff --git a/lovely/fixes.toml b/lovely/fixes.toml index e03c94e54..7d7176e5a 100644 --- a/lovely/fixes.toml +++ b/lovely/fixes.toml @@ -78,7 +78,7 @@ target = 'functions/misc_functions.lua' pattern = "function save_run()" position = "after" payload = """ if G.STATE == G.STATES.TAROT_PACK or G.STATE == G.STATES.PLANET_PACK or G.STATE == G.STATES.SPECTRAL_PACK - or G.STATE == G.STATES.BUFFOON_PACK or G.STATE == G.STATES.STANDARD_PACK or G.STATE == G.STATES.SMODS_BOOSTER_OPENED then return end""" + or G.STATE == G.STATES.BUFFOON_PACK or G.STATE == G.STATES.STANDARD_PACK or G.STATE == SMODS.STATES.BOOSTER_OPENED then return end""" match_indent = true ## Set `G.your_collection.config.collection` to true in all cases diff --git a/lovely/shop.toml b/lovely/shop.toml index 3aad9d5e2..5603dc130 100644 --- a/lovely/shop.toml +++ b/lovely/shop.toml @@ -16,21 +16,6 @@ payload = ''' boosters_in_shop = 2, vouchers_in_shop = 1, ''' - -# Allow booster count to be controlled by G.GAME.modifiers.extra_boosters -[[patches]] -[patches.pattern] -target = 'game.lua' -match_indent = true -position = 'at' -pattern = ''' -for i = 1, 2 do - G.GAME.current_round.used_packs = G.GAME.current_round.used_packs or {} -''' -payload = ''' -for i=1, G.GAME.starting_params.boosters_in_shop + (G.GAME.modifiers.extra_boosters or 0) do - G.GAME.current_round.used_packs = G.GAME.current_round.used_packs or {} -''' # Custom deck functionality [[patches]] [patches.pattern] @@ -45,35 +30,6 @@ if self.effect.config.boosters_in_shop then G.GAME.starting_params.boosters_in_shop = self.effect.config.boosters_in_shop end ''' - -# Allow voucher count to be controlled by G.GAME.modifiers.extra_vouchers -[[patches]] -[patches.pattern] -target = 'game.lua' -match_indent = true -position = 'at' -pattern = ''' -if G.GAME.current_round.voucher and G.P_CENTERS[G.GAME.current_round.voucher] then - local card = Card(G.shop_vouchers.T.x + G.shop_vouchers.T.w/2, - G.shop_vouchers.T.y, G.CARD_W, G.CARD_H, G.P_CARDS.empty, G.P_CENTERS[G.GAME.current_round.voucher],{bypass_discovery_center = true, bypass_discovery_ui = true}) - card.shop_voucher = true - create_shop_card_ui(card, 'Voucher', G.shop_vouchers) - card:start_materialize() - G.shop_vouchers:emplace(card) -end -''' -payload = ''' -local vouchers_to_spawn = 0 -for _,_ in pairs(G.GAME.current_round.voucher.spawn) do vouchers_to_spawn = vouchers_to_spawn + 1 end -if vouchers_to_spawn < G.GAME.starting_params.vouchers_in_shop + (G.GAME.modifiers.extra_vouchers or 0) then - SMODS.get_next_vouchers(G.GAME.current_round.voucher) -end -for _, key in ipairs(G.GAME.current_round.voucher or {}) do - if G.P_CENTERS[key] and G.GAME.current_round.voucher.spawn[key] then - SMODS.add_voucher_to_shop(key) - end -end -''' # Modify generating vouchers [[patches]] [patches.pattern] diff --git a/src/game_object.lua b/src/game_object.lua index 1f24311c4..68d8310f0 100644 --- a/src/game_object.lua +++ b/src/game_object.lua @@ -1825,6 +1825,7 @@ SMODS.UndiscoveredCompat = { config = {}, dollars = 5, mult = 2, + blind_types = nil, -- Map of types, used by SMODS.get_new_blind() atlas = 'blind_chips', discovered = false, pos = { x = 0, y = 0 }, @@ -1844,6 +1845,9 @@ SMODS.UndiscoveredCompat = { end G.P_BLINDS[self.key] = self if self.modifies_draw then SMODS.Blinds.modifies_draw[self.key] = true end + end, + get_types = function(self) + return self.blind_types end } SMODS.Blind:take_ownership('eye', { @@ -4024,6 +4028,12 @@ SMODS.UndiscoveredCompat = { } + ------------------------------------------------------------------------------------------------- + ------- API IMPORT SMODS.GameObject.AntePath + ------------------------------------------------------------------------------------------------- + + assert(load(NFS.read(SMODS.path..'src/ante_path.lua'), ('=[SMODS _ "src/ante_path.lua"]')))() + ------------------------------------------------------------------------------------------------- ----- API IMPORT GameObject.DrawStep ------------------------------------------------------------------------------------------------- diff --git a/src/game_objects/ante_path.lua b/src/game_objects/ante_path.lua new file mode 100644 index 000000000..9d9463d82 --- /dev/null +++ b/src/game_objects/ante_path.lua @@ -0,0 +1,606 @@ +------- UI DEFS +function SMODS.create_CanvasContainer_BlindSelect(run_info) + local ui_out + if run_info then + + else + -- Needs to set G.blind_prompt_box + ui_out = { + n=G.UIT.ROOT, + config={}, + nodes={} + } + end + return ui_out +end + +------- API CODE SMODS.AntePath + +-- Helper funcs +function SMODS.create_blind_ap_node(args) + args = args or {} + args.node_index = args.node_index or 1 + if args.blind_type == "Small" then + return SMODS.APNode { + index = args.node_index, + callbacks = { + {key = "enter_blind", triggers = {selected = true}}, + {key = "evaluate_round", triggers = {defeated = true}}, + {key = "enter_shop", triggers = {cashed_out = true}}, + {key = "enter_blind_select", triggers = {shop_ended = true}}, + {key = "create_tag", triggers = {skipped = true}}, + }, + blinds = {"bl_small"}, + tags = {get_next_tag_key()}, + next_nodes_indices = args.nni + } + elseif args.blind_type == "Big" then + return SMODS.APNode { + index = args.node_index, + callbacks = { + {key = "enter_blind", triggers = {selected = true}}, + {key = "evaluate_round", triggers = {defeated = true}}, + {key = "enter_shop", triggers = {cashed_out = true}}, + {key = "enter_blind_select", triggers = {shop_ended = true}}, + {key = "create_tag", triggers = {skipped = true}}, + }, + blinds = {"bl_big"}, + tags = {get_next_tag_key()}, + next_nodes_indices = args.nni + } + elseif args.blind_type == "Boss" then + local boss_type = (G.GAME.round_resets.ante)%G.GAME.win_ante == 0 and G.GAME.round_resets.ante > 0 and "Showdown" or "Boss" + return SMODS.APNode { + index = args.node_index, + callbacks = { + {key = "enter_blind", triggers = {selected = true}}, + {key = "ante_up", triggers = {defeated = true}}, + {key = "evaluate_round", triggers = {defeated = true}}, + {key = "enter_blind_select", triggers = {shop_ended = true}}, + {key = "next_ante_path", triggers = {cashed_out = true}}, + {key = "enter_shop", triggers = {cashed_out = true}}, + }, + blinds = {SMODS.get_new_blind({[boss_type] = true})}, -- Todo : Replace with correct function + next_nodes_indices = args.nni, + } + else + return SMODS.APNode { + index = args.node_index, + hidden = true, + selected = true, + } + end +end + +function SMODS.get_vanilla_ap_blinds() + return {"Small", "Big", "Boss"} +end + +local vanilla_ap_key = "VANILLA" + +SMODS.AntePaths = {} +SMODS.AntePath = SMODS.GameObject:extend { + set = 'AntePath', + obj_table = SMODS.AntePaths, + obj_buffer = {}, + required_parameters = { + 'key', + }, + inject = function(self) + + end, + create_data = function (self) + -- Vanilla Blind structure + -- "Small" -> "Big" -> "Boss" + local path_data = { + key = self.key, + active_node = 1, + nodes = { + SMODS.create_blind_ap_node(), -- Invisible, selected start node + } + } + local vanilla_blinds = SMODS.get_vanilla_ap_blinds() + for i, blind_type in ipairs(vanilla_blinds) do + table.insert(path_data.nodes, SMODS.create_blind_ap_node({blind_type = blind_type, node_index = i + 1, nni = i < #vanilla_blinds and {[i + 2] = true} or nil})) + end + return path_data + end, + create_ui = function (self) + -- Vanilla Blind select UI + local canvas_container = UIBox { + definition = {n=G.UIT.ROOT, colour = G.C.CLEAR, padding = 0.2}, + config = {align="cm", offset = {x=0,y=G.ROOM.T.y + 29}, major = G.ROOM_ATTACH, bond = 'Weak'}, + nodes = { + SMODS.create_CanvasContainer_BlindSelect() + } + } + return canvas_container + end, + create_run_info_ui = function (self) + -- Vanilla Run Info Blind Tab UI + local canvas_container = UIBox { + definition = {n=G.UIT.ROOT, colour = G.C.CLEAR, padding = 0.2}, + config = {align="cm", offset = {x=0,y=G.ROOM.T.y}, major = G.ROOM_ATTACH, bond = 'Weak'}, + nodes = { + SMODS.create_CanvasContainer_BlindSelect(true) + } + } + return canvas_container + end, + create_callback_ui = function (self, cb_key, ap_node, ap_node_UIE) + if not cb_key or not SMODS.APNodeCallbacks[cb_key] then return end + return SMODS.APNodeCallbacks[cb_key]:create_ui(ap_node, ap_node_UIE) + end +} + +SMODS.AntePath { + key = vanilla_ap_key, +} + +function SMODS.get_ante_path() + return SMODS.ANTE_PATH and SMODS.AntePaths[SMODS.ANTE_PATH.key] or SMODS.AntePaths[vanilla_ap_key] +end + +function SMODS.get_ap_node(index) + return SMODS.ANTE_PATH and SMODS.ANTE_PATH.nodes and SMODS.ANTE_PATH.nodes[index] +end + +function SMODS.save_ante_path() + if not SMODS.ANTE_PATH then return {} end + local nodes_table = {} + for _, ap_node in ipairs(SMODS.ANTE_PATH.nodes) do + table.insert(nodes_table, ap_node:save()) + end + local ante_path_table = { + key = SMODS.ANTE_PATH.key, + active_node = SMODS.ANTE_PATH.active_node, + nodes = nodes_table, + } + return ante_path_table +end + +function SMODS.load_ante_path(ante_path_table) + for i, ap_node_table in ipairs(ante_path_table.nodes) do + ante_path_table.nodes[i] = SMODS.APNode{node_table = ap_node_table} + end + SMODS.set_ante_path(ante_path_table) +end + +function SMODS.next_ante_path() + SMODS.set_ante_path(SMODS.get_ante_path():create_data()) +end + +function SMODS.set_ante_path(data) + SMODS.ANTE_PATH = data +end + +function SMODS.set_active_ap_node(ap_node) + if type(ap_node) == "number" then + SMODS.ANTE_PATH.active_node = ap_node + else + SMODS.ANTE_PATH.active_node = ap_node.index + end +end + +function SMODS.get_active_ap_node() + return SMODS.get_ap_node(SMODS.ANTE_PATH.active_node) +end + +local start_run_ref = Game.start_run +function Game:start_run(args) + start_run_ref(self, args) + local saveTable = args.savetext + if saveTable and saveTable.ANTE_PATH then + SMODS.load_ante_path(saveTable.ANTE_PATH) + end +end + +local save_run_ref = save_run +function save_run() + save_run_ref() + G.ARGS.save_run.ANTE_PATH = recursive_table_cull(SMODS.save_ante_path()) +end + +local delete_run_ref = Game.delete_run +function Game:delete_run() + delete_run_ref(self) + SMODS.ANTE_PATH = nil +end + +------- API CODE Object.APNode +SMODS.APNode = Object:extend() +function SMODS.APNode:init(args) + args = args or {} + if args.node_table then + self:load(args.node_table) + return + end + + self.index = args.index + self.hidden = args.hidden + self.selected = args.selected or false + + self:set_callbacks(args.callbacks or {}) + self:set_blinds(args.blinds or {}) + self:set_tags(args.tags or {}) + + self:set_next_nodes(args.next_nodes_indices or {}) +end + +function SMODS.APNode:set_callbacks(cbs) + self.callbacks = {} + for _, cb in ipairs(cbs) do + table.insert(self.callbacks, { + key = cb.key, + triggers = cb.triggers, + called = cb.called or false, + ignore_hold = cb.ignore_hold or false + }) + end +end + +function SMODS.APNode:set_blinds(blinds) + self.blinds = {} + for _, blind_key in ipairs(blinds) do + table.insert(self.blinds, { + key = blind_key, + used = false, + }) + end +end + +function SMODS.APNode:set_tags(tags) + self.tags = {} + for _, tag_key in ipairs(tags) do + table.insert(self.tags, { + key = tag_key, + used = false, + }) + end +end + +function SMODS.APNode:trigger_callbacks(trigger_type) + if not trigger_type then return end + local hold = false + for _, cb in ipairs(self.callbacks) do + local callback = SMODS.APNodeCallbacks[cb.key] + if not cb.called and (not hold or cb.ignore_hold) and cb.triggers[trigger_type] then + cb.called = true + hold = hold or callback:on_callback(self, cb, trigger_type) + end + end +end + +function SMODS.APNode:get_blind(keep) + local blind_tuple + for _, tup in ipairs(self.blinds) do + if not tup.used then + blind_tuple = tup + break + end + end + local blind = blind_tuple.key + if blind and not keep then blind_tuple.used = true end + return blind +end + +function SMODS.APNode:get_tag(keep) + local tag_tuple + for _, tup in ipairs(self.tags) do + if not tup.used then + tag_tuple = tup + break + end + end + local tag = tag_tuple.key + if tag and not keep then tag_tuple.used = true end + return tag +end + +function SMODS.APNode:set_next_nodes(nni) + self.next_nodes_indices = nni or {} +end + +function SMODS.APNode:save() + local node_table = { + index = self.index, + hidden = self.hidden, + callbacks = self.callbacks, + blinds = self.blinds, + tags = self.tags, + selected = self.selected, + next_nodes_indices = self.next_nodes_indices, + } + return node_table +end + +function SMODS.APNode:load(node_table) + self.index = node_table.index + self.hidden = node_table.hidden + self.callbacks = node_table.callbacks or {} + self.blinds = node_table.blinds or {} + self.tags = node_table.tags or {} + self.selected = node_table.selected or false + self.next_nodes_indices = node_table.next_nodes_indices or {} +end + +------- API CODE GameObject.APNodeCallback +SMODS.APNodeCallbacks = {} +SMODS.APNodeCallback = SMODS.GameObject:extend { + set = 'APNodeCallback', + obj_table = SMODS.APNodeCallbacks, + obj_buffer = {}, + required_parameters = { + 'key', + 'on_callback', + }, + inject = function(self) + + end, + create_ui = function (self, ap_node, ap_node_UIE) + end +} + +SMODS.APNodeCallback { + key = "enter_blind", + on_callback = function (self, ap_node, cb, trigger_type) + -- Change game state to ap_node:get_blind() + SMODS.enter_state(SMODS.STATES.BLIND, {key = ap_node:get_blind(), trigger_callbacks = true}) -- Todo : update all instances of use according to GameStates PR + return true + end, + create_ui = function (self, ap_node, ap_node_UIE) + return SMODS.GUI.bt_callback_enter_blind(ap_node, ap_node_UIE) + end +} + +function SMODS.GUI.bt_callback_enter_blind(ap_node, ap_node_UIE) + return {} +end + +SMODS.APNodeCallback { + key = "evaluate_round", + on_callback = function (self, ap_node, cb, trigger_type) + -- Create cashout and evaluate round + SMODS.enter_state(SMODS.STATES.ROUND_EVAL, {trigger_callbacks = true}) + return true + end, + create_ui = function (self, ap_node, ap_node_UIE) + return SMODS.GUI.bt_callback_evaluate_round(ap_node, ap_node_UIE) + end +} + +function SMODS.GUI.bt_callback_evaluate_round(ap_node, ap_node_UIE) + return {} +end + +SMODS.APNodeCallback { + key = "enter_shop", + on_callback = function (self, ap_node, cb, trigger_type) + -- Change game state to shop + SMODS.enter_state(SMODS.STATES.SHOP, {trigger_callbacks = true}) + return true + end, + create_ui = function (self, ap_node, ap_node_UIE) + return SMODS.GUI.bt_callback_enter_shop(ap_node, ap_node_UIE) + end +} + +function SMODS.GUI.bt_callback_enter_shop(ap_node, ap_node_UIE) + return {} +end + +SMODS.APNodeCallback { + key = "enter_blind_select", + on_callback = function (self, ap_node, cb, trigger_type) + -- Change game state to blind select + SMODS.enter_state(SMODS.STATES.BLIND_SELECT) + return true + end, + create_ui = function (self, ap_node, ap_node_UIE) + return nil + end +} + +SMODS.APNodeCallback { + key = "ante_up", + on_callback = function (self, ap_node, cb, trigger_type) + -- Ante up + SMODS.ante_end = true + ease_ante(1) + SMODS.ante_end = nil + check_for_unlock({type = 'ante_up', ante = G.GAME.round_resets.ante + 1}) + -- Moved here from G.FUNCS.cash_out() -> Might have to be moved again for better timing + G.GAME.round_resets.blind_ante = G.GAME.round_resets.ante + ------ + return false + end, + create_ui = function (self, ap_node, ap_node_UIE) + return SMODS.GUI.bt_callback_ante_up(ap_node, ap_node_UIE) + end +} + +function SMODS.GUI.bt_callback_ante_up(ap_node, ap_node_UIE) + return {} +end + +SMODS.APNodeCallback { + key = "create_tag", + on_callback = function (self, ap_node, cb, trigger_type) + -- Create tag(s) from ap_node:get_tag() + add_tag(ap_node:get_tag()) + return false + end, + create_ui = function (self, ap_node, ap_node_UIE) + return SMODS.GUI.bt_callback_create_tag(ap_node, ap_node_UIE) + end +} + +function SMODS.GUI.bt_callback_create_tag(ap_node, ap_node_UIE) + return {} +end + +SMODS.APNodeCallback { + key = "next_ante_path", + on_callback = function (self, ap_node, cb, trigger_type) + G.E_MANAGER:add_event(Event{ + trigger = "immediate", + func = function () + SMODS.next_ante_path() + return true + end + }) + return false + end, + create_ui = function (self, ap_node, ap_node_UIE) + return nil + end +} + +------- API CODE GameObject.APNodeButton +SMODS.APNodeButtons = {} +SMODS.APNodeButton = SMODS.GameObject:extend { + set = 'APNodeButton', + obj_table = SMODS.APNodeButtons, + obj_buffer = {}, + required_parameters = { + 'key', + 'on_click', + }, + inject = function(self) + if type(self.on_click) ~= "function" then + sendWarnMessage(("APNodeButton injected with invalid function '%s'"):format(self.on_click)) + end + end, + create_ui = function (self, ap_node, ap_node_UIE) + + end, + on_click = function (self, ap_node) + + end +} + +SMODS.APNodeButton { + key = "select", + on_click = function (self, ap_node) + SMODS.set_active_ap_node(ap_node) + ap_node:trigger_callbacks("selected") + end, +} + +SMODS.APNodeButton { + key = "skip", + on_click = function (self, ap_node) + SMODS.set_active_ap_node(ap_node) + ap_node:trigger_callbacks("skipped") + end, +} + +SMODS.APNodeButton { + key = "reroll", + on_click = function (self, ap_node) + -- Reroll Blind + end, +} + +------- API CODE OVERRIDES + + +--[[ +blind_states and loc_blind_states + +Game:update(dt) -> This; + if G.prev_small_state ~= G.GAME.round_resets.blind_states.Small or + G.prev_large_state ~= G.GAME.round_resets.blind_states.Big or + G.prev_boss_state ~= G.GAME.round_resets.blind_states.Boss or G.RESET_BLIND_STATES then ... +can probably be ignored and replaced with own system + +Game:start_run() -> get_next_tag_key() is called, besides that; blind_states is set +]] +function reset_blinds() + G.GAME.round_resets.boss_rerolled = false +end + +SMODS.Joker:take_ownership("j_matador", { + check_for_unlock = function (self, args) + return G.GAME.current_round.hands_played == 1 and G.GAME.current_round.discards_left == G.GAME.round_resets.discards and G.GAME.blind:is_type("Boss") + end +}) + +SMODS.Joker:take_ownership("j_hanging_chad", { + check_for_unlock = function (self, args) + return G.GAME.last_hand_played == self.unlock_condition.extra and G.GAME.blind:is_type("Boss") + end +}) + +-- Create Blind Select UI -> Not used in SMODS.STATES.BLIND_SELECT.on_enter() +function create_UIBox_blind_select() end + +-- Run Info Tab +function G.UIDEF.current_blinds() + return SMODS.get_ante_path():create_run_info_ui() +end + +-- Blind Choice Handler +function G.FUNCS.blind_choice_handler(e) + +end + +-- Cash Out -> Functionality is handled by custom SMODS.GameStates and APNodeCallbacks +function G.FUNCS.cash_out(e) + if SMODS.get_current_state().args.trigger_callbacks then + SMODS.get_active_ap_node():trigger_callbacks("cashed_out") + end +end + +-- Needs to be patched.. +function new_round() + -- .. because of this; + -- local blhash = '' + -- if G.GAME.round_resets.blind == G.P_BLINDS.bl_small then + -- G.GAME.round_resets.blind_states.Small = 'Current' + -- G.GAME.current_boss_streak = 0 + -- blhash = 'S' + -- elseif G.GAME.round_resets.blind == G.P_BLINDS.bl_big then + -- G.GAME.round_resets.blind_states.Big = 'Current' + -- G.GAME.current_boss_streak = 0 + -- blhash = 'B' + -- else + -- G.GAME.round_resets.blind_states.Boss = 'Current' + -- blhash = 'L' + -- end + -- G.GAME.subhash = (G.GAME.round_resets.ante)..(blhash) + -- G.GAME.blind:set_blind(G.GAME.round_resets.blind) +end + +-- Todo : once GameStates PR is merged, replace all SMODS.queue_state() calls with ApNodeCallbacks + +-- get_blind_main_colour() -> replace using own system for blind_states +function get_blind_main_colour(blind) + +end + +-- Toggle Shop -> Functionality is handled by custom SMODS.GameStates and APNodeCallbacks +function G.FUNCS.toggle_shop(e) + if SMODS.get_current_state().args.trigger_callbacks then + SMODS.get_active_ap_node():trigger_callbacks("shop_ended") + end +end + +-- Select Blind -> Replaced by SMODS.GameStates.BLIND:on_enter() +function G.FUNCS.select_blind(e) end + +-- Skip Blind (-> use own func in UI defs) +function G.FUNCS.skip_blind(e) end + +-- Reroll Boss (-> use own func in UI defs) +function G.FUNCS.reroll_boss(e) end + +function G.FUNCS.reroll_boss_button(e) end + +ease_bg_col_bl_ref = ease_background_colour_blind +function ease_background_colour_blind(state, blind_override) + if SMODS.GameStates[state] and SMODS.GameStates[state].ease_background_colour then + return SMODS.GameStates[state]:ease_background_colour(blind_override) + end + return ease_bg_col_bl_ref(state, blind_override) +end \ No newline at end of file diff --git a/src/overrides.lua b/src/overrides.lua index cdc8cfb8c..90ffe444b 100644 --- a/src/overrides.lua +++ b/src/overrides.lua @@ -2705,7 +2705,7 @@ function Card:set_ability(center, initial, delay_sprites) self.delay_center = old_center end set_ability(self, center, initial, delay_sprites) - if not initial and (G.STATE ~= G.STATES.SMODS_BOOSTER_OPENED and G.STATE ~= G.STATES.SHOP and not G.SETTINGS.paused or G.TAROT_INTERRUPT) then + if not initial and (G.STATE ~= SMODS.STATES.BOOSTER_OPENED and G.STATE ~= G.STATES.SHOP and not G.SETTINGS.paused or G.TAROT_INTERRUPT) then SMODS.calculate_context({setting_ability = true, old = old_center.key, new = self.config.center_key, other_card = self, unchanged = old_center.key == self.config.center.key}) end self.front_hidden = self:should_hide_front() diff --git a/src/ui.lua b/src/ui.lua index 4f5943b56..cb0937be9 100644 --- a/src/ui.lua +++ b/src/ui.lua @@ -2674,6 +2674,110 @@ G.FUNCS.hand_type_UI_set = function(e) end end + +SMODS.CanvasContainer = UIBox:extend() + +local function clipped_collides_with_point(self, point) + return self.clipper:collides_with_point(point) and UIElement.collides_with_point(self, point) +end +function SMODS.CanvasContainer:init(args) + UIBox.init(self, args) + self.canvas = love.graphics.newCanvas(self.T.w, self.T.h, {type = '2d'}) + self.canvas:setFilter('linear', 'linear') +end + +function SMODS.CanvasContainer:draw() + if self.FRAME.DRAW >= G.FRAMES.DRAW and not G.OVERLAY_TUTORIAL then return end + self.FRAME.DRAW = G.FRAMES.DRAW + + love.graphics.setCanvas(self.canvas) + for k, v in pairs(self.children) do + if k ~= 'h_popup' and k ~= 'alert' then v:draw() end + end + + if self.states.visible then + add_to_drawhash(self) + love.graphics.setCanvas(G.CANVAS) + self.UIRoot:draw_self() + love.graphics.setCanvas(self.canvas) + self.UIRoot:draw_children() + for k, v in ipairs(self.draw_layers) do + love.graphics.setCanvas(G.CANVAS) + if v.draw_self then v:draw_self() else v:draw() end + love.graphics.setCanvas(self.canvas) + if v.draw_children then v:draw_children() end + end + end + + love.graphics.setCanvas(G.CANVAS) + self:draw_canvas() + + if self.children.alert then self.children.alert:draw() end + + self:draw_boundingrect() +end + +function SMODS.CanvasContainer:draw_canvas() + if not self.states.visible then return end + love.graphics.draw( + self.canvas, + --self.sprite, -- WRONG + 0, 0, + 0, + self.VT.w/(self.T.w), + self.VT.h/(self.T.h) + ) + love.graphics.pop() +end + +function SMODS.CanvasContainer:set_parent_child(node, parent) + local UIE = (not parent and UIElement or SMODS.CanvasContainerUIE)(parent, self, node.n, node.config) + + --set the group of the element + if parent and parent.config and parent.config.group then if UIE.config then UIE.config.group = parent.config.group else UIE.config = {group = parent.config.group} end end + + --set the button for the element + if parent and parent.config and parent.config.button then if UIE.config then UIE.config.button_UIE = parent else UIE.config = {button_UIE = parent} end end + if parent and parent.config and parent.config.button_UIE then if UIE.config then UIE.config.button_UIE = parent.config.button_UIE else UIE.config = {button = parent.config.button} end end + + if node.n and node.n == G.UIT.O and UIE.config.button then + UIE.config.object.states.click.can = false + end + + --current node is a container + if (node.n and node.n == G.UIT.C or node.n == G.UIT.R or node.n == G.UIT.ROOT) and node.nodes then + for k, v in pairs(node.nodes) do + self:set_parent_child(v, UIE) + end + end + + if not parent then + self.UIRoot = UIE + self.UIRoot.parent = self + else + UIE.clipper = self.UIRoot + UIE.collides_with_point = clipped_collides_with_point + table.insert(parent.children, UIE) + end + if node.config and node.config.mid then + self.Mid = UIE + end +end + +function SMODS.CanvasContainer:calculate_xywh(node, _T, recalculate, _scale) + +end + +SMODS.CanvasContainerUIE = UIElement:extend() +function SMODS.CanvasContainerUIE:set_wh() + +end + +function SMODS.CanvasContainerUIE:set_alignments() + +end + + function G.UIDEF.custom_deck_tab(_suit) local t = {} diff --git a/src/utils.lua b/src/utils.lua index 11976c115..602fd0934 100644 --- a/src/utils.lua +++ b/src/utils.lua @@ -1324,7 +1324,7 @@ SMODS.calculate_individual_effect = function(effect, scored_card, key, amount, f SMODS.calculate_context({ money_altered = true, amount = amount, - from_shop = (G.STATE == G.STATES.SHOP or G.STATE == G.STATES.SMODS_BOOSTER_OPENED or G.STATE == G.STATES.SMODS_REDEEM_VOUCHER) or nil, + from_shop = (G.STATE == SMODS.STATES.SHOP or G.STATE == SMODS.STATES.BOOSTER_OPENED or G.STATE == SMODS.STATES.REDEEM_VOUCHER) or nil, from_consumeable = (G.STATE == G.STATES.PLAY_TAROT) or nil, from_scoring = (G.STATE == G.STATES.HAND_PLAYED) or nil, }) @@ -2946,9 +2946,9 @@ function SMODS.update_hand_limit_text(play, discard) end function SMODS.draw_cards(hand_space) - if not (G.STATE == G.STATES.TAROT_PACK or G.STATE == G.STATES.SPECTRAL_PACK or G.STATE == G.STATES.SMODS_BOOSTER_OPENED) and - G.hand.config.card_limit <= 0 and #G.hand.cards == 0 then - G.STATE = G.STATES.GAME_OVER; G.STATE_COMPLETE = false + if not (G.STATE == G.STATES.TAROT_PACK or G.STATE == G.STATES.SPECTRAL_PACK or G.STATE == SMODS.STATES.BOOSTER_OPENED) and + G.hand.config.card_limit <= 0 and #G.hand.cards == 0 then + G.STATE = G.STATES.GAME_OVER; G.STATE_COMPLETE = false return true end @@ -3443,7 +3443,7 @@ function ease_dollars(mod, instant) SMODS.calculate_context({ money_altered = true, amount = mod, - from_shop = (G.STATE == G.STATES.SHOP or G.STATE == G.STATES.SMODS_BOOSTER_OPENED or G.STATE == G.STATES.SMODS_REDEEM_VOUCHER) or nil, + from_shop = (G.STATE == SMODS.STATES.SHOP or G.STATE == SMODS.STATES.BOOSTER_OPENED or G.STATE == SMODS.STATES.REDEEM_VOUCHER) or nil, from_consumeable = (G.STATE == G.STATES.PLAY_TAROT) or nil, from_scoring = (G.STATE == G.STATES.HAND_PLAYED) or nil, })