diff --git a/lovely/fixes.toml b/lovely/fixes.toml index 639bb95fc..49ac250d8 100644 --- a/lovely/fixes.toml +++ b/lovely/fixes.toml @@ -795,7 +795,7 @@ target = 'card.lua' match_indent = true position = 'after' pattern = ''' -if v ~= chosen_joker then +if v ~= chosen_joker then ''' payload = ''' v.getting_sliced = true @@ -812,4 +812,54 @@ function pseudoshuffle(list, seed) ''' payload = ''' if seed and type(seed) == "string" then seed = pseudoseed(seed) end -''' \ No newline at end of file +''' + +# Update Save Actions to use the inputted function +[[patches]] +[patches.pattern] +target = "game.lua" +pattern = '''for k, v in pairs(G.I.CARD) do + if v.sort_id == saveTable.ACTION.card then + G.FUNCS.use_card({config = {ref_table = v}}, nil, true) + end +end''' +position = 'at' +payload = '''local action_card = nil +for _, card in pairs(G.I.CARD) do + if card.sort_id == saveTable.ACTION.card then + action_card = card + end + if saveTable.ACTION.highlights then + for k, v in pairs(saveTable.ACTION.highlights) do + if card.area and G[k] == card.area and v[card.sort_id] then + card.area:add_to_highlighted(card, true) + end + end + end +end +if action_card then + SMODS.action_nosave = true + G.FUNCS[saveTable.ACTION.type]({config = {ref_table = action_card}}, saveTable.ACTION.args and unpack(saveTable.ACTION.args)) + SMODS.action_nosave = nil +end''' +match_indent = true + +# added arguments for save actions +[[patches]] +[patches.pattern] +target = "functions/button_callbacks.lua" +pattern = '''if card.ability.set == 'Booster' and not nosave and G.STATE == G.STATES.SHOP then + save_with_action({ + type = 'use_card', + card = card.sort_id, + }) + end''' +position = 'at' +payload = '''if card.ability.set == 'Booster' and not SMODS.action_nosave and G.STATE == G.STATES.SHOP then + save_with_action({ + type = 'use_card', + args = {mute}, + card = card.sort_id, + }) +end''' +match_indent = true \ No newline at end of file diff --git a/lsp_def/utils.lua b/lsp_def/utils.lua index 3fdd17f10..c582a6cad 100644 --- a/lsp_def/utils.lua +++ b/lsp_def/utils.lua @@ -747,3 +747,9 @@ function SMODS.check_looping_context(eval_object) end ---@param k? number Index of challenge in G.CHALLENGES. Only relevant for challenges defined outside SMODS ---@return boolean function SMODS.challenge_is_unlocked(challenge, k) end + +---@param cardareas table | nil a map of cardarea keys to access them from the global G table. Passing nil saves all global cardarea highights +---@return table +--- Saves highlighted cards for saved actions that require them +--- Returns a table of sort_id maps, indexed by the keys of their cardareas +function SMODS.save_action_highights(cardareas) end \ No newline at end of file diff --git a/src/utils.lua b/src/utils.lua index eae06be07..2746c0603 100644 --- a/src/utils.lua +++ b/src/utils.lua @@ -334,7 +334,7 @@ function SMODS.modify_rank(card, amount, manual_sprites) rank_data = SMODS.Ranks[rank_key] end end - + return SMODS.change_base(card, nil, rank_key, manual_sprites) end @@ -1029,7 +1029,7 @@ function SMODS.calculate_quantum_enhancements(card, effects, context) local old_center = card.config.center local old_center_key = card.config.center_key -- Note: For now, just trigger extra enhancements in order. - -- Future work: combine enhancements during + -- Future work: combine enhancements during -- playing card scoring (ex. Mult comes before Glass because +_mult -- naturally comes before x_mult) local extra_enhancements_list = {} @@ -1245,7 +1245,7 @@ SMODS.calculate_individual_effect = function(effect, scored_card, key, amount, f if (key == 'p_dollars' or key == 'dollars' or key == 'h_dollars') and amount then if effect.card and effect.card ~= scored_card then juice_card(effect.card) end SMODS.ease_dollars_calc = true - ease_dollars(amount) + ease_dollars(amount) SMODS.ease_dollars_calc = nil if not effect.remove_default_message then if effect.dollar_message then @@ -1305,7 +1305,7 @@ SMODS.calculate_individual_effect = function(effect, scored_card, key, amount, f blockable = false, blocking = false, delay = 0.8, - func = (function() + func = (function() ease_colour(G.C.UI_CHIPS, G.C.BLUE, 0.8) ease_colour(G.C.UI_MULT, G.C.RED, 0.8) return true @@ -1317,7 +1317,7 @@ SMODS.calculate_individual_effect = function(effect, scored_card, key, amount, f blocking = false, no_delete = true, delay = 1.3, - func = (function() + func = (function() G.C.UI_CHIPS[1], G.C.UI_CHIPS[2], G.C.UI_CHIPS[3], G.C.UI_CHIPS[4] = G.C.BLUE[1], G.C.BLUE[2], G.C.BLUE[3], G.C.BLUE[4] G.C.UI_MULT[1], G.C.UI_MULT[2], G.C.UI_MULT[3], G.C.UI_MULT[4] = G.C.RED[1], G.C.RED[2], G.C.RED[3], G.C.RED[4] return true @@ -1358,16 +1358,16 @@ SMODS.calculate_individual_effect = function(effect, scored_card, key, amount, f if key == 'effect' then return true end - + if key == 'prevent_debuff' or key == 'add_to_hand' or key == 'remove_from_hand' or key == 'stay_flipped' or key == 'prevent_stay_flipped' or key == 'prevent_trigger' then return key end - if key == 'remove' or key == 'debuff_text' or key == 'cards_to_draw' or key == 'numerator' or key == 'denominator' or key == 'no_destroy' or + if key == 'remove' or key == 'debuff_text' or key == 'cards_to_draw' or key == 'numerator' or key == 'denominator' or key == 'no_destroy' or key == 'replace_scoring_name' or key == 'replace_display_name' or key == 'replace_poker_hands' or key == 'modify' then return { [key] = amount } end - + if key == 'debuff' then return { [key] = amount, debuff_source = scored_card } end @@ -1536,20 +1536,20 @@ SMODS.calculate_repetitions = function(card, context, reps) -- After each inserted repetition we insert the post effects local new_size = #reps for i = curr_size + 1, new_size do - if not first then + if not first then post = {} if not context.post_trigger and SMODS.optional_features.post_trigger then SMODS.calculate_context({blueprint_card = context.blueprint_card, post_trigger = true, other_card = _card, other_context = context, other_ret = eval}, post) end end first = nil - if next(post) then + if next(post) then reps[#reps - new_size + i].retriggers.retrigger_flag = true else break end -- index from behind since that doesn't change for idx, eff in ipairs(post) do if next(eff) then - select(2, next(eff)).retrigger_flag = true + select(2, next(eff)).retrigger_flag = true table.insert(reps, #reps + 1 - new_size + i, eff) end end @@ -1648,7 +1648,7 @@ function Card:calculate_edition(context) end end end -end +end function SMODS.calculate_card_areas(_type, context, return_table, args) local flags = {} @@ -1669,7 +1669,7 @@ function SMODS.calculate_card_areas(_type, context, return_table, args) local effects = {eval} for _,v in ipairs(post) do effects[#effects+1] = v end - + if context.other_joker then for k, v in pairs(effects[1]) do v.other_card = _card @@ -1834,7 +1834,7 @@ SMODS.current_evaluated_object = nil -- Joker B calls SMODS.pseudorandom_probability() to check whether it should trigger -- A loop is caused (ignore the fact that Joker B would be the trigger_obj and not a playing card) (I'd write a Quantum Ranks example, If I had any!!) -- To avoid this; Check before evaluating any object, whether the current getter context type (if it's a getter context) has previously caused said object to create a getter context, --- if yes, don't evaluate the object. +-- if yes, don't evaluate the object. function SMODS.is_getter_context(context) if context.mod_probability or context.fix_probability then return "probability" end if context.check_enhancement then return "enhancement" end @@ -1861,7 +1861,7 @@ end -- SMODS.context_stack = {1: {context = [unique context 1], count = [number of times it was added consecutively], caller = [the SMODS.current_evaluated_object when the context was added]}, ...} -- (Contexts may repeat non-consecutively, though I don't think they ever should..) -- Allows some advanced effects, like: --- Individual playing cards modifying probabilities checked during individual scoring, only when they're the context.other_card +-- Individual playing cards modifying probabilities checked during individual scoring, only when they're the context.other_card -- (-> By checking the context in the stack PRIOR to the mod_probability context for the .individual / .other_card flags) SMODS.context_stack = {} @@ -1906,16 +1906,16 @@ function SMODS.calculate_context(context, return_table, no_resolve) context.main_eval = true flags[#flags+1] = SMODS.calculate_card_areas('jokers', context, return_table, { joker_area = true, has_area = has_area }) context.main_eval = nil - + flags[#flags+1] = SMODS.calculate_card_areas('playing_cards', context, return_table, { has_area = has_area }) context.main_eval = true flags[#flags+1] = SMODS.calculate_card_areas('individual', context, return_table) context.main_eval = nil - + if SMODS.no_resolve then SMODS.no_resolve = nil end - + SMODS.pop_from_context_stack(context, "utils.lua : SMODS.calculate_context") - + if not return_table then local ret = {} for i,f in ipairs(flags) do @@ -1938,8 +1938,8 @@ function SMODS.score_card(card, context) while j <= #reps do if reps[j] ~= 1 then local _, eff = next(reps[j]) - while eff.retrigger_flag do - SMODS.calculate_effect(eff, eff.card); j = j+1; _, eff = next(reps[j]) + while eff.retrigger_flag do + SMODS.calculate_effect(eff, eff.card); j = j+1; _, eff = next(reps[j]) end SMODS.calculate_effect(eff, eff.card) percent = percent + percent_delta @@ -1985,7 +1985,7 @@ function SMODS.calculate_main_scoring(context, scoring_hand) end --if card is debuffed if scoring_hand and card.debuff then - if in_scoring then + if in_scoring then G.GAME.blind.triggered = true G.E_MANAGER:add_event(Event({ trigger = 'immediate', @@ -2051,7 +2051,7 @@ function SMODS.calculate_destroying_cards(context, cards_destroyed, scoring_hand local destroyed = nil --un-highlight all cards local in_scoring = scoring_hand and SMODS.in_scoring(card, context.scoring_hand) - if scoring_hand and in_scoring and not card.destroyed then + if scoring_hand and in_scoring and not card.destroyed then -- Use index of card in scoring hand to determine pitch local m = 1 for j, _card in pairs(scoring_hand) do @@ -2145,7 +2145,7 @@ function SMODS.get_card_areas(_type, _context) { object = G.GAME.selected_back, scored_card = G.deck.cards[1] or G.deck }, } if G.GAME.blind then t[#t + 1] = { object = G.GAME.blind, scored_card = G.GAME.blind.children.animatedSprite } end - if G.GAME.challenge then t[#t + 1] = { object = SMODS.Challenges[G.GAME.challenge], scored_card = G.deck.cards[1] or G.deck } end + if G.GAME.challenge then t[#t + 1] = { object = SMODS.Challenges[G.GAME.challenge], scored_card = G.deck.cards[1] or G.deck } end for _, stake in ipairs(SMODS.get_stake_scoring_targets()) do t[#t + 1] = { object = stake, scored_card = G.deck.cards[1] or G.deck } end @@ -2576,9 +2576,9 @@ function SMODS.destroy_cards(cards, bypass_eternal, immediate, skip_anim) card.skip_destroy_animation = skip_anim end end - + check_for_unlock{type = 'shatter', shattered = glass_shattered} - + if next(playing_cards) then SMODS.calculate_context({scoring_hand = cards, remove_playing_cards = true, removed = playing_cards}) end for i = 1, #cards do @@ -2630,8 +2630,8 @@ 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 + 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 @@ -2640,7 +2640,7 @@ function SMODS.draw_cards(hand_space) delay(0.3) SMODS.drawn_cards = {} for i=1, hand_space do --draw cards from deckL - if G.STATE == G.STATES.TAROT_PACK or G.STATE == G.STATES.SPECTRAL_PACK then + if G.STATE == G.STATES.TAROT_PACK or G.STATE == G.STATES.SPECTRAL_PACK then draw_card(G.deck,G.hand, i*100/hand_space,'up', true) else draw_card(G.deck,G.hand, i*100/hand_space,'up', true) @@ -2691,7 +2691,7 @@ function SMODS.merge_effects(...) local t = {} for _, v in ipairs({...}) do for _, vv in ipairs(v) do - if vv == true or (type(vv) == "table" and next(vv)) then + if vv == true or (type(vv) == "table" and next(vv)) then table.insert(t, vv) end end @@ -2786,7 +2786,7 @@ function Game:start_run(args) game_start_run(self, args) G.E_MANAGER:add_event(Event({ trigger = 'immediate', - func = function() + func = function() SMODS.refresh_score_UI_list() return true end @@ -2805,14 +2805,14 @@ G.FUNCS.SMODS_scoring_calculation_function = function(e) else e.children[1].UIBox:add_child(SMODS.GUI.hand_chips_container(scale), e.children[1]) end - e.config.current_scoring_calculation = G.GAME.current_scoring_calculation.key + e.config.current_scoring_calculation = G.GAME.current_scoring_calculation.key end local container = e.children[1].children[2] local chip_display = container.UIBox:get_UIE_by_ID('hand_chips_container') local operator = container.UIBox:get_UIE_by_ID('hand_operator_container') local mult_display = container.UIBox:get_UIE_by_ID('hand_mult_container') - + if G.GAME.current_scoring_calculation.update_ui then G.GAME.current_scoring_calculation:update_ui(container, chip_display, mult_display, operator) else @@ -2879,7 +2879,7 @@ function SMODS.scale_card(card, args) end end end - + if type(args.operation) == 'function' then args.operation(args.ref_table, args.ref_value, initial, scalar_value) elseif args.operation == 'X' then @@ -2889,7 +2889,7 @@ function SMODS.scale_card(card, args) else SMODS.additive_scaling(args.ref_table, args.ref_value, initial, scalar_value) end - + scaling_message = scaling_message or { message = localize(args.message_key and {type='variable',key=args.message_key,vars={args.message_key =='a_xmult' and args.ref_table[args.ref_value] or scalar_value}} or 'k_upgrade_ex'), colour = args.message_colour or G.C.FILTER, @@ -3072,7 +3072,7 @@ function UIElement:draw_pixellated_under(_type, _parallax, _emboss, _progress) self.pixellated_rect.sw ~= self.shadow_parrallax.x or self.pixellated_rect.sh ~= self.shadow_parrallax.y or self.pixellated_rect.progress ~= (_progress or 1) - then + then self.pixellated_rect = { w = self.VT.w, h = self.VT.h, @@ -3189,7 +3189,7 @@ function CardArea:handle_card_limit() self.config.card_limits.total_slots = self.config.card_limits.extra_slots + (self.config.card_limits.base or 0) + (self.config.card_limits.mod or 0) self.config.card_limits.extra_slots_used = self:count_property('extra_slots_used') self.config.card_count = #self.cards + self.config.card_limits.extra_slots_used - + if G.hand and self == G.hand and self.config.card_count + (SMODS.cards_to_draw or 0) < self.config.card_limits.total_slots then if G.STATE == G.STATES.DRAW_TO_HAND and not SMODS.blind_modifies_draw(G.GAME.blind.config.blind.key) and not SMODS.draw_queued then SMODS.draw_queued = true @@ -3201,7 +3201,7 @@ function CardArea:handle_card_limit() trigger = 'immediate', func = function() if (self.config.card_limits.total_slots - self.config.card_count - (SMODS.cards_to_draw or 0)) > 0 and #G.deck.cards > (SMODS.cards_to_draw or 0) then - G.FUNCS.draw_from_deck_to_hand(self.config.card_limits.total_slots - self.config.card_count - (SMODS.cards_to_draw or 0)) + G.FUNCS.draw_from_deck_to_hand(self.config.card_limits.total_slots - self.config.card_count - (SMODS.cards_to_draw or 0)) end return true end @@ -3225,4 +3225,18 @@ end -- Function used to determine whether the current blind modifies the number of cards drawn function SMODS.blind_modifies_draw(key) if SMODS.Blinds.modifies_draw[key] then return true end -end \ No newline at end of file +end + +-- saving highights for any card actions you might want saved between runs, similar to boosters +function SMODS.save_action_highights(cardareas) + local highlights = {} + for k, v in pairs(G) do + if (type(v) == "table") and v.is and v:is(CardArea) and (not cardareas or cardareas[k]) and #v.highlighted > 0 then + highlights[k] = {} + for _, highlight in ipairs(v.highlighted) do + highlights[k][highlight.sort_id] = true + end + end + end + return next(highlights) and highlights or nil +end