diff --git a/.gitignore b/.gitignore index 063b3c1..02dd800 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1 @@ **/lovely*.log -lovely/ \ No newline at end of file diff --git a/Cartomancer/lovely/dynamic-ante-display.toml b/Cartomancer/lovely/dynamic-ante-display.toml new file mode 100644 index 0000000..b2ecac9 --- /dev/null +++ b/Cartomancer/lovely/dynamic-ante-display.toml @@ -0,0 +1,49 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = 0 + +# Patch dynamic ante display into +# function create_UIBox_your_collection_blinds(exit) +# this will only work for vanilla, as steamodded overrides this + +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +pattern = "local ante_amounts = {}" +position = "before" +payload = ''' +local min_ante = 1 +local max_ante = 16 +local spacing = 1 - 15*0.06 +if G.GAME and G.GAME.round_resets and G.GAME.round_resets.ante then + local current_ante = G.GAME.round_resets.ante + + if current_ante > 8 then + min_ante = current_ante - 8 + 1 + max_ante = current_ante + 8 + end +end +''' +match_indent = true + +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +pattern = "for i = 1, math.min(16, math.max(16, G.PROFILES[G.SETTINGS.profile].high_scores.furthest_ante.amt)) do" +position = "at" +payload = ''' +for i = min_ante, max_ante do +''' +match_indent = true + +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +pattern = "local spacing = 1 - math.min(20, math.max(15, G.PROFILES[G.SETTINGS.profile].high_scores.furthest_ante.amt))*0.06" +position = "at" +payload = ''' +-- :3 +''' +match_indent = true + diff --git a/Cartomancer/lovely/dynamic-hand-align.toml b/Cartomancer/lovely/dynamic-hand-align.toml new file mode 100644 index 0000000..e1fa646 --- /dev/null +++ b/Cartomancer/lovely/dynamic-hand-align.toml @@ -0,0 +1,26 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = 69 + +[[patches]] +[patches.pattern] +target = "cardarea.lua" +pattern = ''' +local max_cards = math.max(#self.cards, self.config.temp_limit)''' +position = "after" +payload = ''' +if max_cards_override then max_cards = max_cards_override end''' +match_indent = true + +[[patches]] +[patches.regex] +target = "cardarea.lua" +pattern = ''' +if self\.config\.type == \'hand\' and [^\n]*then''' +position = "after" +payload = ''' + + local max_cards_override = (Cartomancer.SETTINGS.dynamic_hand_align and self.config.temp_limit - #self.cards > 5) and #self.cards +''' + diff --git a/Cartomancer/lovely/fixed-flames.toml b/Cartomancer/lovely/fixed-flames.toml new file mode 100644 index 0000000..90904f1 --- /dev/null +++ b/Cartomancer/lovely/fixed-flames.toml @@ -0,0 +1,30 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = 69 + + +[[patches]] +[patches.regex] +target = "functions/button_callbacks.lua" +position = "at" +pattern = ''' +(?math\.max\(0\., math\.log\(G\.ARGS\.score_intensity\.earned_score, 5\)-2\))''' +payload = "Cartomancer.get_flames_intensity()" + +[[patches]] +[patches.regex] +target = "functions/misc_functions.lua" +position = "at" +pattern = ''' +(?\(not G\.video_organ and G\.STATE == G\.STATES\.SPLASH\) and 0 or AC\[k\]\.vol and v\.volfunc\(AC\[k\]\.vol\) or 0)''' +payload = "Cartomancer.handle_flames_volume($value)" + +[[patches]] +[patches.pattern] +target = 'functions/button_callbacks.lua' +pattern = '''_F.timer = _F.timer + G.real_dt*(1 + _F.intensity*0.2)''' +position = 'at' +payload = ''' +_F.timer = Cartomancer.handle_flames_timer(_F.timer, _F.intensity)''' +match_indent = true diff --git a/Cartomancer/lovely/hand-sorting.toml b/Cartomancer/lovely/hand-sorting.toml new file mode 100644 index 0000000..7011b30 --- /dev/null +++ b/Cartomancer/lovely/hand-sorting.toml @@ -0,0 +1,30 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = 0 + +# Add no sort button to +# create_UIBox_buttons +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +pattern = ''' +{n=G.UIT.T, config={text = localize('b_sort_hand'), scale = text_scale*0.8, colour = G.C.UI.TEXT_LIGHT}}''' +position = "before" +payload = ''' +Cartomancer.SETTINGS.improved_hand_sorting and +create_toggle{ col = true, label = localize('b_sort_hand'), label_scale = text_scale*0.8, scale = 0.30, w = 0, shadow = true, ref_table = G.hand, ref_value = 'cart_sorting', callback = function () G.FUNCS.cartomancer_sort_hand_off() end } +or''' +match_indent = true + +# Set default value of G.hand.cart_sorting +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +pattern = ''' +function create_UIBox_buttons()''' +position = "after" +payload = ''' + if G.hand and G.hand.cart_sorting == nil then G.hand.cart_sorting = true end +''' +match_indent = true diff --git a/Cartomancer/lovely/hidden-jokers.toml b/Cartomancer/lovely/hidden-jokers.toml new file mode 100644 index 0000000..dfc920e --- /dev/null +++ b/Cartomancer/lovely/hidden-jokers.toml @@ -0,0 +1,28 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = 69 + +[[patches]] +[patches.pattern] +target = "cardarea.lua" +pattern = "self.children.area_uibox:draw()" +position = "after" +payload = ''' +if self == G.jokers then + Cartomancer.add_visibility_controls() +end +''' +match_indent = true + +[[patches]] +[patches.pattern] +target = "cardarea.lua" +pattern = "function CardArea:emplace(card, location, stay_flipped)" +position = "after" +payload = ''' +if self == G.jokers then + Cartomancer.handle_joker_added(card) +end +''' +match_indent = true diff --git a/Cartomancer/lovely/keybinds.toml b/Cartomancer/lovely/keybinds.toml new file mode 100644 index 0000000..f82b968 --- /dev/null +++ b/Cartomancer/lovely/keybinds.toml @@ -0,0 +1,20 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = 69 + + +[[patches]] +[patches.pattern] +target = 'engine/controller.lua' +pattern = "function Controller:key_press_update(key, dt)" +position = "after" +payload = ''' + if key == "escape" and Cartomancer.INTERNAL_in_config then + Cartomancer.INTERNAL_in_config = false + if not Cartomancer.use_smods() then + Cartomancer.save_config() + end + end +''' +match_indent = true diff --git a/Cartomancer/lovely/limit-deck-size.toml b/Cartomancer/lovely/limit-deck-size.toml new file mode 100644 index 0000000..e55774f --- /dev/null +++ b/Cartomancer/lovely/limit-deck-size.toml @@ -0,0 +1,85 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = 69 + +# Make all drawn cards visible + +[[patches]] +[patches.pattern] +target = "cardarea.lua" +pattern = "local stay_flipped = G.GAME and G.GAME.blind and G.GAME.blind:stay_flipped(self, card)" +position = "before" +payload = ''' +if self == G.hand and not card.states.visible then + card.states.visible = true +end''' +match_indent = true + +# Fix drawing specific card staying invisible +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = "local stay_flipped = G.GAME and G.GAME.blind and G.GAME.blind:stay_flipped(to, card)" +position = "before" +payload = ''' +if card and to == G.hand and not card.states.visible then + card.states.visible = true +end''' +match_indent = true + +# Replace drawing deck pile +[[patches]] +[patches.pattern] +target = "cardarea.lua" +pattern = ''' + local deck_height = (self.config.deck_height or 0.15)/52 + for k, card in ipairs(self.cards) do + if card.facing == 'front' then card:flip() end + + if not card.states.drag.is then + card.T.x = self.T.x + 0.5*(self.T.w - card.T.w) + self.shadow_parrallax.x*deck_height*(#self.cards/(self == G.deck and 1 or 2) - k) + 0.9*self.shuffle_amt*(1 - k*0.01)*(k%2 == 1 and 1 or -0) + card.T.y = self.T.y + 0.5*(self.T.h - card.T.h) + self.shadow_parrallax.y*deck_height*(#self.cards/(self == G.deck and 1 or 2) - k) + card.T.r = 0 + 0.3*self.shuffle_amt*(1 + k*0.05)*(k%2 == 1 and 1 or -0) + card.T.x = card.T.x + card.shadow_parrallax.x/30 + end + end''' +position = "at" +payload = ''' + local display_limit + if not Cartomancer.SETTINGS.compact_deck_enabled then + display_limit = 999999 + else + display_limit = Cartomancer.SETTINGS.compact_deck_visible_cards + end + + local deck_height = (self.config.deck_height or 0.15)/52 + local total_cards = #self.cards <= display_limit and #self.cards or display_limit -- limit height + local fixedX, fixedY, fixedR = nil, nil, nil + + for k, card in ipairs(self.cards) do + if card.facing == 'front' then card:flip() end + + if not card.states.drag.is then + if fixedX then + card.T.x = fixedX + card.T.y = fixedY + card.T.r = fixedR -- rotation + card.states.visible = false + else + card.T.x = self.T.x + 0.5*(self.T.w - card.T.w) + self.shadow_parrallax.x*deck_height*(total_cards/(self == G.deck and 1 or 2) - k) + 0.9*self.shuffle_amt*(1 - k*0.01)*(k%2 == 1 and 1 or -0) + card.T.y = self.T.y + 0.5*(self.T.h - card.T.h) + self.shadow_parrallax.y*deck_height*(total_cards/(self == G.deck and 1 or 2) - k) + card.T.r = 0 + 0.3*self.shuffle_amt*(1 + k*0.05)*(k%2 == 1 and 1 or -0) + card.T.x = card.T.x + card.shadow_parrallax.x/30 + card.states.visible = true + + if k >= display_limit then + fixedX = card.T.x + fixedY = card.T.y + fixedR = card.T.r + end + end + end + end''' +match_indent = true + diff --git a/Cartomancer/lovely/saturn-compat.toml b/Cartomancer/lovely/saturn-compat.toml new file mode 100644 index 0000000..5cb8dd1 --- /dev/null +++ b/Cartomancer/lovely/saturn-compat.toml @@ -0,0 +1,15 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = 69 + +[[patches]] +[patches.pattern] +target = 'main.lua' +pattern = '''assert(load(nfs.read(Saturn.PATH .. "/core/logic/hide_played.lua")))()''' +position = 'at' +payload = ''' +-- Disabled for Cartomancer deck viewer compatibility. +-- assert(load(nfs.read(Saturn.PATH .. "/core/logic/hide_played.lua")))()''' +match_indent = true + diff --git a/Cartomancer/lovely/stackable-deck-steamodded-0.9.8.toml b/Cartomancer/lovely/stackable-deck-steamodded-0.9.8.toml new file mode 100644 index 0000000..bc0b3bf --- /dev/null +++ b/Cartomancer/lovely/stackable-deck-steamodded-0.9.8.toml @@ -0,0 +1,15 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = 69 + +# Add unique count + +[[patches]] +[patches.pattern] +target = "main.lua" +match_indent = true +pattern = "modded and {" +position = "before" +payload = ''' +not unplayed_only and Cartomancer.add_unique_count() or nil, -- Cartomancer Steamodded 0.9.8 compatibility''' diff --git a/Cartomancer/lovely/stackable-deck-steamodded.toml b/Cartomancer/lovely/stackable-deck-steamodded.toml new file mode 100644 index 0000000..bbcf456 --- /dev/null +++ b/Cartomancer/lovely/stackable-deck-steamodded.toml @@ -0,0 +1,103 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = 69 + +# If somehow someone still uses version that old - maybe add this pattern too +# -- Steamodded<0917b +# for k, v in ipairs(G.playing_cards) do +# table.insert(SUITS[v.base.suit], v) +[[patches]] +[patches.pattern] +target = '=[SMODS _ "src/overrides.lua"]' +match_indent = true +pattern = ''' + for k, v in ipairs(G.playing_cards) do + if v.base.suit then table.insert(SUITS[v.base.suit], v) end''' +position = "at" +payload = ''' +local SUITS_SORTED = Cartomancer.tablecopy(SUITS) +for k, v in ipairs(G.playing_cards) do + if v.base.suit then + local greyed + if unplayed_only and not ((v.area and v.area == G.deck) or v.ability.wheel_flipped) then + greyed = true + end + local card_string = v:cart_to_string {deck_view = true, greyed = true} + if greyed then + card_string = string.format('%sGreyed', card_string) + end + + if greyed and Cartomancer.SETTINGS.deck_view_hide_drawn_cards then + -- Ignore this card. + elseif not SUITS[v.base.suit][card_string] then + -- Initiate stack + table.insert(SUITS_SORTED[v.base.suit], card_string) + + local _scale = 0.7 + local copy = copy_card(v, nil, _scale) + + copy.greyed = greyed + copy.stacked_quantity = 1 + + SUITS[v.base.suit][card_string] = copy + else + -- Stack cards + local stacked_card = SUITS[v.base.suit][card_string] + stacked_card.stacked_quantity = stacked_card.stacked_quantity + 1 + end + end +''' + +[[patches]] +[patches.pattern] +target = '=[SMODS _ "src/overrides.lua"]' +match_indent = true +pattern = 'card_limit = #SUITS[suit_map[j]],' +position = "at" +payload = 'card_limit = #SUITS_SORTED[suit_map[j]],' + +[[patches]] +[patches.pattern] +target = '=[SMODS _ "src/overrides.lua"]' +match_indent = true +pattern = ''' + for i = 1, #SUITS[suit_map[j]] do + if SUITS[suit_map[j]][i] then + local greyed, _scale = nil, 0.7 + if unplayed_only and not ((SUITS[suit_map[j]][i].area and SUITS[suit_map[j]][i].area == G.deck) or SUITS[suit_map[j]][i].ability.wheel_flipped) then + greyed = true + end + local copy = copy_card(SUITS[suit_map[j]][i], nil, _scale) + copy.greyed = greyed + copy.T.x = view_deck.T.x + view_deck.T.w / 2 + copy.T.y = view_deck.T.y + + copy:hard_set_T() + view_deck:emplace(copy) + end + end''' +position = "at" +payload = ''' +for i = 1, #SUITS_SORTED[suit_map[j]] do + local card_string = SUITS_SORTED[suit_map[j]][i] + local card = SUITS[suit_map[j]][card_string] + + card.T.x = view_deck.T.x + view_deck.T.w/2 + card.T.y = view_deck.T.y + card:create_quantity_display() + + card:hard_set_T() + view_deck:emplace(card) +end +''' + +[[patches]] +[patches.pattern] +target = '=[SMODS _ "src/overrides.lua"]' +match_indent = true +pattern = ' modded and {n = G.UIT.R, config = {align = "cm"}, nodes = {' +position = "at" +payload = ''' + not unplayed_only and Cartomancer.add_unique_count() or nil, + modded and {n = G.UIT.R, config = {align = "cm"}, nodes = {''' diff --git a/Cartomancer/lovely/stackable-deck-vanilla.toml b/Cartomancer/lovely/stackable-deck-vanilla.toml new file mode 100644 index 0000000..9c997af --- /dev/null +++ b/Cartomancer/lovely/stackable-deck-vanilla.toml @@ -0,0 +1,146 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = 69 + +# +# Vanilla patches +# + +# Overwrite how suits are added + +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +pattern = "table.insert(SUITS[v.base.suit], v)" +position = "at" +payload = ''' +local greyed +if unplayed_only and not ((v.area and v.area == G.deck) or v.ability.wheel_flipped) then + greyed = true +end +local card_string = v:cart_to_string {deck_view = true} +if greyed then + card_string = card_string .. "Greyed" +end + +if greyed and Cartomancer.SETTINGS.deck_view_hide_drawn_cards then + -- Ignore this card. +elseif not SUITS[v.base.suit][card_string] then + table.insert(SUITS_SORTED[v.base.suit], card_string) + + local _scale = 0.7 + local copy = copy_card(v, nil, _scale) + + copy.greyed = greyed + copy.stacked_quantity = 1 + + SUITS[v.base.suit][card_string] = copy +else + local stacked_card = SUITS[v.base.suit][card_string] + stacked_card.stacked_quantity = stacked_card.stacked_quantity + 1 +end''' +match_indent = true + +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +pattern = ''' + if SUITS[suit_map[j]][1] then + local view_deck = CardArea(''' +position = "at" +payload = ''' + if SUITS_SORTED[suit_map[j]][1] then + local view_deck = CardArea(''' +match_indent = true + +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +pattern = "local suit_map = {'Spades', 'Hearts', 'Clubs', 'Diamonds'}" +position = "after" +payload = "local SUITS_SORTED = Cartomancer.tablecopy(SUITS)" +match_indent = true + +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +pattern = "local suit_tallies = {['Spades'] = 0, ['Hearts'] = 0, ['Clubs'] = 0, ['Diamonds'] = 0}" +position = "before" +payload = ''' +----------------------------------------------------------- +-- Add empty card area to view deck to fix a visual issue with missing deck. +if not next(deck_tables) then + local view_deck = CardArea( + G.ROOM.T.x + 0.2*G.ROOM.T.w/2,G.ROOM.T.h, + 6.5*G.CARD_W, + 0.6*G.CARD_H, + {card_limit = 1, type = 'title', view_deck = true, highlight_limit = 0, card_w = G.CARD_W*0.7, draw_layers = {'card'}}) + + table.insert( + deck_tables, + {n=G.UIT.R, config={align = "cm", padding = 0}, nodes={ + {n=G.UIT.O, config={object = view_deck}} + }} + ) +end +----------------------------------------------------------- +''' +match_indent = true + +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +pattern = "{card_limit = #SUITS[suit_map[j]], type = 'title', view_deck = true, highlight_limit = 0, card_w = G.CARD_W*0.7, draw_layers = {'card'}})" +position = "at" +payload = "{card_limit = #SUITS_SORTED[suit_map[j]], type = 'title', view_deck = true, highlight_limit = 0, card_w = G.CARD_W*0.7, draw_layers = {'card'}})" +match_indent = true + +# Add unique count + +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +pattern = '''modded and {n=G.UIT.R, config={align = "cm"}, nodes={''' +position = "before" +payload = "not unplayed_only and Cartomancer.add_unique_count() or nil," +match_indent = true + +# Overwrite cards copy and display code + +#Note for self: multi line pattern patches only work with original spacing. +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +pattern = ''' + for i = 1, #SUITS[suit_map[j]] do + if SUITS[suit_map[j]][i] then + local greyed, _scale = nil, 0.7 + if unplayed_only and not ((SUITS[suit_map[j]][i].area and SUITS[suit_map[j]][i].area == G.deck) or SUITS[suit_map[j]][i].ability.wheel_flipped) then + greyed = true + end + local copy = copy_card(SUITS[suit_map[j]][i],nil, _scale) + copy.greyed = greyed + copy.T.x = view_deck.T.x + view_deck.T.w/2 + copy.T.y = view_deck.T.y + + copy:hard_set_T() + view_deck:emplace(copy) + end + end''' +position = "at" +payload = ''' + for i = 1, #SUITS_SORTED[suit_map[j]] do + local card_string = SUITS_SORTED[suit_map[j]][i] + local card = SUITS[suit_map[j]][card_string] + + card.T.x = view_deck.T.x + view_deck.T.w/2 + card.T.y = view_deck.T.y + card:create_quantity_display() + + card:hard_set_T() + view_deck:emplace(card) + + end +''' +match_indent = true \ No newline at end of file diff --git a/Cartomancer/lovely/tags.toml b/Cartomancer/lovely/tags.toml new file mode 100644 index 0000000..13a8f7e --- /dev/null +++ b/Cartomancer/lovely/tags.toml @@ -0,0 +1,14 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = 69 + + +[[patches]] +[patches.pattern] +target = 'game.lua' +pattern = '''G.FUNCS.blind_chip_UI_scale(G.hand_text_area.blind_chips)''' +position = 'before' +payload = ''' +Cartomancer.update_tags_visibility()''' +match_indent = true diff --git a/Cartomancer/lovely/vanilla-ui.toml b/Cartomancer/lovely/vanilla-ui.toml new file mode 100644 index 0000000..7aad247 --- /dev/null +++ b/Cartomancer/lovely/vanilla-ui.toml @@ -0,0 +1,90 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = 69 + + +# Localization +[[patches]] +[patches.pattern] +target = "game.lua" +pattern = "boot_timer('prep stage', 'splash prep',1)" +position = "before" +payload = "Cartomancer.load_mod_file('internal/localization.lua', 'localization')" +match_indent = true + +# Add tab button to settings menu +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +match_indent = true +position = "before" +pattern = '''local t = create_UIBox_generic_options({back_func = 'options',contents = {create_tabs(''' +payload = ''' +local settings_icon = Cartomancer.add_settings_icon() +if settings_icon then + tabs[#tabs+1] = { + colour = G.C.MONEY, + custom_button = {settings_icon}, + tab_definition_function = Cartomancer.config_tab, + tab_definition_function_args = '' + } +end +''' + +# Use custom button +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +match_indent = true +position = "at" +pattern = '''but_UI_label''' +payload = ''' +args.ref_table and args.ref_table.custom_button or but_UI_label -- Cartomancer''' + +# Use custom color +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +match_indent = true +position = "at" +pattern = '''colour = args.colour,''' +payload = ''' +colour = args.ref_table and args.ref_table.colour or args.colour, -- Cartomancer''' + + +# From steamodded for vertical tabs support. +# Fix UIElement.config.chosen being overriden if choice=true is set +# UIElement:click() +[[patches]] +[patches.pattern] +target = "engine/ui.lua" +match_indent = true +position = "after" +pattern = "if self.config.choice then" +payload = " local chosen_temp = self.config.chosen" + +[[patches]] +[patches.pattern] +target = "engine/ui.lua" +match_indent = true +position = "at" +pattern = "self.config.chosen = true" +payload = "self.config.chosen = chosen_temp or true" + +# Add dynamic label support to UIBox_button +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +match_indent = true +position = "before" +pattern = "for k, v in ipairs(args.label) do" +payload = ''' +if args.dynamic_label then + but_UI_label = {} + + table.insert(but_UI_label, {n=G.UIT.R, config={align = "cm", padding = 0, minw = args.minw, maxw = args.maxw}, nodes={ + {n=G.UIT.T, config={ref_table = args.dynamic_label, ref_value = 'text', scale = args.scale, colour = args.text_colour, shadow = args.shadow, focus_args = button_pip and args.focus_args or nil, func = button_pip,}} + }}) +end +''' \ No newline at end of file diff --git a/Cartomancer/lovely/zoom-jokers.toml b/Cartomancer/lovely/zoom-jokers.toml new file mode 100644 index 0000000..dd92f4a --- /dev/null +++ b/Cartomancer/lovely/zoom-jokers.toml @@ -0,0 +1,58 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = 69 + +# Replace joker sorting. Needs better mod compat +[[patches]] +[patches.pattern] +target = "cardarea.lua" +pattern = "if self.config.type == 'joker' or self.config.type == 'title_2' then" +position = "at" +payload = ''' +if self == G.jokers and G.jokers.cart_jokers_expanded then + local align_cards = Cartomancer.expand_G_jokers() + + -- This should work fine without cryptid. But because cryptid's patch is priority=0, it has to be this way + if not G.GAME.modifiers.cry_conveyor then + table.sort(self.cards, function (a, b) return a.T.x + a.T.w/2 - 100*(a.pinned and a.sort_id or 0) < b.T.x + b.T.w/2 - 100*(b.pinned and b.sort_id or 0) end) + end + + if align_cards then + G.jokers:hard_set_cards() + end +elseif self.config.type == 'joker' or self.config.type == 'title_2' then''' +match_indent = true + +# Hide all cards that are off-screen +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "if not self.states.visible then return end" +position = "after" +payload = ''' +if self.VT.x < -3 or self.VT.x > G.TILE_W + 2.5 then return end''' +match_indent = true + +# Add slider ID +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +pattern = '''{n=G.UIT.B, config={w=startval,h=args.h, r = 0.1, colour = args.colour, ref_table = args, refresh_movement = true}},''' +position = "at" +payload = ''' +{n=G.UIT.B, config={id = args.id, w=startval,h=args.h, r = 0.1, colour = args.colour, ref_table = args, refresh_movement = true}}, +''' +match_indent = true + +# Hide slider value +[[patches]] +[patches.regex] +target = "functions/UI_definitions.lua" +pattern = ''' +(?\{n=G\.UIT\.C\, config=\{align = "cm"\, minh = args\.h\,r = 0\.1\, minw = 0\.8\, colour = args\.colour\,shadow = true\}\, nodes=\{ +[\t ]*\{n=G\.UIT\.T\, config=\{ref_table = args\, ref_value = 'text'\, scale = args\.text_scale\, colour = G\.C\.UI\.TEXT_LIGHT\, decimal_places = args\.decimal_places\}\} +[\t ]*\}\})\,''' +position = "at" +payload = ''' +not args.hide_val and $content or nil''' diff --git a/Cryptid/lovely/Probability.toml b/Cryptid/lovely/Probability.toml new file mode 100644 index 0000000..fc8c5c9 --- /dev/null +++ b/Cryptid/lovely/Probability.toml @@ -0,0 +1,300 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = 5 + +# there's gonna be a lot of this +# init all cards with ability.cry_prob +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "self.base_cost = center.cost or 1" +position = "before" +payload = ''' +self.ability.cry_prob = 1 +''' +match_indent = true + +# define function in lovely +[[patches]] +[patches.pattern] +target = "functions/misc_functions.lua" +pattern = "function save_run()" +position = "before" +payload = ''' +function cry_prob(owned, den, rigged) + prob = G.GAME and G.GAME.probabilities.normal or 1 + if rigged then + return den + else + if owned then return prob*owned else return prob end + end +end +''' +match_indent = true + +# lucky +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = '''elseif _c.effect == 'Lucky Card' then loc_vars = {G.GAME.probabilities.normal, cfg.mult, 5, cfg.p_dollars, 15}''' +position = "at" +payload = ''' +elseif _c.effect == 'Lucky Card' then loc_vars = {cfg.cry_prob and cry_prob(cfg.cry_prob, 15, cfg.cry_rigged) or G.GAME.probabilities.normal, cfg.mult, 5, cfg.p_dollars, 15} +''' +match_indent = true + +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = '''if pseudorandom('lucky_money') < G.GAME.probabilities.normal/15 then''' +position = "at" +payload = ''' +if pseudorandom('lucky_money') < cry_prob(self.ability.cry_prob, 15, self.ability.cry_rigged)/15 then +''' +match_indent = true + +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = '''if pseudorandom('lucky_mult') < G.GAME.probabilities.normal/5 then''' +position = "at" +payload = ''' +if pseudorandom('lucky_mult') < cry_prob(self.ability.cry_prob, 5, self.ability.cry_rigged)/5 then +''' +match_indent = true + +# glass +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = '''elseif _c.effect == 'Glass Card' then loc_vars = {cfg.Xmult, G.GAME.probabilities.normal, cfg.extra}''' +position = "at" +payload = ''' +elseif _c.effect == 'Glass Card' then loc_vars = {cfg.Xmult, cfg.cry_prob and cry_prob(cfg.cry_prob, cfg.extra, cfg.cry_rigged) or G.GAME.probabilities.normal, cfg.extra} +''' +match_indent = true + +# wow this is a fat line +# Yellow Stake - Glass can't destroy Eternals +# Glass Stake - Any card can shatter +[[patches]] +[patches.pattern] +target = "functions/state_events.lua" +pattern = '''if SMODS.has_enhancement(scoring_hand[i], 'm_glass') and not scoring_hand[i].debuff and pseudorandom('glass') < G.GAME.probabilities.normal/(scoring_hand[i].ability.name == 'Glass Card' and scoring_hand[i].ability.extra or G.P_CENTERS.m_glass.config.extra) then''' +position = "at" +payload = ''' +if (SMODS.has_enhancement(scoring_hand[i], 'm_glass') + and not scoring_hand[i].debuff + and pseudorandom('glass') < cry_prob( + scoring_hand[i].ability.cry_prob, + scoring_hand[i].ability.extra or G.P_CENTERS.m_glass.config.extra, + scoring_hand[i].ability.cry_rigged + ) / (scoring_hand[i].ability.name == 'Glass Card' + and scoring_hand[i].ability.extra + or G.P_CENTERS.m_glass.config.extra) + or (G.GAME.modifiers.cry_shatter_rate + and pseudorandom('cry_shatter') < 1 / G.GAME.modifiers.cry_shatter_rate)) + and not scoring_hand[i].ability.eternal then''' +match_indent = true + +# wheeeeeeeeeeel +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = '''elseif _c.name == "The Wheel of Fortune" then loc_vars = {G.GAME.probabilities.normal, cfg.extra}; info_queue[#info_queue+1] = G.P_CENTERS.e_foil; info_queue[#info_queue+1] = G.P_CENTERS.e_holo; info_queue[#info_queue+1] = G.P_CENTERS.e_polychrome;''' +position = "at" +payload = ''' +elseif _c.name == "The Wheel of Fortune" then loc_vars = {cfg.cry_prob and cry_prob(cfg.cry_prob, cfg.extra, cfg.cry_rigged) or G.GAME.probabilities.normal, cfg.extra}; info_queue[#info_queue+1] = G.P_CENTERS.e_foil; info_queue[#info_queue+1] = G.P_CENTERS.e_holo; info_queue[#info_queue+1] = G.P_CENTERS.e_polychrome; +''' +match_indent = true + +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = '''if self.ability.name == 'Ectoplasm' or self.ability.name == 'Hex' or pseudorandom('wheel_of_fortune') < G.GAME.probabilities.normal/self.ability.extra then''' +position = "at" +payload = ''' +if self.ability.name == 'Ectoplasm' or self.ability.name == 'Hex' or pseudorandom('wheel_of_fortune') < cry_prob(self.ability.cry_prob, self.ability.extra, self.ability.cry_rigged)/self.ability.extra then +''' +match_indent = true + +# ok now onto jonklers + +# space +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = '''elseif self.ability.name == 'Space Joker' then loc_vars = {''..(G.GAME and G.GAME.probabilities.normal or 1), self.ability.extra}''' +position = "at" +payload = ''' +elseif self.ability.name == 'Space Joker' then loc_vars = {cry_prob(self.ability.cry_prob, self.ability.extra, self.ability.cry_rigged), self.ability.extra} +''' +match_indent = true + +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = '''if self.ability.name == 'Space Joker' and pseudorandom('space') < G.GAME.probabilities.normal/self.ability.extra then''' +position = "at" +payload = ''' +if self.ability.name == 'Space Joker' and pseudorandom('space') < cry_prob(self.ability.cry_prob, self.ability.extra, self.ability.cry_rigged)/self.ability.extra then +''' +match_indent = true + +# 8ball +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = '''elseif self.ability.name == '8 Ball' then loc_vars = {''..(G.GAME and G.GAME.probabilities.normal or 1),self.ability.extra}''' +position = "at" +payload = ''' +elseif self.ability.name == '8 Ball' then loc_vars = {cry_prob(self.ability.cry_prob, self.ability.extra, self.ability.cry_rigged),self.ability.extra} +''' +match_indent = true + +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = '''if (context.other_card:get_id() == 8) and (pseudorandom('8ball') < G.GAME.probabilities.normal/self.ability.extra) then''' +position = "at" +payload = ''' +if (context.other_card:get_id() == 8) and (pseudorandom('8ball') < cry_prob(self.ability.cry_prob, self.ability.extra, self.ability.cry_rigged)/self.ability.extra) then +''' +match_indent = true + +# business +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = '''elseif self.ability.name == 'Business Card' then loc_vars = {''..(G.GAME and G.GAME.probabilities.normal or 1), self.ability.extra}''' +position = "at" +payload = ''' +elseif self.ability.name == 'Business Card' then loc_vars = {cry_prob(self.ability.cry_prob, self.ability.extra, self.ability.cry_rigged),self.ability.extra} +''' +match_indent = true + +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = '''pseudorandom('business') < G.GAME.probabilities.normal/self.ability.extra then''' +position = "at" +payload = ''' +pseudorandom('business') < cry_prob(self.ability.cry_prob, self.ability.extra, self.ability.cry_rigged)/self.ability.extra then +''' +match_indent = true + +# gros michel + cavendish +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = '''elseif self.ability.name == 'Gros Michel' then loc_vars = {self.ability.extra.mult, ''..(G.GAME and G.GAME.probabilities.normal or 1), self.ability.extra.odds}''' +position = "at" +payload = ''' +elseif self.ability.name == 'Gros Michel' then loc_vars = {self.ability.extra.mult, cry_prob(self.ability.cry_prob, self.ability.extra.odds, self.ability.cry_rigged), self.ability.extra.odds} +''' +match_indent = true + +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = '''elseif self.ability.name == 'Cavendish' then loc_vars = {self.ability.extra.Xmult, ''..(G.GAME and G.GAME.probabilities.normal or 1), self.ability.extra.odds}''' +position = "at" +payload = ''' +elseif self.ability.name == 'Cavendish' then loc_vars = {self.ability.extra.Xmult, cry_prob(self.ability.cry_prob, self.ability.extra.odds, self.ability.cry_rigged), self.ability.extra.odds} +''' +match_indent = true + +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = '''if pseudorandom(self.ability.name == 'Cavendish' and 'cavendish' or 'gros_michel') < G.GAME.probabilities.normal/self.ability.extra.odds then''' +position = "at" +payload = ''' +if pseudorandom(self.ability.name == 'Cavendish' and 'cavendish' or 'gros_michel') < cry_prob(self.ability.cry_prob, self.ability.extra.odds, self.ability.cry_rigged)/self.ability.extra.odds then +''' +match_indent = true + +# business +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = '''elseif self.ability.name == 'Business Card' then loc_vars = {''..(G.GAME and G.GAME.probabilities.normal or 1), self.ability.extra}''' +position = "at" +payload = ''' +elseif self.ability.name == 'Business Card' then loc_vars = {cry_prob(self.ability.cry_prob, self.ability.extra, self.ability.cry_rigged),self.ability.extra} +''' +match_indent = true + +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = '''pseudorandom('business') < G.GAME.probabilities.normal/self.ability.extra then''' +position = "at" +payload = ''' +pseudorandom('business') < cry_prob(self.ability.cry_prob, self.ability.extra, self.ability.cry_rigged)/self.ability.extra then +''' +match_indent = true + +# bloodstone +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = '''elseif self.ability.name == 'Bloodstone' then loc_vars = {''..(G.GAME and G.GAME.probabilities.normal or 1), self.ability.extra.odds, self.ability.extra.Xmult}''' +position = "at" +payload = ''' +elseif self.ability.name == 'Bloodstone' then loc_vars = {cry_prob(self.ability.cry_prob, self.ability.extra.odds, self.ability.cry_rigged), self.ability.extra.odds, self.ability.extra.Xmult} +''' +match_indent = true + +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = '''pseudorandom('bloodstone') < G.GAME.probabilities.normal/self.ability.extra.odds then''' +position = "at" +payload = ''' +pseudorandom('bloodstone') < cry_prob(self.ability.cry_prob, self.ability.extra.odds, self.ability.cry_rigged)/self.ability.extra.odds then +''' +match_indent = true + +# reserved parking +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = '''elseif self.ability.name == 'Reserved Parking' then loc_vars = {self.ability.extra.dollars, ''..(G.GAME and G.GAME.probabilities.normal or 1), self.ability.extra.odds}''' +position = "at" +payload = ''' +elseif self.ability.name == 'Reserved Parking' then loc_vars = {self.ability.extra.dollars, cry_prob(self.ability.cry_prob, self.ability.extra.odds, self.ability.cry_rigged), self.ability.extra.odds} +''' +match_indent = true + +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = '''pseudorandom('parking') < G.GAME.probabilities.normal/self.ability.extra.odds then''' +position = "at" +payload = ''' +pseudorandom('parking') < cry_prob(self.ability.cry_prob, self.ability.extra.odds, self.ability.cry_rigged)/self.ability.extra.odds then +''' +match_indent = true + +# hallucination +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = '''elseif self.ability.name == 'Hallucination' then loc_vars = {G.GAME.probabilities.normal, self.ability.extra}''' +position = "at" +payload = ''' +elseif self.ability.name == 'Hallucination' then loc_vars = {cry_prob(self.ability.cry_prob, self.ability.extra, self.ability.cry_rigged), self.ability.extra} +''' +match_indent = true + +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = '''if pseudorandom('halu'..G.GAME.round_resets.ante) < G.GAME.probabilities.normal/self.ability.extra then''' +position = "at" +payload = ''' +if pseudorandom('halu'..G.GAME.round_resets.ante) < cry_prob(self.ability.cry_prob, self.ability.extra, self.ability.cry_rigged)/self.ability.extra then +''' +match_indent = true diff --git a/Cryptid/lovely/achievement.toml b/Cryptid/lovely/achievement.toml new file mode 100644 index 0000000..ad2018c --- /dev/null +++ b/Cryptid/lovely/achievement.toml @@ -0,0 +1,38 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = -1 + +## Cryptid Achievements + +# Check to earn some achievements on startup +[[patches]] +[patches.pattern] +target = "game.lua" +pattern = '''check_for_unlock({type = 'blind_discoveries'})''' +position = "after" +payload = ''' +if change_context ~= "splash" then + if not (G.ACHIEVEMENTS and G.ACHIEVEMENTS['ach_cry_used_crash'] and G.ACHIEVEMENTS['ach_cry_used_crash'].earned) then check_for_unlock({type = 'ach_cry_used_crash'}) end + if not (G.ACHIEVEMENTS and G.ACHIEVEMENTS['ach_cry_traffic_jam'] and G.ACHIEVEMENTS['ach_cry_traffic_jam'].earned) then check_for_unlock({type = 'win_challenge_startup'}) end + if not (G.ACHIEVEMENTS and G.ACHIEVEMENTS['ach_cry_perfectly_balanced'] and G.ACHIEVEMENTS['ach_cry_perfectly_balanced'].earned) then check_for_unlock({type = 'win_stake_startup'}) end +end''' +match_indent = true + +# Cryptid the Cryptid check +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = '''new_cards[#new_cards+1] = _card''' +position = "before" +payload = '''if _card.config.center.key == "c_cryptid" then check_for_unlock({type = "cryptid_the_cryptid"}) end''' +match_indent = true + +# WHAT HAVE YOU DONE check +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = '''local sliced_card = G.jokers.cards[my_pos+1]''' +position = "after" +payload = '''if sliced_card.config.center.rarity == "cry_exotic" then check_for_unlock({type = "what_have_you_done"}) end''' +match_indent = true \ No newline at end of file diff --git a/Cryptid/lovely/blind.toml b/Cryptid/lovely/blind.toml new file mode 100644 index 0000000..4b24515 --- /dev/null +++ b/Cryptid/lovely/blind.toml @@ -0,0 +1,80 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = -1 + +# The Tax effect +[[patches]] +[patches.pattern] +target = "functions/state_events.lua" +pattern = "func = (function() update_hand_text({delay = 0, immediate = true}, {mult = 0, chips = 0, chip_total = math.floor(hand_chips*mult), level = '', handname = ''});play_sound('button', 0.9, 0.6);return true end)" +position = "at" +payload = "func = (function() update_hand_text({delay = 0, immediate = true}, {mult = 0, chips = 0, chip_total = G.GAME.blind.cry_cap_score and G.GAME.blind:cry_cap_score(math.floor(hand_chips*mult)) or math.floor(hand_chips*mult), level = '', handname = ''});play_sound('button', 0.9, 0.6);return true end)" +match_indent = true + +[[patches]] +[patches.pattern] +target = "functions/state_events.lua" +pattern = "ease_to = G.GAME.chips + math.floor(hand_chips*mult)," +position = "at" +payload = "ease_to = G.GAME.chips + (G.GAME.blind.cry_cap_score and G.GAME.blind:cry_cap_score(math.floor(hand_chips*mult)) or math.floor(hand_chips*mult))," +match_indent = true + +# Bunco (Magenta Dagger) and Cryptid (The Tax) compat +[[patches]] +[patches.pattern] +target = 'functions/state_events.lua' +pattern = "ease_to = G.GAME.chips + math.floor(hand_chips * mult) * (e and e.antiscore and -1 or 1)," +position = 'at' +match_indent = true +payload = '''ease_to = G.GAME.chips + (G.GAME.blind.cry_cap_score and G.GAME.blind:cry_cap_score(math.floor(hand_chips*mult)) or math.floor(hand_chips*mult)) * (e and e.antiscore and -1 or 1),''' + +# Fix a crash related to undebuffing Jokers at end of round +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "if not G.P_CENTERS['e_'..(self.edition.type)].discovered then" +position = "at" +payload = "if self.edition.type and G.P_CENTERS['e_'..(self.edition.type)] and not G.P_CENTERS['e_'..(self.edition.type)].discovered then" +match_indent = true + +# Blocks hands with more than 5 cards with Psychic +[[patches]] +[patches.pattern] +target = "blind.lua" +pattern = "if self.debuff.h_size_ge and #cards < self.debuff.h_size_ge then" +position = "before" +payload = ''' + if self.name == "The Psychic" and #cards > 5 then + self.triggered = true + return true + end +''' +match_indent = true + +# Shut the up plz and ty +[[patches]] +[patches.pattern] +target = "blind.lua" +pattern = '''sendWarnMessage(("Blind object %s has debuff_card function, recalc_debuff is preferred"):format(obj.key), obj.set)''' +position = "at" +payload = ''' +-- sendWarnMessage(("Blind object %s has debuff_card function, recalc_debuff is preferred"):format(obj.key), obj.set) +''' +match_indent = true + +# track game overs by blinds on profiles +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +pattern = '''local blind_choice = {config = G.GAME.blind.config.blind or G.P_BLINDS.bl_small}''' +position = "after" +payload = ''' +local cry_defeated_by = blind_choice.config.name or "Small Blind" +if not G.PROFILES[G.SETTINGS.profile].cry_defeated_by_blind then G.PROFILES[G.SETTINGS.profile].cry_defeated_by_blind = {} end +G.PROFILES[G.SETTINGS.profile].cry_defeated_by_blind[cry_defeated_by] = (G.PROFILES[G.SETTINGS.profile].cry_defeated_by_blind[cry_defeated_by] or 0) + 1 +check_for_unlock({ type = "lose_to_specific_blind", blind = cry_defeated_by, amount = G.PROFILES[G.SETTINGS.profile].cry_defeated_by_blind[cry_defeated_by] }) +''' +match_indent = true + + diff --git a/Cryptid/lovely/cat.toml b/Cryptid/lovely/cat.toml new file mode 100644 index 0000000..c09e6a4 --- /dev/null +++ b/Cryptid/lovely/cat.toml @@ -0,0 +1,335 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = 1 + +# what in ze fuck am i cooking +[[patches]] +[patches.pattern] +target = "tag.lua" +pattern = '''tag_sprite.states.collide.can = true''' +position = "after" +payload = ''' +if self.key == 'tag_cry_cat' then tag_sprite.states.click.can = true; tag_sprite.states.drag.can = true end +''' +match_indent = true + +# m +[[patches]] +[patches.pattern] +target = "tag.lua" +pattern = '''tag_sprite.stop_hover = function(_self) _self.hovering = false; Node.stop_hover(_self); _self.hover_tilt = 0 end''' +position = "after" +payload = ''' +tag_sprite.click = function(_self) + if self.key == 'tag_cry_cat' and self.HUD_tag then + for i = 1, #G.GAME.tags do + local other_cat = G.GAME.tags[i] + if other_cat.key == 'tag_cry_cat' then + if not self.ability.level then self.ability.level = 1 end + if not other_cat.ability.level then other_cat.ability.level = 1 end -- setting ability just doesn't seem to be working... so you get this + if (self.ability.level == other_cat.ability.level) and (other_cat ~= self) and not cry_too_fast_kitty then + cry_too_fast_kitty = true + local perc = (other_cat.ability.level + 1)/10 + if perc > 1 then perc = 1 end + + local edition = G.P_CENTER_POOLS.Edition[1] + local j = 1 + while j < other_cat.ability.level + 1 do + for i = 2, #G.P_CENTER_POOLS.Edition do + j = j + 1 + if j >= other_cat.ability.level + 1 then + edition = G.P_CENTER_POOLS.Edition[i] + break + end + end + end + + G.E_MANAGER:add_event(Event({ + delay = 0.0, + trigger = 'immediate', + func = (function() + attention_text({ + text = ""..other_cat.ability.level, + colour = G.C.WHITE, + scale = 1, + hold = 0.3/G.SETTINGS.GAMESPEED, + cover = other_cat.HUD_tag, + cover_colour = G.C.DARK_EDITION, + align = 'cm', + }) + play_sound('generic1', 0.8 + perc/2, 0.6) + play_sound('multhit1', 0.9 + perc/2, 0.4) + return true + end) + })) + G.E_MANAGER:add_event(Event({ + delay = 0.0, + trigger = 'immediate', + func = (function() + attention_text({ + text = "-", + colour = G.C.WHITE, + scale = 1, + hold = 0.3/G.SETTINGS.GAMESPEED, + cover = self.HUD_tag, + cover_colour = G.C.RED, + align = 'cm', + }) + return true + end) + })) + G.E_MANAGER:add_event(Event({ + func = (function() + self.HUD_tag.states.visible = false + return true + end) + })) + G.E_MANAGER:add_event(Event({ -- i have no idea what this does but i'm not messing with it + func = func + })) + + other_cat.ability.level = other_cat.ability.level + 1 + + if self.ability.shiny then + if not Cryptid.shinytagdata[self.key] then + Cryptid.shinytagdata[self.key] = true + Cryptid.save() + end + end + + G.E_MANAGER:add_event(Event({ + trigger = 'after', + delay = 0.7, + func = (function() + other_cat:juice_up(0.25, 0.1) + other_cat.ability.edshader = edition.shader + play_sound(edition.sound.sound, (edition.sound.per or 1)*1.3, (edition.sound.vol or 0.25)*0.6) + self:remove() + cry_too_fast_kitty = nil + return true + end) + })) + break + end + end + end + end +end +''' +match_indent = true + +# tag_sprite draw +[[patches]] +[patches.pattern] +target = "tag.lua" +pattern = '''tag_sprite.stop_hover = function(_self) _self.hovering = false; Node.stop_hover(_self); _self.hover_tilt = 0 end''' +position = "after" +payload = ''' +tag_sprite.draw = function(_self) + if not _self.states.visible then return end + + _self.tilt_var = self.tilt_var or {mx = 0, my = 0, dx = _self.tilt_var.dx or 0, dy = _self.tilt_var.dy or 0, amt = 0} + _self.tilt_var.mx, _self.tilt_var.my = G.CONTROLLER.cursor_position.x, G.CONTROLLER.cursor_position.y + _self.tilt_var.amt = math.abs(_self.hover_offset.y + _self.hover_offset.x - 10)*0.3 + + _self.ARGS.send_to_shader = _self.ARGS.send_to_shader or {} + _self.ARGS.send_to_shader[1] = math.min(_self.VT.r*3, 1) + G.TIMERS.REAL/(28) + (_self.juice and _self.juice.r*10 or 0) + _self.tilt_var.amt + _self.ARGS.send_to_shader[2] = G.TIMERS.REAL*2 + + _self.tilt_var = _self.tilt_var or {} + _self.tilt_var.mx, _self.tilt_var.my =G.CONTROLLER.cursor_position.x,G.CONTROLLER.cursor_position.y + + _self.role.draw_major = _self + _self:draw_shader('dissolve', 0.1) + local ed = _self.config.tag.ability.edshader + if ed then + if ed == 'foil' or ed == 'cry_noisy' then + _self:draw_shader('dissolve') + end + _self:draw_shader(ed, nil, _self.ARGS.send_to_shader) + if ed == 'negative' or ed == 'cry_oversat' then + _self:draw_shader('negative_shine', nil, _self.ARGS.send_to_shader) + end + else + _self:draw_shader('dissolve') + end + add_to_drawhash(_self) +end +''' +match_indent = true + +# init tilt_var +[[patches]] +[patches.pattern] +target = "tag.lua" +pattern = '''tag_sprite.T.scale = 1''' +position = "before" +payload = ''' +tag_sprite.tilt_var = {mx = 0, my = 0, dx = 0, dy = 0, amt = 0} +''' +match_indent = true + +# make the cat tag meow (can probably do this without injecting?) +[[patches]] +[patches.pattern] +target = "tag.lua" +pattern = '''play_sound('tarot2', math.random()*0.1 + 0.55, 0.09)''' +position = "before" +payload = ''' +if self.key == 'tag_cry_cat' and not self.hide_ability then + play_sound('cry_meow'..math.random(4), 1.26, 0.12); +end''' +match_indent = true + + + + +# shiny tags +[[patches]] +[patches.pattern] +target = "tag.lua" +pattern = '''local tag_sprite = Sprite(0,0,_size*1,_size*1,G.ASSET_ATLAS[(not self.hide_ability) and G.P_TAGS[self.key].atlas or "tags"], (self.hide_ability) and G.tag_undiscovered.pos or self.pos)''' +position = "at" +payload = ''' +local tagatlas = G.ASSET_ATLAS[(not self.hide_ability) and G.P_TAGS[self.key].atlas or "tags"] +if self.ability.shiny and not self.hide_ability then + if not G.P_TAGS[self.key].atlas then + tagatlas = G.ASSET_ATLAS['cry_shinyv'] + elseif G.P_TAGS[self.key].atlas == 'cry_tag_cry' then + tagatlas = G.ASSET_ATLAS['cry_shinyc'] + end +end + +local tag_sprite = Sprite(0,0,_size*1,_size*1,tagatlas, (self.hide_ability) and G.tag_undiscovered.pos or self.pos) +''' +match_indent = true + +# collection +# nice pattern match? +[[patches]] +[patches.pattern] +target = '''=[SMODS _ "src/overrides.lua"]''' +pattern = ''' + opt_callback = 'your_collection_tags_page', + focus_args = { snap_to = true, nav = 'wide' }, + current_option = page, + colour = G.C.RED, + no_pips = true + }) + } + }''' +position = "after" +payload = ''' +, + Cryptid.shinytag_tally() > 0 and create_toggle{ -- tally function runs way too often but whatever + label = localize('k_cry_shiny'), + w = 0, + ref_table = G, + ref_value = "showshinytags" + } or nil, +''' +match_indent = true + +[[patches]] +[patches.pattern] +target = '''=[SMODS _ "src/overrides.lua"]''' +pattern = ''' +if not v.discovered then temp_tag.hide_ability = true end +''' +position = "before" +payload = ''' +if G.showshinytags then + temp_tag.ability.shiny = true + if not Cryptid.shinytagdata[temp_tag.key] then + temp_tag.hide_ability = true + end +end +''' +match_indent = true + +# i can't seem to get the tag page easily +# i'm also surprised this doesn't multipatch +[[patches]] +[patches.pattern] +target = '''=[SMODS _ "src/overrides.lua"]''' +pattern = ''' +local page = args.cycle_config.current_option or 1 +''' +position = "at" +payload = ''' +if args then G.cry_current_tagpage = args.cycle_config.current_option end +local page = args and args.cycle_config.current_option or G.cry_current_tagpage or 1 +''' +match_indent = true + +# update collection +# scuffed +[[patches]] +[patches.pattern] +target = '''game.lua''' +pattern = ''' +self.E_MANAGER:update(self.real_dt) +''' +position = "before" +payload = ''' +if not G.showshinytags then G.showshinytags = false end +if not G.showshinytags_b then G.showshinytags_b = false end + +if G.showshinytags ~= G.showshinytags_b then + G.showshinytags_b = G.showshinytags + G.FUNCS.your_collection_tags_page() +end +''' +match_indent = true + +# save+loading time + +# cryptidsave stuff +[[patches]] +[patches.pattern] +target = '''game.lua''' +pattern = ''' +if not love.filesystem.getInfo(G.SETTINGS.profile..'/'..'meta.jkr') then love.filesystem.append( G.SETTINGS.profile..'/'..'meta.jkr', 'return {}') end +''' +position = "after" +payload = ''' +if not love.filesystem.getInfo(G.SETTINGS.profile..'/'..'cryptidsave.jkr') then love.filesystem.append( G.SETTINGS.profile..'/'..'cryptidsave.jkr', 'return {}') end +''' +match_indent = true + +[[patches]] +[patches.pattern] +target = '''game.lua''' +pattern = ''' +local meta = STR_UNPACK(get_compressed(G.SETTINGS.profile..'/'..'meta.jkr') or 'return {}') +''' +position = "after" +payload = ''' +local cryptidsave = STR_UNPACK(get_compressed(G.SETTINGS.profile..'/'..'cryptidsave.jkr') or 'return {}') + +if cryptidsave and cryptidsave.shinytags then + Cryptid.shinytagdata = copy_table(cryptidsave.shinytags) +else + -- populated later when tags actually exist + Cryptid.shinytagdata = {} +end +''' +match_indent = true + +[[patches]] +[patches.pattern] +target = '''tag.lua''' +pattern = ''' +function Tag:yep(message, _colour, func) +''' +position = "after" +payload = ''' +if self.ability.shiny then + if not Cryptid.shinytagdata[self.key] then + Cryptid.shinytagdata[self.key] = true + Cryptid.save() + end +end +''' +match_indent = true diff --git a/Cryptid/lovely/ccd.toml b/Cryptid/lovely/ccd.toml new file mode 100644 index 0000000..0e487a1 --- /dev/null +++ b/Cryptid/lovely/ccd.toml @@ -0,0 +1,109 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = -1 + +# This is sacrilegious +[[patches]] +[patches.pattern] +target = "game.lua" +pattern = "self.GAME.starting_deck_size = #G.playing_cards" +position = "before" +payload = ''' +if G.GAME.modifiers.cry_ccd then + for k, v in pairs(G.playing_cards) do + v:set_ability(Cryptid.random_consumable('cry_ccd',{"no_doe", "no_grc"}, nil, nil, true), true, nil) + end +end +''' +match_indent = true + +# Aura use conditions +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "if G.hand and (#G.hand.highlighted == 1) and G.hand.highlighted[1] and (not G.hand.highlighted[1].edition) then return true end" +position = "at" +payload = ''' +if self.area ~= G.hand then + return G.hand and (#G.hand.highlighted == 1) and G.hand.highlighted[1] and (not G.hand.highlighted[1].edition) +else + local idx = 1 + if G.hand.highlighted[1] == self then + local idx = 2 + end + return (#G.hand.highlighted == 2) and (not G.hand.highlighted[idx].edition) +end +''' +match_indent = true + +# Prevent counting CCD consumables for pack uses +[[patches]] +[patches.pattern] +target = "functions/button_callbacks.lua" +pattern = "if area == G.consumeables then" +position = "at" +payload = "if area == G.consumeables or area == G.hand then" +match_indent = true + +# Fix bugs from removing CCD +# This really shouldn't be in the card drawing code, but it doesn't really matter since that's where it crashes anyway lol +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "if not self.config.center.discovered and (self.ability.consumeable or self.config.center.unlocked) and not self.config.center.demo and not self.bypass_discovery_center then" +position = "before" +payload = "if self.ability.set == 'Enhanced' then self.ability.consumeable = nil end" +match_indent = true + +# ui, ui, ui +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +pattern = '''name_from_rows(AUT.name, is_playing_card and G.C.WHITE or nil),''' +position = "at" +payload = ''' +AUT.ccd and name_from_rows(AUT.ccd.name, G.C.WHITE) or nil, +AUT.ccd and desc_from_rows(AUT.ccd.main) or nil, +name_from_rows(AUT.name, is_playing_card and G.C.WHITE or nil), +''' +match_indent = true + +# i love patching like five billion things +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = '''return generate_card_ui(self.config.center, nil, loc_vars, card_type, badges, hide_desc, main_start, main_end, self)''' +position = "before" +payload = ''' +if card_type ~= 'Default' and card_type ~= 'Enhanced' and self.playing_card then + loc_vars = loc_vars or {} + loc_vars.ccd = { + playing_card = not not self.base.colour, value = self.base.value, suit = self.base.suit, colour = self.base.colour, + nominal_chips = self.base.nominal > 0 and self.base.nominal or nil, + bonus_chips = (self.ability.bonus + (self.ability.perma_bonus or 0)) > 0 and (self.ability.bonus + (self.ability.perma_bonus or 0)) or nil, + } +end +''' +match_indent = true + +# lalala ok this is a mess +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = '''local loc_vars = {}''' +position = "before" +payload = ''' +if specific_vars and specific_vars.ccd then + full_UI_table.ccd = {name = {}, main = {}} + localize{type = 'other', key = 'playing_card', set = 'Other', nodes = full_UI_table.ccd.name, vars = {localize(specific_vars.ccd.value, 'ranks'), localize(specific_vars.ccd.suit, 'suits_plural'), colours = {specific_vars.ccd.colour}}} + full_UI_table.ccd.name = full_UI_table.ccd.name[1] + if specific_vars.ccd.nominal_chips then + localize{type = 'other', key = 'card_chips', nodes = full_UI_table.ccd.main, vars = {specific_vars.ccd.nominal_chips}} + end + if specific_vars.ccd.bonus_chips then + localize{type = 'other', key = 'card_extra_chips', nodes = full_UI_table.ccd.main, vars = {specific_vars.ccd.bonus_chips}} + end +end +''' +match_indent = true \ No newline at end of file diff --git a/Cryptid/lovely/challenges.toml b/Cryptid/lovely/challenges.toml new file mode 100644 index 0000000..4d6cfe8 --- /dev/null +++ b/Cryptid/lovely/challenges.toml @@ -0,0 +1,31 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = -1 + +# Rush Hour - remove tags +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +pattern = "if type == 'Small' then" +position = "at" +payload = "if type == 'Small' and not G.GAME.modifiers.cry_no_tags then" +match_indent = true + +# Rush Hour - remove tags +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +pattern = "elseif type == 'Big' then" +position = "at" +payload = "elseif type == 'Big' and not G.GAME.modifiers.cry_no_tags then" +match_indent = true + +# Rush Hour - remove tags +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +pattern = "elseif not run_info then" +position = "at" +payload = "elseif type == 'Boss' and not run_info then" +match_indent = true \ No newline at end of file diff --git a/Cryptid/lovely/code.toml b/Cryptid/lovely/code.toml new file mode 100644 index 0000000..2d5ff08 --- /dev/null +++ b/Cryptid/lovely/code.toml @@ -0,0 +1,384 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = -1 + +# Code UI disables hold R shortcut +[[patches]] +[patches.pattern] +target = "engine/controller.lua" +pattern = 'if key == "r" and not G.SETTINGS.paused then' +position = "at" +payload = 'if key == "r" and not G.SETTINGS.paused and not (G.GAME and G.GAME.USING_CODE) then' +match_indent = true + + +# Payload - cash out UI +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = "elseif config.name == 'interest' then" +position = "before" +payload = ''' +elseif config.name == 'interest_payload' then +table.insert(left_text, {n=G.UIT.T, config={text = num_dollars, scale = 0.8*scale, colour = G.C.SECONDARY_SET.Code, shadow = true, juice = true}}) +table.insert(left_text,{n=G.UIT.O, config={object = DynaText({string = {" "..localize{type = 'variable', key = 'interest', vars = {G.GAME.interest_amount*config.payload, 5, G.GAME.interest_amount*config.payload*G.GAME.interest_cap/5}}}, colours = {G.C.SECONDARY_SET.Code}, shadow = true, pop_in = 0, scale = 0.4*scale, silent = true})}}) +''' +match_indent = true + +# Payload - cash out +[[patches]] +[patches.pattern] +target = "functions/state_events.lua" +pattern = "if G.GAME.dollars >= 5 and not G.GAME.modifiers.no_interest then" +position = "at" +payload = ''' +if G.GAME.dollars >= 5 and not G.GAME.modifiers.no_interest and G.GAME.cry_payload then + add_round_eval_row({bonus = true, payload = G.GAME.cry_payload, name='interest_payload', pitch = pitch, dollars = G.GAME.interest_amount*G.GAME.cry_payload*math.min(math.floor(G.GAME.dollars/5), G.GAME.interest_cap/5)}) + pitch = pitch + 0.06 + if not G.GAME.seeded and not G.GAME.challenge then + if G.GAME.interest_amount*math.min(math.floor(G.GAME.dollars/5), G.GAME.interest_cap/5) == G.GAME.interest_amount*G.GAME.interest_cap/5 then + G.PROFILES[G.SETTINGS.profile].career_stats.c_round_interest_cap_streak = G.PROFILES[G.SETTINGS.profile].career_stats.c_round_interest_cap_streak + 1 + else + G.PROFILES[G.SETTINGS.profile].career_stats.c_round_interest_cap_streak = 0 + end + end + check_for_unlock({type = 'interest_streak'}) + dollars = dollars + G.GAME.interest_amount*G.GAME.cry_payload*math.min(math.floor(G.GAME.dollars/5), G.GAME.interest_cap/5) + G.GAME.cry_payload = nil +elseif G.GAME.dollars >= 5 and not G.GAME.modifiers.no_interest then''' +match_indent = true + +# Revert - fix a crash +[[patches]] +[patches.pattern] +target = "functions/button_callbacks.lua" +pattern = "if area and area.cards[1] then" +position = "at" +payload = "if area and area.cards and area.cards[1] then" +match_indent = true + +# Crash - use glitched shader +[[patches]] +[patches.pattern] +target = "game.lua" +pattern = "G.SHADERS['CRT']:send('glitch_intensity', 0)--0.1*G.SETTINGS.GRAPHICS.crt/100 + (G.screenwipe_amt) + 1)" +position = "at" +payload = "G.SHADERS['CRT']:send('glitch_intensity', glitched_intensity or 0)" +match_indent = true + +# Semicolon - don't lose +[[patches]] +[patches.pattern] +target = "functions/state_events.lua" +pattern = '''G.RESET_JIGGLES = true''' +position = 'after' +match_indent = true +payload = ''' +if G.GAME.current_round.semicolon then + game_over = false +end +''' + +# Semicolon - end screen text +[[patches]] +[patches.regex] +target = "functions/common_events.lua" +pattern = '''localize\('ph_mr_bones'\)..' '\}, colours = \{G.C.FILTER''' +position = 'at' +# match_indent = true +line_prepend = '' +payload = '''(G.GAME.current_round.semicolon and ";" or localize('ph_mr_bones'))..' '}, colours = {(G.GAME.current_round.semicolon and G.C.SET.Code or G.C.FILTER)''' + +# Semicolon - polished UI +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = '''{n=G.UIT.T, config={text = localize('b_cash_out')..": ", scale = 1, colour = G.C.UI.TEXT_LIGHT, shadow = true}},''' +position = "at" +payload = '''{n=G.UIT.T, config={text = G.GAME.current_round.semicolon and localize('k_end_blind') or (localize('b_cash_out')..": "), scale = 1, colour = G.C.UI.TEXT_LIGHT, shadow = true}},''' +match_indent = true + +# Semicolon - polished UI +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = '''{n=G.UIT.T, config={text = localize('$')..config.dollars, scale = 1.2*scale, colour = G.C.WHITE, shadow = true, juice = true}}''' +position = "at" +payload = '''{n=G.UIT.T, config={text = not G.GAME.current_round.semicolon and localize('$')..config.dollars or ';', scale = 1.2*scale, colour = G.C.WHITE, shadow = true, juice = true}}''' +match_indent = true + +# Semicolon - polished UI +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = '''{n=G.UIT.R, config={id = 'cash_out_button', align = "cm", padding = 0.1, minw = 7, r = 0.15, colour = G.C.ORANGE, shadow = true, hover = true, one_press = true, button = 'cash_out', focus_args = {snap_to = true}}, nodes={''' +position = "at" +payload = '''{n=G.UIT.R, config={id = 'cash_out_button', align = "cm", padding = 0.1, minw = 7, r = 0.15, colour = G.GAME.current_round.semicolon and G.C.SET.Code or G.C.ORANGE, shadow = true, hover = true, one_press = true, button = 'cash_out', focus_args = {snap_to = true}}, nodes={''' +match_indent = true + +# Semicolon - reset value at start of round +[[patches]] +[patches.pattern] +target = "functions/state_events.lua" +pattern = "G.GAME.blind:set_blind(G.GAME.round_resets.blind)" +position = "after" +payload = ''' +G.GAME.current_round.semicolon = false +''' +match_indent = true + +# Delete - placeholder booster, in the case that all are deleted +[[patches]] +[patches.regex] +target = "functions/common_events.lua" +pattern = '''return center\nend\n\nfunction get_current_pool\(_type, _rarity, _legendary, _append\)''' +position = "before" +payload = '''if not center then center = G.P_CENTERS['p_buffoon_normal_1'] end ''' + +# Delete - banished keys prevent pool stuff, guess we're going for this method after all +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = '''if v.yes_pool_flag and not G.GAME.pool_flags[v.yes_pool_flag] then add = nil end''' +position = "after" +payload = '''if G.GAME.cry_banished_keys[v.key] then add = nil end''' +match_indent = true + +# Delete - multiuse 1 +[[patches]] +[patches.pattern] +target = "functions/button_callbacks.lua" +pattern = '''if card.area and (not nc or card.area == G.pack_cards) then card.area:remove_card(card) end''' +position = "before" +payload = ''' +local cry_muse = false +if card.ability.cry_multiuse and not (card.ability.cry_multiuse <= 1) then + cry_muse = true + dont_dissolve = true +end +''' +match_indent = true + +# Delete - multiuse 2 +[[patches]] +[patches.pattern] +target = "functions/button_callbacks.lua" +pattern = '''if (prev_state == G.STATES.TAROT_PACK or prev_state == G.STATES.PLANET_PACK or''' +position = "before" +payload = ''' +if cry_muse then + card.ability.cry_multiuse = card.ability.cry_multiuse - 1 + card.ability.extra_value = -1 * math.max(1, math.floor(card.cost/2)) + card:set_cost() + delay(0.4) + + -- i make my own card eval status text :D + + card:juice_up() + play_sound('generic1') + attention_text({ + text = format_ui_value(card.ability.cry_multiuse), + scale = 1.1, + hold = 0.6, + major = card, + backdrop_colour = G.C.SECONDARY_SET[card.config.center.set], + align = 'bm', + offset = {x = 0, y = 0.2} + }) + + delay(0.8) + local _area = area ~= G.pack_cards and area or G.consumeables + draw_card(G.play, _area, 1, 'up', true, card, nil, true) +end +''' +match_indent = true + +# Delete - init table to avoid headaches +[[patches]] +[patches.pattern] +target = "game.lua" +pattern = '''ecto_minus = 1,''' +position = "after" +payload = ''' +cry_banished_keys = {}, +''' +match_indent = true + +# Run - don't clear shop +[[patches]] +[patches.pattern] +target = "game.lua" +pattern = '''if self.shop then self.shop:remove(); self.shop = nil end''' +position = "at" +payload = '''if self.shop and not G.GAME.USING_CODE then self.shop:remove(); self.shop = nil end''' +match_indent = true + +[[patches]] +[patches.pattern] +target = "game.lua" +pattern = '''ease_background_colour_blind(G.STATES.SHOP)''' +position = "at" +payload = '''if not G.GAME.USING_RUN then ease_background_colour_blind(G.STATES.SHOP) end''' +match_indent = true + +[[patches]] +[patches.pattern] +target = "game.lua" +pattern = '''if self.STATE == self.STATES.SELECTING_HAND then''' +position = "before" +payload = ''' +if G.GAME.USING_RUN then + if not (self.STATE == self.STATES.STANDARD_PACK or self.STATE == self.STATES.BUFFOON_PACK or self.STATE == self.STATES.PLANET_PACK or self.STATE == self.STATES.TAROT_PACK or self.STATE == self.STATES.SPECTRAL_PACK or self.STATE == self.STATES.SMODS_BOOSTER_OPENED) then -- do you are have stupid + self.STATE = self.STATES.SHOP + end + if G.GAME.blind then G.GAME.blind:change_colour() end -- aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + if G.load_cry_runarea then + G.cry_runarea = CardArea( + G.discard.T.x, + G.discard.T.y, + G.discard.T.w, + G.discard.T.h, + { type = "discard", card_limit = 1e100 } + ) + G.cry_runarea:load(G.load_cry_runarea) + G.load_cry_runarea = nil + end +end +''' +match_indent = true + +# Run - handle packs (this is incredibly invasive) +# we can't do "draw from run to hand" because modded packs presumably don't get ovewritten like that +[[patches]] +[patches.pattern] +target = "functions/state_events.lua" +pattern = '''for i=1, hand_space do --draw cards from deckL''' +position = "before" +payload = '''if not G.GAME.USING_RUN then''' +match_indent = true +# the inconsistency hurts +[[patches]] +[patches.pattern] +target = "functions/button_callbacks.lua" +pattern = '''G.FUNCS.draw_from_hand_to_deck()''' +position = "at" +payload = '''if not G.GAME.USING_RUN then + G.FUNCS.draw_from_hand_to_deck() +else + G.FUNCS.draw_from_hand_to_run() +end''' +match_indent = true +[[patches]] +[patches.regex] +target = "functions/state_events.lua" +pattern = '''end\n\s+G\.FUNCS\.discard_cards_from_highlighted \= function\(e, hook\)''' +position = "before" +payload = ''' +else + for i = 1, #G.cry_runarea.cards do + draw_card(G.cry_runarea,G.hand, i*100/#G.cry_runarea.cards,'up', true) + end +end +''' +match_indent = true + +[[patches]] +[patches.pattern] +target = "functions/state_events.lua" +pattern = '''G.FUNCS.draw_from_deck_to_hand = function(e)''' +position = "before" +payload = ''' +G.FUNCS.draw_from_hand_to_run = function(e) + local hand_count = #G.hand.cards + for i=1, hand_count do --draw cards from deck + draw_card(G.hand, G.cry_runarea, i*100/hand_count,'down', nil, nil, 0.08) + end +end +''' +match_indent = true + +[[patches]] +[patches.pattern] +target = "game.lua" +pattern = '''G.shop.alignment.offset.y = -5.3''' +position = "at" +payload = '''if not G.shop then return true end +G.shop.alignment.offset.y = -5.3''' +match_indent = true + +# Increase highlight limit for consumables +[[patches]] +[patches.pattern] +target = "game.lua" +pattern = "{card_limit = self.GAME.starting_params.consumable_slots, type = 'joker', highlight_limit = 1})" +position = "at" +payload = "{card_limit = self.GAME.starting_params.consumable_slots, type = 'joker', highlight_limit = 1e100})" +match_indent = true + +# Increase highlight limit for jokers +[[patches]] +[patches.pattern] +target = "game.lua" +pattern = "{card_limit = self.GAME.starting_params.joker_slots, type = 'joker', highlight_limit = 1})" +position = "at" +payload = "{card_limit = self.GAME.starting_params.joker_slots, type = 'joker', highlight_limit = 1e100})" +match_indent = true + +# Satellite Uplink +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = '''card = create_card("Planet", G.pack_cards, nil, nil, true, true, nil, 'pl1')''' +position = "at" +payload = ''' +if G.GAME.used_vouchers.v_cry_satellite_uplink and pseudorandom('cry_satellite_uplink') > 0.8 then + card = create_card("Code", G.pack_cards, nil, nil, true, true, nil, 'pl2') +else + card = create_card("Planet", G.pack_cards, nil, nil, true, true, nil, 'pl1') +end +''' +match_indent = true + +# Exploit - reset variables +[[patches]] +[patches.pattern] +target = "functions/state_events.lua" +pattern = '''-- TARGET: effects after hand evaluation''' +position = "after" +payload = ''' +G.E_MANAGER:add_event(Event({ + func = function() + G.GAME.cry_exploit_override = nil + return true + end +})) +''' +match_indent = true + +# Exploit - patch into smods +[[patches]] +[patches.pattern] +target = '''=[SMODS _ "src/overrides.lua"]''' +pattern = '''disp_text = text''' +position = "before" +payload = ''' +text = G.GAME.cry_exploit_override or text +''' +match_indent = true + +# Double Tag makes exact copy of rework tag +[[patches]] +[patches.pattern] +target = "tag.lua" +pattern = 'add_tag(Tag(_context.tag.key))' +position = "at" +payload = ''' + local tag = Tag(_context.tag.key) + if _context.tag.key == "tag_cry_rework" then + tag.ability.rework_edition = _context.tag.ability.rework_edition + tag.ability.rework_key = _context.tag.ability.rework_key + end + add_tag(tag) +''' +match_indent = true diff --git a/Cryptid/lovely/conveyor.toml b/Cryptid/lovely/conveyor.toml new file mode 100644 index 0000000..0dde77d --- /dev/null +++ b/Cryptid/lovely/conveyor.toml @@ -0,0 +1,29 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = -1 + +# Conveyor Deck - Don't sort cards +[[patches]] +[patches.pattern] +target = "cardarea.lua" +pattern = "table.sort(self.cards, function (a, b) return a.T.x + a.T.w/2 - 100*((a.pinned and not a.ignore_pinned) and a.sort_id or 0) < b.T.x + b.T.w/2 - 100*((b.pinned and not b.ignore_pinned) and b.sort_id or 0) end)" +position = "at" +payload = "if not G.GAME.modifiers.cry_conveyor then table.sort(self.cards, function (a, b) return a.T.x + a.T.w/2 - 100*((a.pinned and not a.ignore_pinned) and a.sort_id or 0) < b.T.x + b.T.w/2 - 100*((b.pinned and not b.ignore_pinned) and b.sort_id or 0) end) end" +match_indent = true + +# Start of round effects +[[patches]] +[patches.pattern] +target = "functions/state_events.lua" +pattern = "G.GAME.blind:set_blind(G.GAME.round_resets.blind)" +position = "after" +payload = ''' +if G.GAME.modifiers.cry_conveyor and #G.jokers.cards>0 then + local duplicated_joker = copy_card(G.jokers.cards[#G.jokers.cards]) + duplicated_joker:add_to_deck() + G.jokers:emplace(duplicated_joker) + G.jokers.cards[1]:start_dissolve() +end +''' +match_indent = true \ No newline at end of file diff --git a/Cryptid/lovely/cube.toml b/Cryptid/lovely/cube.toml new file mode 100644 index 0000000..a3246ba --- /dev/null +++ b/Cryptid/lovely/cube.toml @@ -0,0 +1,27 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = -1 + +# Joker Lock +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = "elseif v.enhancement_gate then" +position = "before" +payload = ''' +elseif v.source_gate then + if v.source_gate ~= _append then + add = nil + else + add = true + end +elseif v.joker_gate then + add = nil + for kk, vv in pairs(G.jokers.cards) do + if vv.ability.name == v.joker_gate then + add = true + end + end +''' +match_indent = true \ No newline at end of file diff --git a/Cryptid/lovely/equilibrium.toml b/Cryptid/lovely/equilibrium.toml new file mode 100644 index 0000000..65cef87 --- /dev/null +++ b/Cryptid/lovely/equilibrium.toml @@ -0,0 +1,30 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = -1 + +# non-pack scaling in pack slots +[[patches]] +[patches.pattern] +target = "game.lua" +pattern = "G.shop_booster.T.y, G.CARD_W*1.27, G.CARD_H*1.27, G.P_CARDS.empty, G.P_CENTERS[G.GAME.current_round.used_packs[i]], {bypass_discovery_center = true, bypass_discovery_ui = true})" +position = "at" +payload = "G.shop_booster.T.y, G.CARD_W*(G.P_CENTERS[G.GAME.current_round.used_packs[i]].set == 'Booster' and 1.27 or 1), G.CARD_H*(G.P_CENTERS[G.GAME.current_round.used_packs[i]].set == 'Booster' and 1.27 or 1), G.P_CARDS.empty, G.P_CENTERS[G.GAME.current_round.used_packs[i]], {bypass_discovery_center = true, bypass_discovery_ui = true})" +match_indent = true + +# scaling issues when reclaiming Overstock +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +pattern = "G.GAME.shop.joker_max*1.02*G.CARD_W," +position = "at" +payload = "math.min(G.GAME.shop.joker_max,4)*1.02*G.CARD_W," +match_indent = true + +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = "G.shop_jokers.T.w = G.GAME.shop.joker_max*1.01*G.CARD_W" +position = "at" +payload = "G.shop_jokers.T.w = math.min(G.GAME.shop.joker_max,4)*1.02*G.CARD_W" +match_indent = true \ No newline at end of file diff --git a/Cryptid/lovely/lib_gameset.toml b/Cryptid/lovely/lib_gameset.toml new file mode 100644 index 0000000..962689d --- /dev/null +++ b/Cryptid/lovely/lib_gameset.toml @@ -0,0 +1,199 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = -1 + +# Turn Jimbo into Jolly Joker +[[patches]] +[patches.pattern] +target = "card_character.lua" +pattern = 'self.children.card.states.visible = false' +position = "before" +payload = "self.children.card:set_ability(G.P_CENTERS.j_jolly)" +match_indent = true + +[[patches]] +[patches.pattern] +target = "card_character.lua" +pattern = 'colours = {G.C.RED, G.C.BLUE, G.C.ORANGE},' +position = "at" +payload = 'colours = {G.C.CRY_EXOTIC, G.C.BLUE, G.C.CRY_JOLLY},' +match_indent = true + +# Make profiles all start with a prefix +[[patches]] +[patches.pattern] +target = "game.lua" +pattern = 'self:load_profile(G.SETTINGS.profile or 1)' +position = "before" +payload = '''Cryptid.profile_prefix = Jen and "J" or "M" +if type(G.SETTINGS.profile) ~= "string" or G.SETTINGS.profile:sub(1, #Cryptid.profile_prefix) ~= Cryptid.profile_prefix then + G.SETTINGS.profile = Cryptid.profile_prefix .. "1" +end +for i = 1, 3 do + G.PROFILES[Cryptid.profile_prefix .. i] = {} +end''' +match_indent = true + +# Remove the builtin "P" prefix +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +pattern = 'profile_data.name = profile_data.name or ("P".._profile)' +position = "at" +payload = 'profile_data.name = profile_data.name or (_profile)' +match_indent = true + +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +pattern = 'G.PROFILES[G.SETTINGS.profile].name = "P"..G.SETTINGS.profile' +position = "at" +payload = 'G.PROFILES[G.SETTINGS.profile].name = G.SETTINGS.profile' +match_indent = true + +# Pre-load all profiles in selection menu +[[patches]] +[patches.pattern] +target = "functions/button_callbacks.lua" +pattern = 'for i = 1, 3 do' +position = "after" +payload = 'i = Cryptid.profile_prefix .. i' +match_indent = true + +# Gameset sprite in profile screen +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +pattern = '{n=G.UIT.C, config={align = "cl", minw = rwidth}, nodes={{n=G.UIT.T, config={text = tostring(profile_data.career_stats.c_wins),colour = G.C.RED, shadow = true, scale = 1*scale}}}}' +position = "after" +payload = ',{n=G.UIT.C, config={align = "cl", minw = rwidth}, nodes={{n=G.UIT.O, config={object = Cryptid.gameset_sprite(1, _profile)}}}}' +match_indent = true + +# Gameset sprite in deck select +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +pattern = '{n=G.UIT.C, config={align = "cm", minw = 2.5}, nodes={}}' +position = "at" +payload = '{n=G.UIT.C, config={align = "cm", minw = 0.2}, nodes={}},{n=G.UIT.C, config={align = "cl", minw = rwidth}, nodes={{n=G.UIT.O, config={object = Cryptid.gameset_sprite()}}}}' +match_indent = true + +# Gameset sprite in win screen +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +pattern = '{n=G.UIT.R, config={align = "cm", minh = 0.4, minw = 0.1}, nodes={}},' +position = "at" +payload = '{n=G.UIT.R, config={align = "cm", minh = 0.1, minw = 0.1}, nodes={}},' +match_indent = true + +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +pattern = 'not show_win_cta and {n=G.UIT.R, config={align = "cm", minh = 0.2, minw = 0.1}, nodes={}} or nil,' +position = "at" +payload = 'not show_win_cta and {n=G.UIT.R, config={align = "cm", minh = 0.1, minw = 0.1}, nodes={}} or nil,' +match_indent = true + +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +pattern = "not show_win_cta and UIBox_button({button = 'go_to_menu', label = {localize('b_main_menu')}, minw = 2.5, maxw = 2.5, minh = 1, focus_args = {nav = 'wide'}}) or nil," +position = "after" +payload = '{n=G.UIT.R, config={align = "cm", minw = rwidth}, nodes={{n=G.UIT.O, config={object = Cryptid.gameset_sprite()}}}},' +match_indent = true + +# Gameset sprite in lose screen +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +pattern = "show_lose_cta and" +position = "before" +payload = '{n=G.UIT.R, config={align = "cm"}, nodes={{n=G.UIT.C, config={align = "cm", minw = rwidth}, nodes={{n=G.UIT.O, config={object = Cryptid.gameset_sprite()}}}},' +match_indent = true + +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +pattern = "{n=G.UIT.T, config={text = localize('b_main_menu'), scale = 0.5, colour = G.C.UI.TEXT_LIGHT}}" +position = "after" +payload = '}}' +match_indent = true + +[[patches]] +[patches.regex] +target = "functions/UI_definitions.lua" +pattern = '''\{n=G\.UIT\.R, config=\{align = "cm", padding = 0\.1\}, nodes=\{\s+\{n=G\.UIT\.R, config=\{id = 'from_game_over',''' +position = "at" +payload = '''{n=G.UIT.C, config={align = "cm", padding = 0.1}, nodes={ +{n=G.UIT.R, config={id = 'from_game_over',''' + +# Disabled UI +# Show disabled tooltip +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = "local info_queue = {}" +position = "after" +payload = '''if _c.cry_disabled or (_c.force_gameset and _c.force_gameset == 'disabled') then + if _c.cry_disabled then + if _c.cry_disabled.type == "card_dependency" then + local name = Cryptid.get_center(_c.cry_disabled.key) and localize{type = 'name_text', set = Cryptid.get_center(_c.cry_disabled.key).set, key = _c.cry_disabled.key} or _c.cry_disabled.key + info_queue[#info_queue+1] = {key = 'disabled_card_dependency', set = 'Other', specific_vars = {name}} + elseif _c.cry_disabled.type == "mod_dependency" then + local name = Cryptid.cross_mod_names[_c.cry_disabled.key] or _c.cry_disabled.key + info_queue[#info_queue+1] = {key = 'disabled_mod_dependency', set = 'Other', specific_vars = {name}} + elseif _c.cry_disabled.type == "mod_conflict" then + local name = SMODS.Mods[_c.cry_disabled.key].name + info_queue[#info_queue+1] = {key = 'disabled_mod_conflict', set = 'Other', specific_vars = {name}} + else + if not (_c.force_gameset and _c.force_gameset ~= 'disabled') then + info_queue[#info_queue+1] = {key = 'disabled', set = 'Other'} + end + end + else + info_queue[#info_queue+1] = {key = 'disabled', set = 'Other'} + end +end''' +match_indent = true + +# replace rarity badge with gameset +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +pattern = "card_type = (debuffed and AUT.card_type ~= 'Enhanced') and localize('k_debuffed') or card_type" +position = "after" +payload = ''' +if AUT.card_type == "Back" then + card_type = localize('b_deck') +end +if AUT.card_type == "Tag" then + card_type = localize('b_tag') +end +if AUT.card_type == "Blind" then + card_type = localize('b_blind') +end +if AUT.card_type == "Content Set" then + card_type = localize('k_content_set') +end +if card.gameset_select then + card_type = localize('cry_gameset_'..card.config.center.force_gameset) + if card_type == "ERROR" then + card_type = localize('cry_gameset_custom') + end +end +if not card.gameset_select and card.config.center and card.config.center.cry_disabled then + card_type = localize('cry_gameset_disabled') +end +''' +match_indent = true + +# Descriptions for Backs and Blinds in gameset UI +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = "elseif _c.set == 'Tag' then" +position = "before" +payload = "elseif _c.set == 'Back' or _c.set == 'Blind' then localize{type = 'descriptions', key = _c.key, set = _c.set, nodes = desc_nodes, vars = specific_vars or {}}" +match_indent = true \ No newline at end of file diff --git a/Cryptid/lovely/lib_https.toml b/Cryptid/lovely/lib_https.toml new file mode 100644 index 0000000..67b8a4d --- /dev/null +++ b/Cryptid/lovely/lib_https.toml @@ -0,0 +1,74 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = -1 + +# hi it's me toneblock and i'm being stupid again! (Game:update inject) +[[patches]] +[patches.pattern] +target = "game.lua" +pattern = '''if G.FILE_HANDLER and G.FILE_HANDLER and G.FILE_HANDLER.update_queued and (''' +position = "before" +payload = ''' +if not Cryptid.member_count_delay then Cryptid.member_count_delay = 0 end +if (Cryptid.member_count_delay > 5) or not Cryptid.member_count then -- it doesn't need to update this frequently? but it also doesn't need to be higher tbh... + if Cryptid.update_member_count then Cryptid.update_member_count() end -- i honestly hate nil checks like this, wish there was a shorthand + Cryptid.member_count_delay = 0 +else + Cryptid.member_count_delay = Cryptid.member_count_delay + dt +end +''' +match_indent = true + +# call Cryptid.update_member_count() whenever the collection is opened to ensure it updates properly on title collection if it can (better than running it on loc_vars) +# it's not computationally intense at all, so whatever +[[patches]] +[patches.pattern] +target = "functions/button_callbacks.lua" +pattern = '''G.FUNCS.your_collection = function(e)''' +position = "after" +payload = ''' +if Cryptid.update_member_count then Cryptid.update_member_count() end +''' +match_indent = true + +# notice if https is disabled (by default) +# also does some other things since this is patching in the same spot (SDM0 easter egg) +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = "if _c.set == 'Other' then" +position = "before" +payload = ''' +if _c.name == 'cry-membershipcard' or _c.name == 'cry-membershipcardtwo' then + if not Cryptid_config["HTTPS Module"] then + if G.localization.descriptions.Other.cry_https_disabled then + main_end = {} + localize{type = 'other', key = 'cry_https_disabled', nodes = main_end, vars = {}} + main_end = main_end[1] + end + end +end +if _c.name == 'cry-translucent Joker' then + if G.jokers and G.jokers.cards then + for k, v in ipairs(G.jokers.cards) do + if (v.edition and v.edition.negative) and (G.localization.descriptions.Other.remove_negative)then + main_end = {} + localize{type = 'other', key = 'remove_negative', nodes = main_end, vars = {}} + main_end = main_end[1] + break + end + end + end +end +if _c.name == 'cry-blurred Joker' then + if (SMODS.Mods["sdm0sstuff"] or {}).can_load then + if G.localization.descriptions.Other.blurred_sdm0 then + main_end = {} + localize{type = 'other', key = 'blurred_sdm0', nodes = main_end, vars = {}} + main_end = main_end[1] + end + end +end +''' +match_indent = true \ No newline at end of file diff --git a/Cryptid/lovely/lib_misc.toml b/Cryptid/lovely/lib_misc.toml new file mode 100644 index 0000000..e0264de --- /dev/null +++ b/Cryptid/lovely/lib_misc.toml @@ -0,0 +1,259 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = -1 + +# Make the splash screen more jolly +# Requires "Custom Main Menu" config to be enabled +[[patches]] +[patches.pattern] +target = "game.lua" +pattern = "SC = Card(G.ROOM.T.w/2 - SC_scale*G.CARD_W/2, 10. + G.ROOM.T.h/2 - SC_scale*G.CARD_H/2, SC_scale*G.CARD_W, SC_scale*G.CARD_H, G.P_CARDS.empty, G.P_CENTERS['j_joker'])" +position = "after" +payload = ''' +if ((Cryptid_config and Cryptid_config.menu) or false) then + SC = Card(G.ROOM.T.w/2 - SC_scale*G.CARD_W/2, 10. + G.ROOM.T.h/2 - SC_scale*G.CARD_H/2, SC_scale*G.CARD_W, SC_scale*G.CARD_H, G.P_CARDS.empty, G.P_CENTERS['j_jolly'],{bypass_discovery_center = true, bypass_discovery_ui = true}) +end +''' +match_indent = true + +# Make cards in splash screen CCD cards +# Disabling this because it caused fps drops on profiles with nothing discovered +[[patches]] +[patches.pattern] +target = "game.lua" +pattern = "if math.random() > 0.8 then card.sprite_facing = 'back'; card.facing = 'back' end" +position = "before" +payload = ''' +--if Cryptid.random_consumable then card:set_ability(Cryptid.random_consumable('cry_splash',{"no_grc"},nil,nil,true), true, nil) end +''' +match_indent = true + +# Show Glitched Edition to confirm Cryptid is Active if custom main menu is enabled +[[patches]] +[patches.pattern] +target = "game.lua" +pattern = "replace_card.states.visible = false" +position = "before" +payload = ''' +if ((Cryptid_config and Cryptid_config.menu) or false) then + replace_card:set_edition(G.P_CENTERS.e_cry_glitched and 'e_cry_glitched' or 'e_negative',true,true) +end +''' +match_indent = true + +# Patch related crash +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "if not initial then G.GAME.blind:debuff_card(self) end" +position = "at" +payload = "if not initial and G.GAME and G.GAME.blind then G.GAME.blind:debuff_card(self) end" +match_indent = true + +# Draw midground layer +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "if self.config.center.soul_pos and (self.config.center.discovered or self.bypass_discovery_center) then" +position = "after" +payload = ''' +if self.config.center.soul_pos and self.config.center.soul_pos.extra and (self.config.center.discovered or self.bypass_discovery_center) then + local scale_mod = 0.07-- + 0.02*math.cos(1.8*G.TIMERS.REAL) + 0.00*math.cos((G.TIMERS.REAL - math.floor(G.TIMERS.REAL))*math.pi*14)*(1 - (G.TIMERS.REAL - math.floor(G.TIMERS.REAL)))^3 + local rotate_mod = 0--0.05*math.cos(1.219*G.TIMERS.REAL) + 0.00*math.cos((G.TIMERS.REAL)*math.pi*5)*(1 - (G.TIMERS.REAL - math.floor(G.TIMERS.REAL)))^2 + self.children.floating_sprite2:draw_shader('dissolve',0, nil, nil, self.children.center,scale_mod, rotate_mod,nil, 0.1--[[ + 0.03*math.cos(1.8*G.TIMERS.REAL)--]],nil, 0.6) + self.children.floating_sprite2:draw_shader('dissolve', nil, nil, nil, self.children.center, scale_mod, rotate_mod) +end +''' +match_indent = true + + +# Custom variables in info queue +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = "function generate_card_ui(_c, full_UI_table, specific_vars, card_type, badges, hide_desc, main_start, main_end)" +position = "after" +payload = "if _c.specific_vars then specific_vars = _c.specific_vars end" +match_indent = true + +# Fix not all cards returning to hand on big hands +[[patches]] +[patches.pattern] +target = "game.lua" +pattern = "{card_limit = 500, type = 'discard'})" +position = "at" +payload = "{card_limit = 1e308, type = 'discard'})" +match_indent = true + +# When hand size exceeds deck size, space the cards as if the hand size was equal to the deck size +[[patches]] +[patches.pattern] +target = "cardarea.lua" +pattern = "function CardArea:align_cards()" +position = "after" +payload = ''' + if self.config.type == 'hand' then + self.config.temp_limit = math.min(self.config.card_limit, #G.playing_cards) + end +''' +match_indent = true + +# Crash fix +[[patches]] +[patches.pattern] +target = "functions/button_callbacks.lua" +pattern = "if not G.SAVED_GAME.VERSION or G.SAVED_GAME.VERSION < '0.9.2' then" +position = "at" +payload = "if not G.SAVED_GAME or not G.SAVED_GAME.VERSION or G.SAVED_GAME.VERSION < '0.9.2' then" +match_indent = true + +# Register banned bosses for rush hour +# Also initializes disabled/enabled cards +[[patches]] +[patches.pattern] +target = "game.lua" +pattern = "set_profile_progress()" +position = "before" +payload = ''' +for i = 1, #G.CHALLENGES do + if (G.CHALLENGES[i].id == 'c_cry_rush_hour' or G.CHALLENGES[i].id == 'c_cry_rush_hour_ii' or G.CHALLENGES[i].id == 'c_cry_rush_hour_iii') and #G.CHALLENGES[i].restrictions.banned_other == 0 then + for k, v in pairs(G.P_BLINDS) do + if k ~= "bl_cry_clock" and k ~= "bl_cry_lavender_loop" and v.boss then + G.CHALLENGES[i].restrictions.banned_other[#G.CHALLENGES[i].restrictions.banned_other+1] = {id = k, type = 'blind'} + end + end + end +end +''' +match_indent = true + +# Prevent Jokers from spitting empty messages +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = "text = extra.message or text" +position = "after" +payload = "if not text or text == '' then return end" +match_indent = true + +# Add default pool value for Consumeables +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = 'else _pool[#_pool + 1] = "j_joker"' +position = "before" +payload = '''elseif _type == 'Consumeables' then _pool[#_pool + 1] = "c_ceres"''' +match_indent = true + +# hand size forgiveness if playing negative or antimatter deck (someone please fix) +[[patches]] +[patches.pattern] +target = "game.lua" +pattern = "function Game:update_draw_to_hand(dt)" +position = "after" +payload = ''' +if G.GAME.selected_back and (G.GAME.selected_back.name == 'cry--Negative Deck' or G.GAME.selected_back.name == 'cry-Antimatter') and G.hand.config.card_limit <= 0 then -- 'cry--Negative Deck'... sure + G.hand.config.card_limit = 1 +end +''' +match_indent = true + +# init Cryptid global through lovely +# so other mods can add things to obj pools +# and define some stub functions so that the game does not immediately crash when talisman isn't loaded +[[patches]] +[patches.pattern] +target = "main.lua" +pattern = '''function love.load()''' +position = "before" +payload = ''' +Cryptid = {} +Cryptid.aliases = {} +function cry_format(...) + return ... +end + +-- These ones are deprecated, they do not do anything and are just here to prevent crashes +Cryptid.memepack = {} +Cryptid.food = {} +Cryptid.M_jokers = {} +Cryptid.Megavouchers = {} +''' +match_indent = true + +# Adds cry_creating_card event +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = ''' + check_for_unlock({type = 'have_edition'}) +end +''' +position = "after" +payload = ''' +SMODS.calculate_context{cry_creating_card = true, card = card} +''' +match_indent = true + +# plural handler (annoyingly fragile overwrite) +# also i pass the whole vars here, even though it's inefficient, just because it looks better +# whatever +[[patches]] +[patches.pattern] +target = "functions/misc_functions.lua" +pattern = ''' +assembled_string = assembled_string..(type(subpart) == 'string' and subpart or format_ui_value(args.vars[tonumber(subpart[1])]) or 'ERROR') +''' +position = "at" +payload = ''' +assembled_string = assembled_string..(type(subpart) == 'string' and subpart or (Cryptid.pluralize and Cryptid.pluralize(subpart[1], args.vars)) or format_ui_value(args.vars[tonumber(subpart[1])]) or 'ERROR') +''' +match_indent = true + +# prevent misprint crashing when big +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = ''' +for i = self.ability.extra.min, self.ability.extra.max do + r_mults[#r_mults+1] = tostring(i) +end +''' +position = "at" +payload = ''' +if self.ability.extra.max - self.ability.extra.min < 500 then + for i = self.ability.extra.min, self.ability.extra.max do + r_mults[#r_mults+1] = tostring(i) + end +else + for i = 1, 50 do + r_mults[#r_mults+1] = tostring(math.random(self.ability.extra.min, self.ability.extra.max)) + end +end + +''' +match_indent = true + +# handle banned playing cards +# this must patch into pseudorandom_element to not break Steamodded in_pool logic +[[patches]] +[patches.pattern] +target = "functions/misc_functions.lua" +pattern = "if keep then" +position = "before" +payload = ''' +if G.GAME and G.GAME.cry_banned_pcards and G.GAME.cry_banned_pcards[k] then + keep = false +end +''' +match_indent = true + +# Cross-Mod Content - allow Cryptid to load atlas/sound/shader files from other mods +[[patches]] +[patches.pattern] +target = '''=[SMODS _ "src/game_object.lua"]''' +pattern = "self.full_path = (self.mod and self.mod.path or SMODS.path) .." +position = "at" +payload = "self.full_path = (self.mod_path or self.mod and self.mod.path or SMODS.path) .." +match_indent = true diff --git a/Cryptid/lovely/lib_modifiers.toml b/Cryptid/lovely/lib_modifiers.toml new file mode 100644 index 0000000..04ac8e1 --- /dev/null +++ b/Cryptid/lovely/lib_modifiers.toml @@ -0,0 +1,127 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = -1 + +# Apply booster pack edition and stickers to contents - by Jen Walter +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "card.T.x = self.T.x" +position = "before" +payload = ''' +local edi = self.edition or {} +if edi.type then + if card.ability.name ~= "cry-meteor" + and card.ability.name ~= "cry-exoplanet" + and card.ability.name ~= "cry-stardust" then + card:set_edition({[edi.type] = true}) + end +end +local stickers = {'eternal', 'perishable', 'rental', 'banana'} +for _, v in ipairs(stickers) do + if self.ability[v] then + card.ability[v] = self.ability[v] + end +end +''' +match_indent = true + +# save ability (to deal with re-misprinting) +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "G.vouchers:emplace(card_to_save)" +position = "before" +payload = ''' +card_to_save.ability.extra = self and self.ability.extra or card_to_save.ability.extra +''' +match_indent = true + +# patch for stickers in challenge ui +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +pattern = "if v.eternal then card:set_eternal(true) end" +position = "before" +payload = ''' +if v.stickers then + for i, _v in ipairs(v.stickers) do + SMODS.Stickers[_v]:apply(card, true) + end +end +''' +match_indent = true + +# same deal for actual game +[[patches]] +[patches.pattern] +target = "game.lua" +pattern = "if v.eternal then _joker:set_eternal(true) end" +position = "before" +payload = ''' +if v.stickers then + for i, _v in ipairs(v.stickers) do + SMODS.Stickers[_v]:apply(_joker, true) + end +end +''' +match_indent = true + +# remove eternal badge +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "if self.ability.eternal then badges[#badges + 1] = 'eternal' end" +position = "at" +payload = ''' +if not self.ability.cry_absolute then + if self.ability.eternal then badges[#badges + 1] = 'eternal' end +end +''' +match_indent = true + +# remove old pinned badge +# i am fully aware that these badge removals may break stuff since they are good targets +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "if self.pinned then badges[#badges + 1] = 'pinned_left' end" +position = "at" +payload = ''' +-- if self.pinned then badges[#badges + 1] = 'pinned_left' end +''' +match_indent = true + +# don't draw old perishable texture +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = '''if self.ability.perishable then''' +position = "at" +payload = '''if self.ability.perishable and not layer then''' +match_indent = true + +# Adds cry_debuff_immune card modifier +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = 'if self.ability and self.ability.perma_debuff then self.debuff = true end' +position = "after" +payload = ''' +if self.cry_debuff_immune then + self.debuff = false +end +''' +match_indent = true + +# Removes cry_debuff_immune at the end of the round +[[patches]] +[patches.pattern] +target = '''=[SMODS _ "src/utils.lua"]''' +pattern = '-- TARGET: effects after end of round evaluation' +position = "after" +payload = ''' +card.cry_debuff_immune = false +''' +match_indent = true diff --git a/Cryptid/lovely/lib_ui.toml b/Cryptid/lovely/lib_ui.toml new file mode 100644 index 0000000..4bfb007 --- /dev/null +++ b/Cryptid/lovely/lib_ui.toml @@ -0,0 +1,101 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = -1 + +# Antimatter Deck +[[patches]] +[patches.pattern] +target = '''=[SMODS _ "src/card_draw.lua"]''' +pattern = "self.children.back:draw_shader('dissolve')" +position = "at" +payload = ''' +local currentBack = self.params.viewed_back and G.GAME.viewed_back or G.GAME.selected_back +if currentBack and currentBack.effect.config.cry_antimatter or currentBack.effect.config.cry_force_edition == 'negative' then + self.children.back:draw_shader('negative', nil, self.ARGS.send_to_shader) + self.children.center:draw_shader('negative_shine', nil, self.ARGS.send_to_shader) +else + self.children.back:draw_shader('dissolve') +end +''' +match_indent = true + +# render gameset as sticker +[[patches]] +[patches.pattern] +target = '''=[SMODS _ "src/card_draw.lua"]''' +pattern = "if self.sticker and G.shared_stickers[self.sticker] then" +position = "before" +payload = ''' +if not Cryptid.shared_gamesets and G.ASSET_ATLAS["cry_gameset"] then + Cryptid.shared_gamesets = { + modest = Sprite(0, 0, G.CARD_W, G.CARD_H, G.ASSET_ATLAS["cry_gameset"], {x = 0,y = 0}), + mainline = Sprite(0, 0, G.CARD_W, G.CARD_H, G.ASSET_ATLAS["cry_gameset"], {x = 1,y = 0}), + madness = Sprite(0, 0, G.CARD_W, G.CARD_H, G.ASSET_ATLAS["cry_gameset"], {x = 2,y = 0}), + custom = Sprite(0, 0, G.CARD_W, G.CARD_H, G.ASSET_ATLAS["cry_gameset"], {x = 3,y = 0}), + selected = Sprite(0, 0, G.CARD_W, G.CARD_H, G.ASSET_ATLAS["cry_sticker"], {x = 0,y = 4}), + } +end +local gameset_key +if self.config.center.force_gameset then + gameset_key = self.config.center.force_gameset + if gameset_key ~= "disabled" and gameset_key ~= "modest" and gameset_key ~= "mainline" and gameset_key ~= "madness" then + gameset_key = "custom" + end +end +if self.gameset_select and Cryptid.shared_gamesets[gameset_key] then +Cryptid.shared_gamesets[gameset_key].role.draw_major = self +Cryptid.shared_gamesets[gameset_key]:draw_shader('dissolve', nil, nil, nil, self.children.center) +Cryptid.shared_gamesets[gameset_key]:draw_shader('voucher', nil, self.ARGS.send_to_shader, nil, self.children.center) +end +''' +match_indent = true + +# make disabled cards visually debuffed +# warning: this also patches a lot of extra stuff, but that shouldn't matter +# since you shouldn't be able to access them outside of the collection anyway +[[patches]] +[patches.pattern] +target = '''=[SMODS _ "src/card_draw.lua"]''' +pattern = "if self.debuff then" +position = "at" +payload = "if self.debuff or (Cryptid.gameset and Cryptid.gameset(self) == 'disabled') or (self.config.center.gameset_config and self.config.center.gameset_config[Cryptid.gameset(self)] and self.config.center.gameset_config[Cryptid.gameset(self)].disabled) or (self.config.center.cry_disabled and not self.gameset_select) then" +match_indent = true + +# Shine on Oversaturated to make it more noticable +[[patches]] +[patches.pattern] +target = '''=[SMODS _ "src/card_draw.lua"]''' +pattern = "if (self.edition and self.edition.negative) or (self.ability.name == 'Antimatter' and (self.config.center.discovered or self.bypass_discovery_center)) then" +position = 'at' +match_indent = true +payload = "if (self.edition and (self.edition.negative or self.edition.cry_oversat)) or (self.ability.name == 'Antimatter' and (self.config.center.discovered or self.bypass_discovery_center)) then" + +# Make description UI always appear if card is highlighted +[[patches]] +[patches.pattern] +target = "engine/node.lua" +pattern = "if self.children.h_popup then" +position = 'at' +match_indent = true +payload = ''' +if self.children.h_popup and not (self.force_popup and self:force_popup() and Cryptid["force_tooltips"]) then +''' + +# Let description tooltips work for any object +[[patches]] +[patches.pattern] +target = "functions/misc_functions.lua" +pattern = "detailed_tooltip = part.control.T and (G.P_CENTERS[part.control.T] or G.P_TAGS[part.control.T]) or nil," +position = 'at' +match_indent = true +payload = "detailed_tooltip = part.control.T and (Cryptid.get_center(part.control.T) or (G.P_CENTERS[part.control.T] or G.P_TAGS[part.control.T])) or nil," + +# Remove consumable use UI in the collection +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "if self.highlighted and self.area and self.area.config.type ~= 'shop' then" +position = 'at' +match_indent = true +payload = "if self.highlighted and self.area and self.area.config.type ~= 'shop' and not self.area.config.collection then" diff --git a/Cryptid/lovely/misc.toml b/Cryptid/lovely/misc.toml new file mode 100644 index 0000000..4202722 --- /dev/null +++ b/Cryptid/lovely/misc.toml @@ -0,0 +1,494 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = -1 + +# Detect if edition comes from copy_card +[[patches]] +[patches.pattern] +target = 'functions/common_events.lua' +pattern = '''new_card:set_edition(other.edition or {}, nil, true)''' +position = 'before' +payload = ''' +new_card.from_copy = true +''' +match_indent = true + +# Update value of Monsters created via copy_card +[[patches]] +[patches.pattern] +target = 'functions/common_events.lua' +pattern = "if not strip_edition then" +position = 'before' +payload = ''' +if new_card.ability.name == "cry-longboi" then new_card:set_ability(new_card.config.center) end +''' +match_indent = true + +# Joker BigNum value support +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "if self.ability.name == 'Campfire' and G.GAME.blind.boss and not (G.GAME.blind.config and G.GAME.blind.config.bonus) and self.ability.x_mult > 1 then" +position = "at" +payload = ''' +if self.ability.name == 'Campfire' and G.GAME.blind.boss and not (G.GAME.blind.config and G.GAME.blind.config.bonus) and to_big(self.ability.x_mult) > to_big(1) then +''' +match_indent = true + +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "if self.ability.name == 'Hit the Road' and self.ability.x_mult > 1 then" +position = "at" +payload = ''' +if self.ability.name == 'Hit the Road' and to_big(self.ability.x_mult) > to_big(1) then +''' +match_indent = true + +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "if self.ability.x_mult > 1 then" +position = "at" +payload = ''' +if to_big(self.ability.x_mult) > to_big(1) then +''' +match_indent = true + +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "if self.ability.name ~= 'Seeing Double' and self.ability.x_mult > 1 and (self.ability.type == '' or next(context.poker_hands[self.ability.type])) then" +position = "at" +payload = ''' +if self.ability.name ~= 'Seeing Double' and to_big(self.ability.x_mult) > to_big(1) and (self.ability.type == '' or next(context.poker_hands[self.ability.type])) then +''' +match_indent = true + +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "if self.ability.name == 'Caino' and self.ability.caino_xmult > 1 then" +position = "at" +payload = ''' +if self.ability.name == 'Caino' and to_big(self.ability.caino_xmult) > to_big(1) then +''' +match_indent = true + +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "if self.ability.t_mult > 0 and next(context.poker_hands[self.ability.type]) then" +position = "at" +payload = ''' +if to_big(self.ability.t_mult) > to_big(0) and next(context.poker_hands[self.ability.type]) then +''' +match_indent = true + +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "if self.ability.t_chips > 0 and next(context.poker_hands[self.ability.type]) then" +position = "at" +payload = ''' +if to_big(self.ability.t_chips) > to_big(0) and next(context.poker_hands[self.ability.type]) then +''' +match_indent = true + +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "if self.ability.name == 'Ceremonial Dagger' and self.ability.mult > 0 then" +position = "at" +payload = ''' +if self.ability.name == 'Ceremonial Dagger' and to_big(self.ability.mult) > to_big(0) then +''' +match_indent = true + +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "if self.ability.name == 'Castle' and (self.ability.extra.chips > 0) then" +position = "at" +payload = ''' +if self.ability.name == 'Castle' and (to_big(self.ability.extra.chips) > to_big(0)) then +''' +match_indent = true + +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "if self.ability.name == 'Swashbuckler' and self.ability.mult > 0 then" +position = "at" +payload = ''' +if self.ability.name == 'Swashbuckler' and to_big(self.ability.mult) > to_big(0) then +''' +match_indent = true + +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "if self.ability.name == 'Spare Trousers' and self.ability.mult > 0 then" +position = "at" +payload = ''' +if self.ability.name == 'Spare Trousers' and to_big(self.ability.mult) > to_big(0) then +''' +match_indent = true + +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "if self.ability.name == 'Ride the Bus' and self.ability.mult > 0 then" +position = "at" +payload = ''' +if self.ability.name == 'Ride the Bus' and to_big(self.ability.mult) > to_big(0) then +''' +match_indent = true + +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "if self.ability.name == 'Flash Card' and self.ability.mult > 0 then" +position = "at" +payload = ''' +if self.ability.name == 'Flash Card' and to_big(self.ability.mult) > to_big(0) then +''' +match_indent = true + +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "if self.ability.name == 'Popcorn' and self.ability.mult > 0 then" +position = "at" +payload = ''' +if self.ability.name == 'Popcorn' and to_big(self.ability.mult) > to_big(0) then +''' +match_indent = true + +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "if self.ability.name == 'Green Joker' and self.ability.mult > 0 then" +position = "at" +payload = ''' +if self.ability.name == 'Green Joker' and to_big(self.ability.mult) > to_big(0) then +''' +match_indent = true + +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "if self.ability.name == 'Red Card' and self.ability.mult > 0 then" +position = "at" +payload = ''' +if self.ability.name == 'Red Card' and to_big(self.ability.mult) > to_big(0) then +''' +match_indent = true + +[[patches]] +[patches.pattern] +target = "functions/misc_functions.lua" +pattern = "function localize(args, misc_cat)" +position = "after" +payload = ''' +if args and args.vars then + local reset = {} + for i, j in pairs(args.vars) do + if type(j) == 'table' then + if (j.new and type(j.new) == "function") and ((j.m and j.e) or (j.array and j.sign and (type(j.array) == "table"))) then + reset[i] = number_format(j) + end + end + end + for i, j in pairs(reset) do + args.vars[i] = j + end +end +''' +match_indent = true + +# Compat UI for Old Blueprint and Gemini + +# I deleted the patches --Jevonn (test) + +# calculate wheel fail (for Wheel of Hope) +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "if self.ability.name == 'Ectoplasm' or self.ability.name == 'Hex' or pseudorandom('wheel_of_fortune') < G.GAME.probabilities.normal/self.ability.extra then" +position = "after" +payload = ''' +if self.ability.name == 'The Wheel of Fortune' then self.cry_wheel_success = true end +''' +match_indent = false + +# no "Again!" text if a card will shatter +[[patches]] +[patches.pattern] +target = "functions/state_events.lua" +pattern = '''if reps[j] ~= 1 then''' +position = "at" +payload = '''if reps[j] ~= 1 and (not scoring_hand or not scoring_hand[i] or not scoring_hand[i].will_shatter) then''' +match_indent = true + +# m +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = '''if self.ability.consumeable or self.ability.set == 'Joker' or (self.area and self.area == G.pack_cards) then''' +position = "at" +payload = '''if true then''' +match_indent = true + +# Energia - detect blind skips from tag +# kitty printer - add cat tag +[[patches]] +[patches.pattern] +target = "functions/button_callbacks.lua" +pattern = '''add_tag(_tag.config.ref_table)''' +position = "at" +payload = ''' +add_tag( next(SMODS.find_card('j_cry_kittyprinter')) and Tag('tag_cry_cat') or _tag.config.ref_table, true) +''' +match_indent = true + +# Energia - don't add tags from save load +[[patches]] +[patches.pattern] +target = "game.lua" +pattern = '''add_tag(_tag)''' +position = "at" +payload = '''add_tag(_tag, nil, true)''' +match_indent = true + +# Beta Deck - merge slots +[[patches]] +[patches.pattern] +target = "game.lua" +pattern = '''self.consumeables = CardArea(''' +position = "before" +payload = '''if not G.GAME.modifiers.cry_beta then''' +match_indent = true + +[[patches]] +[patches.pattern] +target = "game.lua" +pattern = '''self.discard = CardArea(''' +position = "before" +payload = '''else +self.jokers = CardArea( + 0, 0, + CAI.joker_W+CAI.consumeable_W, + CAI.joker_H, + {card_limit = self.GAME.starting_params.joker_slots+self.GAME.starting_params.consumable_slots-1, type = 'joker', highlight_limit = 1e100}) +self.consumeables = self.jokers +end''' +match_indent = true + +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = '''G.consumeables.T.y = 0''' +position = "after" +payload = '''G.jokers.T.x = G.hand.T.x - 0.1 +G.jokers.T.y = 0''' +match_indent = true + +# Make Perkeo only copy consumables +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = '''if G.consumeables.cards[1] then''' +position = "at" +payload = '''local eligibleJokers = {} +for i = 1, #G.consumeables.cards do + if G.consumeables.cards[i].ability.consumeable then + eligibleJokers[#eligibleJokers + 1] = G.consumeables.cards[i] + end +end +if #eligibleJokers > 0 then''' +match_indent = true + +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = '''local card = copy_card(pseudorandom_element(G.consumeables.cards, pseudoseed('perkeo')), nil)''' +position = "at" +payload = '''local card = copy_card(pseudorandom_element(eligibleJokers, pseudoseed('perkeo')), nil)''' +match_indent = true + +# More Beta Deck fixes +[[patches]] +[patches.pattern] +target = "functions/state_events.lua" +pattern = '''for i=1, #G.jokers.cards + #G.consumeables.cards do''' +position = "at" +payload = ''' +local numcards = #G.jokers.cards + #G.consumeables.cards +if G.GAME.modifiers.cry_beta then numcards = #G.jokers.cards end +for i=1, numcards do''' +match_indent = true + +# Poker Hand display can have enhancements +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +pattern = '''local card = Card(0,0, 0.5*G.CARD_W, 0.5*G.CARD_H, G.P_CARDS[v[1]], G.P_CENTERS.c_base)''' +position = "at" +payload = '''local card = Card(0,0, 0.5*G.CARD_W, 0.5*G.CARD_H, G.P_CARDS[v[1]], G.P_CENTERS[v[3] or 'c_base'])''' +match_indent = true + +# Adds G.GAME.modifiers.cry_forced_draw_amount +[[patches]] +[patches.pattern] +target = "functions/state_events.lua" +pattern = "if G.GAME.blind.name == 'The Serpent' and" +position = "before" +payload = ''' +if G.GAME.modifiers.cry_forced_draw_amount and (G.GAME.current_round.hands_played > 0 or G.GAME.current_round.discards_used > 0) then + hand_space = math.min(#G.deck.cards, G.GAME.modifiers.cry_forced_draw_amount) +end +''' +match_indent = true + +# adds oldbp blueprint corruption +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = 'if _pool_size == 0 then' +position = "before" +payload = ''' +if G.GAME.oldbpfactor and G.GAME.oldbpfactor >= 2 then + if _type == 'Joker' and (_rarity == nil or type(_rarity) ~= "string") and not _legendary and not (G.GAME.used_jokers["j_blueprint"] and not next(find_joker("Showman"))) then + for i = 1, math.floor(G.GAME.oldbpfactor - 1) do + _pool[#_pool + 1] = "j_blueprint" + end + end +end +''' +match_indent = true + +# end of shop decrement +[[patches]] +[patches.pattern] +target = "functions/button_callbacks.lua" +pattern = 'G.SHOP_SIGN.alignment.offset.y = -15' +position = "after" +payload = ''' +if G.GAME.oldbpfactor then G.GAME.oldbpfactor = math.max(G.GAME.oldbpfactor - G.GAME.oldbpfactor/8, 1) end +''' +match_indent = true + +# Make Loopy reset here so it retriggers everything before resetting regardless of position +# Makes Old Blueprint self-destruct after triggering other end of round effects +[[patches]] +[patches.pattern] +target = "functions/state_events.lua" +pattern = '''if G.GAME.round_resets.temp_reroll_cost then G.GAME.round_resets.temp_reroll_cost = nil; calculate_reroll_cost(true) end''' +position = "after" +payload = ''' +for _, v in pairs(find_joker("cry-loopy")) do + if v.ability.extra.retrigger ~= 0 then + v.ability.extra.retrigger = 0 + card_eval_status_text(v, 'extra', nil, nil, nil, {message = localize("k_reset"), colour = G.C.GREEN}) + end +end +SMODS.calculate_context{end_of_round2 = true} +''' +match_indent = true + + +# fix crashing from the source +# well, not from the real source, but close enough +[[patches]] +[patches.pattern] +target = "tag.lua" +pattern = '''update_hand_text({sound = 'button', volume = 0.7, pitch = 0.8, delay = 0.3}, {''' +position = "before" +payload = ''' +if (not self.ability.orbital_hand) or (not G.GAME.hands[self.ability.orbital_hand]) then + local _poker_hands = {} + for k, v in pairs(G.GAME.hands) do + if v.visible then _poker_hands[#_poker_hands+1] = k end + end + self.ability.orbital_hand = pseudorandom_element(_poker_hands, pseudoseed('orbital')) +end +''' +match_indent = true + +# kitty printer 2 (for some reason i can't figure out how to not create another object here) +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +pattern = "local _tag = Tag(G.GAME.round_resets.blind_tags[blind_choice], nil, blind_choice)" +position = "after" +payload = ''' +if next(SMODS.find_card('j_cry_kittyprinter')) then + _tag = Tag('tag_cry_cat', nil, blind_choice) +end +''' +match_indent = true + +# avoids a game-locking crash related to opened booster being nil +# remove this as soon as a fix is done +[[patches]] +[patches.pattern] +target = "game.lua" +pattern = "SMODS.OPENED_BOOSTER.config.center:update_pack(dt)" +position = "at" +payload = ''' +if not SMODS.OPENED_BOOSTER then + G.STATE = G.STATES.SHOP + print('Error: SMODS.OPENED_BOOSTER is nil. Game recovered by setting game state to shop.') +else + SMODS.OPENED_BOOSTER.config.center:update_pack(dt) +end +''' +match_indent = true + +# Created cards match suits of suit deck +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = "card.playing_card = G.playing_card" +position = "after" +payload = ''' +if G.GAME.modifiers.cry_force_suit then card:change_suit(G.GAME.modifiers.cry_force_suit) end +if G.GAME.modifiers.cry_force_enhancement then card:set_ability(G.P_CENTERS[G.GAME.modifiers.cry_force_enhancement]) end +if G.GAME.modifiers.cry_force_edition then card:set_edition({[G.GAME.modifiers.cry_force_edition]=true},true,true) end +if G.GAME.modifiers.cry_force_seal then card:set_seal(G.GAME.modifiers.cry_force_seal) end +''' +match_indent = true + +# Remove G.cry_edeck_select on back +[[patches]] +[patches.pattern] +target = "functions/button_callbacks.lua" +pattern = "G.FUNCS.setup_run = function(e)" +position = "after" +payload = ''' + G.cry_edeck_select = nil +''' +match_indent = true + +# Remove G.cry_edeck_select on escape key press +[[patches]] +[patches.pattern] +target = "engine/controller.lua" +pattern = '''if key == "escape" then''' +position = "after" +payload = ''' + G.cry_edeck_select = nil +''' +match_indent = true +# Make vanilla edition tags Nope! if all jokers in shop have editions +[[patches]] +[patches.pattern] +target = "tag.lua" +pattern = "local _applied = nil" +position = "after" +payload = ''' +if Cryptid.forced_edition() then self:nope() end +''' +match_indent = true diff --git a/Cryptid/lovely/misc_joker.toml b/Cryptid/lovely/misc_joker.toml new file mode 100644 index 0000000..f159ee6 --- /dev/null +++ b/Cryptid/lovely/misc_joker.toml @@ -0,0 +1,22 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = -1 + +# LeBaron James - Calculate Steel effects when played +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = "if context.cardarea == G.hand and context.main_scoring then" +position = "at" +payload = "if (context.cardarea == G.hand or context.cardarea == G.play and next(SMODS.find_card('j_cry_lebaron_james')) and Cryptid.safe_get(SMODS.Ranks,Cryptid.safe_get(card,'base','value') or 'm','key') == 'King') and context.main_scoring then" +match_indent = true + +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = "ret.playing_card = {}" +position = "at" +payload = "ret.playing_card = ret.playing_card or {}" +match_indent = true + diff --git a/Cryptid/lovely/misprint.toml b/Cryptid/lovely/misprint.toml new file mode 100644 index 0000000..2edca00 --- /dev/null +++ b/Cryptid/lovely/misprint.toml @@ -0,0 +1,504 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = -1 + +# Randomize poker hands after RNG is set up +[[patches]] +[patches.pattern] +target = "game.lua" +pattern = "self.GAME.pseudorandom.hashed_seed = pseudohash(self.GAME.pseudorandom.seed)" +position = "after" +payload = ''' +if G.GAME.modifiers.cry_misprint_min and not args.savetext then + for k, v in pairs(G.GAME.hands) do + v.chips = to_big(cry_format(v.chips * Cryptid.log_random(pseudoseed('cry_misprint'),G.GAME.modifiers.cry_misprint_min,G.GAME.modifiers.cry_misprint_max),"%.2g")) + v.mult = to_big(cry_format(v.mult * Cryptid.log_random(pseudoseed('cry_misprint'),G.GAME.modifiers.cry_misprint_min,G.GAME.modifiers.cry_misprint_max),"%.2g")) + v.l_chips = cry_format(v.l_chips * Cryptid.log_random(pseudoseed('cry_misprint'),G.GAME.modifiers.cry_misprint_min,G.GAME.modifiers.cry_misprint_max),"%.2g") + v.l_mult = cry_format(v.l_mult * Cryptid.log_random(pseudoseed('cry_misprint'),G.GAME.modifiers.cry_misprint_min,G.GAME.modifiers.cry_misprint_max),"%.2g") + v.s_chips = v.chips + v.s_mult = v.mult + end +end +''' +match_indent = true + +# Packs +[[patches]] +[patches.pattern] +target = "game.lua" +pattern = "create_shop_card_ui(card, 'Booster', G.shop_booster)" +position = "before" +payload = ''' +Cryptid.misprintize(card) +''' +match_indent = true + +# Prevent pack softlocks +# Off by One Error effect +# Booster Tag effect +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "G.GAME.pack_choices = self.ability.choose or self.config.center.config.choose or 1" +position = "after" +payload = ''' +G.GAME.pack_choices = ((self.ability.choose and self.ability.extra) and math.min(math.floor(self.ability.extra), self.ability.choose)) or 1 +if G.GAME.modifiers.cry_misprint_min then + G.GAME.pack_size = self.ability.extra + if G.GAME.pack_size < 1 then G.GAME.pack_size = 1 end + self.ability.extra = G.GAME.pack_size + G.GAME.pack_choices = math.min(math.floor(G.GAME.pack_size), self.ability.choose) + --G.GAME.pack_choices = math.min(math.floor(G.GAME.pack_size),cry_format(G.GAME.pack_choices * Cryptid.log_random(pseudoseed('cry_misprint_p'..G.GAME.round_resets.ante),G.GAME.modifiers.cry_misprint_min,G.GAME.modifiers.cry_misprint_max),"%.2f")) +end +if G.GAME.cry_oboe then + self.ability.extra = self.ability.extra + G.GAME.cry_oboe + G.GAME.pack_choices = G.GAME.pack_choices + G.GAME.cry_oboe + G.GAME.cry_oboe = nil +end +if G.GAME.boostertag and G.GAME.boostertag > 0 then + self.ability.extra = self.ability.extra * 2 + G.GAME.pack_choices = G.GAME.pack_choices * 2 + G.GAME.boostertag = math.max(0, G.GAME.boostertag - 1) +end +self.ability.extra = math.min(self.ability.extra, 1000) +G.GAME.pack_choices = math.min(G.GAME.pack_choices, 1000) +G.GAME.pack_size = self.ability.extra +''' +match_indent = true + +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "if self.ability.name:find('Arcana') then" +position = "before" +payload = ''' +if self.ability.extra < 1 then self.ability.extra = 1 end +''' +match_indent = true + +# Vouchers +[[patches]] +[patches.pattern] +target = '''=[SMODS _ "src/utils.lua"]''' +pattern = "create_shop_card_ui(card, 'Voucher', G.shop_vouchers)" +position = "before" +payload = ''' +Cryptid.misprintize(card) +if G.GAME.events.ev_cry_choco2 then + card.misprint_cost_fac = (card.misprint_cost_fac or 1) * 2 + card:set_cost() +end +''' +match_indent = true + +[[patches]] +[patches.pattern] +target = "tag.lua" +pattern = "create_shop_card_ui(card, 'Voucher', G.shop_vouchers)" +position = "before" +payload = ''' +Cryptid.misprintize(card) +if G.GAME.events.ev_cry_choco2 then + card.misprint_cost_fac = (card.misprint_cost_fac or 1) * 2 + card:set_cost() +end +''' +match_indent = true + +# Fractional Ante Bugs +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = "G.GAME.round_resets.ante = G.GAME.round_resets.ante + mod" +position = "after" +payload = "G.GAME.round_resets.ante = Big and (to_number(math.floor(to_big(G.GAME.round_resets.ante)))) or math.floor(G.GAME.round_resets.ante)" +match_indent = true + +# UI Bugs +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +pattern = "_size*G.CARD_W," +position = "at" +payload = "math.max(1,math.min(_size,5))*G.CARD_W," +match_indent = true + +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +pattern = "_size*G.CARD_W*1.1," +position = "at" +payload = "math.max(1,math.min(_size,5))*G.CARD_W*1.1," +match_indent = true + +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +pattern = "_size*G.CARD_W*1.1 + 0.5," +position = "at" +payload = "math.max(1,math.min(_size,5))*G.CARD_W*1.1 + 0.5," +match_indent = true + +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +pattern = "{card_limit = _size, type = 'consumeable', highlight_limit = 1})" +position = "at" +payload = "{card_limit = math.max(1,_size), type = 'consumeable', highlight_limit = 1})" +match_indent = true + +# Death and a CCD Patch +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "if self.ability.consumeable.mod_num >= #G.hand.highlighted and #G.hand.highlighted >= (self.ability.consumeable.min_highlighted or 1) then" +position = "at" +payload = "if (self.ability.consumeable.mod_num - ((G.GAME.modifiers.cry_consumable_reduce and (self.ability.name ~= 'Death')) and (self.ability.consumeable.mod_num > 1) and 1 or 0)) >= #G.hand.highlighted + (self.area == G.hand and -1 or 0) and #G.hand.highlighted + (self.area == G.hand and -1 or 0) >= 1 then" +match_indent = true + +# mod_num has no limit +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "self.ability.consumeable.mod_num = math.min(5, self.ability.consumeable.max_highlighted)" +position = "at" +payload = "self.ability.consumeable.mod_num = self.ability.consumeable.max_highlighted" +match_indent = true + +# Infinite Deck +[[patches]] +[patches.pattern] +target = "cardarea.lua" +pattern = "self.config.highlighted_limit = config.highlight_limit or 5" +position = "at" +payload = "self.config.highlighted_limit = config.highlight_limit or G.GAME.modifiers.cry_highlight_limit or 5" +match_indent = true + +[[patches]] +[patches.pattern] +target = "functions/button_callbacks.lua" +pattern = "if #G.hand.highlighted <= 0 or G.GAME.blind.block_play or #G.hand.highlighted > 5 then" +position = "at" +payload = "if #G.hand.highlighted <= (G.GAME.stamp_mod and 1 or 0) or G.GAME.blind.block_play then" +match_indent = true + +# Hieroglyph +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "ease_ante(-center_table.extra)" +position = "at" +payload = "ease_ante(math.floor(-center_table.extra))" +match_indent = true + +# Get Cryptid to display and work with card selections +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = "elseif _c.name == 'Cryptid' then loc_vars = {cfg.extra}" +position = "at" +payload = '''elseif _c.name == 'Cryptid' then loc_vars = {cfg.extra, cfg.max_highlighted} +''' +match_indent = true + +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = 'local _card = copy_card(G.hand.highlighted[1], nil, nil, G.playing_card)' +position = "at" +payload = ''' +for q = 1, #G.hand.highlighted do +local _card = copy_card(G.hand.highlighted[q], nil, nil, G.playing_card) +''' +match_indent = true + +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "new_cards[#new_cards+1] = _card" +position = "after" +payload = "end" +match_indent = true + +# Get seal spectrals to display and work with card selections +[[patches]] +[patches.regex] +target = "functions/common_events.lua" +pattern = ''' +(?[\t ]*)elseif _c\.set == 'Spectral' then ''' +position = 'after' +# match_indent = true +line_prepend = '$indent ' +payload = ''' + +if _c.name == 'Talisman' or _c.name == 'Medium' or _c.name == 'Trance' or _c.name == 'Deja Vu' then + loc_vars = {cfg.max_highlighted} +end +''' + +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = 'local conv_card = G.hand.highlighted[1]' +position = "at" +payload = ''' +for q = 1, #G.hand.highlighted do +local conv_card = G.hand.highlighted[q] +G.E_MANAGER:add_event(Event({func = function() + play_sound('tarot1') + used_tarot:juice_up(0.3, 0.5) + return true end })) + +G.E_MANAGER:add_event(Event({trigger = 'after',delay = 0.1,func = function() + conv_card:set_seal(self.ability.extra, nil, true) + return true end })) +end +delay(0.5) +G.E_MANAGER:add_event(Event({trigger = 'after', delay = 0.2,func = function() G.hand:unhighlight_all(); return true end })) +end--[[ +''' +match_indent = true + +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "if self.ability.name == 'Aura' then" +position = "before" +payload = "--]]" +match_indent = true + +# Fractional pricing +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "self.cost = math.max(1, math.floor((self.base_cost + self.extra_cost + 0.5)*(100-G.GAME.discount_percent)/100))" +position = "after" +payload = ''' + if self.ability.set == 'Joker' then + self.cost = cry_format(self.cost * G.GAME.cry_shop_joker_price_modifier,'%.2f') end + if self.misprint_cost_fac then + self.cost = cry_format(self.cost * self.misprint_cost_fac,'%.2f') + if not G.GAME.modifiers.cry_misprint_min then self.cost = math.floor(self.cost) end end +''' +match_indent = true + +# the d in disp stands for disparity (match internal values to display values) +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "function Card:apply_to_run(center)" +position = "after" +payload = ''' +if (self and self.ability and self.ability.extra_disp) then -- redeeming through centers isn't misprinted + local self_disp = self.ability.extra_disp + local orig_disp = self.config.center.config.extra_disp + local self_extra = self.ability.extra + local orig_extra = self.config.center.config.extra + + local new_fac = self_disp / orig_disp + self.ability.extra = new_fac*orig_extra +end +''' +match_indent = true + +# I LOVE HARDCODING +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "G.hand:change_size(1)" +position = "at" +payload = ''' +G.hand:change_size(center_table.extra) +''' +match_indent = true + +# YOU LOVE HARDCODING +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "change_shop_size(1)" +position = "at" +payload = ''' +change_shop_size(center_table.extra) +''' +match_indent = true + +# WE ALL LOVE HARDCODING +[[patches]] +[patches.regex] +target = "card.lua" +pattern = '''if center_table\.name \=\= 'Antimatter' then\n\s+G\.E_MANAGER\:add_event\(Event\(\{func = function\(\)\n\s+if G\.jokers then \n\s+G\.jokers\.config\.card_limit \= G\.jokers\.config\.card_limit \+ 1\n\s+end\n\s+return true end \}\)\)\n\s+end''' +position = "at" +payload = ''' + if center_table.name == 'Antimatter' then + G.E_MANAGER:add_event(Event({func = function() + if G.jokers then + G.jokers.config.card_limit = G.jokers.config.card_limit + center_table.extra + end + return true end })) + end +''' + +# AAAA +[[patches]] +[patches.regex] +target = "card.lua" +pattern = '''if center_table\.name \=\= 'Crystal Ball' then\n\s+G\.E_MANAGER:add_event\(Event\(\{func \= function\(\)\n\s+G\.consumeables\.config\.card_limit \= G.consumeables\.config\.card_limit \+ 1\n\s+return true end }\)\)\n\s+end''' +position = "at" +payload = ''' + if center_table.name == 'Crystal Ball' then + G.E_MANAGER:add_event(Event({func = function() + G.consumeables.config.card_limit = G.consumeables.config.card_limit + center_table.extra + return true end })) + end +''' + +# anyway how's your day going? +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = '''elseif _c.name == "Clearance Sale" or _c.name == "Liquidation" then loc_vars = {cfg.extra}''' +position = "after" +payload = ''' +elseif _c.name == "Crystal Ball" or _c.name == "Omen Globe" then loc_vars = {cfg.extra} +''' +match_indent = true + +# doing pretty good myself +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = '''if _c.name == "Overstock" or _c.name == 'Overstock Plus' then''' +position = "at" +payload = ''' +if _c.name == "Overstock" or _c.name == "Overstock Plus" then loc_vars = {cfg.extra} +''' +match_indent = true + +# spent the whole day reviving misprinted vouchers +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = '''elseif _c.name == "Blank" or _c.name == "Antimatter" then''' +position = "at" +payload = ''' +elseif _c.name == "Blank" or _c.name == "Antimatter" then loc_vars = {cfg.extra} +''' +match_indent = true + +# but whatever, not like i was doing anything anyway +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +pattern = '''UIBox_button({label = {localize('b_reroll_boss'), localize('$')..'10'}, button = "reroll_boss", func = 'reroll_boss_button'}) or nil''' +position = "at" +payload = ''' +UIBox_button({label = {localize('b_reroll_boss'), localize('$')..Cryptid.cheapest_boss_reroll()}, button = "reroll_boss", func = 'reroll_boss_button'}) or nil +''' +match_indent = true + +# worth it in the end ig, it was bugging me +[[patches]] +[patches.pattern] +target = "functions/button_callbacks.lua" +pattern = '''if ((G.GAME.dollars-G.GAME.bankrupt_at) - 10 >= 0) and''' +position = "at" +payload = ''' +if ((to_big(G.GAME.dollars)-to_big(G.GAME.bankrupt_at)) - to_big(Cryptid.cheapest_boss_reroll()) >= to_big(0)) and +''' +match_indent = true + +# see you around +[[patches]] +[patches.pattern] +target = "functions/button_callbacks.lua" +pattern = '''if not G.from_boss_tag then ease_dollars(-10) end''' +position = "at" +payload = ''' +if not G.from_boss_tag then ease_dollars(-Cryptid.cheapest_boss_reroll()) end +''' +match_indent = true + +# hi i'm back and i'm fixing this thing that breaks sometimes for no reason (it really shouldn't) +[[patches]] +[patches.pattern] +target = "game.lua" +pattern = '''v_overstock_norm = {order = 1, discovered = false, unlocked = true , available = true, cost = 10, name = "Overstock", pos = {x=0,y=0}, set = "Voucher", config = {}},''' +position = "at" +payload = ''' +v_overstock_norm = {order = 1, discovered = false, unlocked = true , available = true, cost = 10, name = "Overstock", pos = {x=0,y=0}, set = "Voucher", config = {extra = 1}}, +''' +match_indent = true + +[[patches]] +[patches.pattern] +target = "game.lua" +pattern = '''v_crystal_ball= {order = 9, discovered = false, unlocked = true , available = true, cost = 10, name = "Crystal Ball", pos = {x=2,y=2}, set = "Voucher", config = {extra = 3}},''' +position = "at" +payload = ''' +v_crystal_ball= {order = 9, discovered = false, unlocked = true , available = true, cost = 10, name = "Crystal Ball", pos = {x=2,y=2}, set = "Voucher", config = {extra = 1}}, +''' +match_indent = true + +[[patches]] +[patches.pattern] +target = "game.lua" +pattern = '''v_overstock_plus= {order = 2, discovered = false, unlocked = false, available = true, cost = 10, name = "Overstock Plus", pos = {x=0,y=1}, set = "Voucher", config = {}, requires = {'v_overstock_norm'},unlock_condition = {type = 'c_shop_dollars_spent', extra = 2500}},''' +position = "at" +payload = ''' +v_overstock_plus= {order = 2, discovered = false, unlocked = false, available = true, cost = 10, name = "Overstock Plus", pos = {x=0,y=1}, set = "Voucher", config = {extra = 1}, requires = {'v_overstock_norm'},unlock_condition = {type = 'c_shop_dollars_spent', extra = 2500}}, +''' +match_indent = true + +[[patches]] +[patches.pattern] +target = "game.lua" +pattern = '''v_antimatter= {order = 24, discovered = false, unlocked = false, available = true, cost = 10, name = "Antimatter", pos = {x=7,y=1}, set = "Voucher", config = {extra = 15}, requires = {'v_blank'},unlock_condition = {type = 'blank_redeems', extra = 10}},''' +position = "at" +payload = ''' +v_antimatter= {order = 24, discovered = false, unlocked = false, available = true, cost = 10, name = "Antimatter", pos = {x=7,y=1}, set = "Voucher", config = {extra = 1}, requires = {'v_blank'},unlock_condition = {type = 'blank_redeems', extra = 10}}, +''' +match_indent = true + +# whyyyyyyyyy +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = '''G.GAME.tarot_rate = 4*center_table.extra''' +position = "at" +payload = ''' +G.GAME.tarot_rate = G.GAME.tarot_rate*center_table.extra +''' +match_indent = true + +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = '''G.GAME.planet_rate = 4*center_table.extra''' +position = "at" +payload = ''' +G.GAME.planet_rate = G.GAME.planet_rate*center_table.extra +''' +match_indent = true + +# keep vanilla rates by modifying tycoons +[[patches]] +[patches.pattern] +target = "game.lua" +pattern = '''v_tarot_tycoon= {order = 18, discovered = false, unlocked = false, available = true,cost = 10, name = "Tarot Tycoon", pos = {x=1,y=1}, set = "Voucher", config = {extra = 32/4, extra_disp = 4}, requires = {'v_tarot_merchant'},unlock_condition = {type = 'c_tarots_bought', extra = 50}},''' +position = "at" +payload = ''' +v_tarot_tycoon= {order = 18, discovered = false, unlocked = false, available = true,cost = 10, name = "Tarot Tycoon", pos = {x=1,y=1}, set = "Voucher", config = {extra = 32/9.6, extra_disp = 4}, requires = {'v_tarot_merchant'},unlock_condition = {type = 'c_tarots_bought', extra = 50}}, +''' +match_indent = true + +[[patches]] +[patches.pattern] +target = "game.lua" +pattern = '''v_planet_tycoon= {order = 20, discovered = false, unlocked = false, available = true,cost = 10, name = "Planet Tycoon", pos = {x=2,y=1}, set = "Voucher", config = {extra = 32/4, extra_disp = 4}, requires = {'v_planet_merchant'},unlock_condition = {type = 'c_planets_bought', extra = 50}},''' +position = "at" +payload = ''' +v_planet_tycoon= {order = 20, discovered = false, unlocked = false, available = true,cost = 10, name = "Planet Tycoon", pos = {x=2,y=1}, set = "Voucher", config = {extra = 32/9.6, extra_disp = 4}, requires = {'v_planet_merchant'},unlock_condition = {type = 'c_planets_bought', extra = 50}}, +''' +match_indent = true diff --git a/Cryptid/lovely/planet.toml b/Cryptid/lovely/planet.toml new file mode 100644 index 0000000..8b26260 --- /dev/null +++ b/Cryptid/lovely/planet.toml @@ -0,0 +1,27 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = -1 + +# Lapio softlock mechanic +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = "if (not v.config.softlock or G.GAME.hands[v.config.hand_type].played > 0) then" +position = "at" +payload = ''' +local softlocked = true +if not v.config.softlock then + softlocked = false +elseif v.config.hand_type then + softlocked = G.GAME.hands[v.config.hand_type].played == 0 +elseif v.config.hand_types then + for _, h in pairs(v.config.hand_types) do + if G.GAME.hands[h].played > 0 then + softlocked = false + end + end +end +if not softlocked then +''' +match_indent = true \ No newline at end of file diff --git a/Cryptid/lovely/seal.toml b/Cryptid/lovely/seal.toml new file mode 100644 index 0000000..eed6ca9 --- /dev/null +++ b/Cryptid/lovely/seal.toml @@ -0,0 +1,20 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = 10 + + +# Call Card:calculate_seal() with destroying_card context +[[patches]] +[patches.regex] +target = "functions/state_events.lua" +pattern = '(?[\t ]*)if destroyed then \n' +position = 'before' +line_prepend = '$indent' +payload = ''' +if scoring_hand[i]:calculate_seal({destroying_card = scoring_hand[i], full_hand = G.play.cards}) and not scoring_hand[i].ability.eternal then + destroyed = true +end + +''' + diff --git a/Cryptid/lovely/spooky.toml b/Cryptid/lovely/spooky.toml new file mode 100644 index 0000000..c01bbc0 --- /dev/null +++ b/Cryptid/lovely/spooky.toml @@ -0,0 +1,60 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = 10 + +# Haunted House - useless skips +[[patches]] +[patches.regex] +target = "functions/button_callbacks.lua" +pattern = 'if _tag then' +position = 'at' +line_prepend = '$indent' +payload = '''if _tag and not G.GAME.events.ev_cry_choco2 then''' + +# Please Take One jank +[[patches]] +[patches.pattern] +target = "game.lua" +pattern = '''ease_background_colour_blind(G.STATES.ROUND_EVAL)''' +position = "after" +payload = '''if G.GAME.events.ev_cry_choco6 and G.round_eval then return true end''' +match_indent = true + +# Revered Antique - create legendary +[[patches]] +[patches.pattern] +target = "game.lua" +pattern = '''if G.load_shop_booster then''' +position = "before" +payload = ''' +if G.GAME.events.ev_cry_choco10 then + local add = true + for k, v in pairs(G.shop_vouchers.cards) do -- G.load_shop_vouchers is already set to nil here, just do a normal check + if v.ability.cry_antique then add = false end + end + if add then + local card = create_card('Joker', G.jokers, true, nil, nil, nil, nil, 'cry_antique') + Cryptid.misprintize(card) + card.misprint_cost_fac = 50/card.cost + card:set_cost() + create_shop_card_ui(card, 'Voucher', G.shop_vouchers) + card:start_materialize() + card.ability.cry_antique = true + G.shop_vouchers.config.card_limit = G.shop_vouchers.config.card_limit + 1 + G.shop_vouchers:emplace(card) + end +end +''' +match_indent = true + +# hackfix for flickering thing +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = '''if not card then''' +position = "at" +payload = ''' +if cfg and not card then +''' +match_indent = true \ No newline at end of file diff --git a/Cryptid/lovely/stake.toml b/Cryptid/lovely/stake.toml new file mode 100644 index 0000000..c80ca04 --- /dev/null +++ b/Cryptid/lovely/stake.toml @@ -0,0 +1,476 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = -1 + + +# Yellow Stake - perishable and rental effects on consumable +[[patches]] +[patches.pattern] +target = "functions/state_events.lua" +pattern = "if G.GAME.round_resets.ante == G.GAME.win_ante and G.GAME.blind:get_type() == 'Boss' then" +position = "before" +payload = ''' +local i = 1 +while i <= #G.jokers.cards do + local gone = G.jokers.cards[i]:calculate_banana() + if not gone then i = i + 1 end +end +''' +match_indent = true + +# Yellow Stake - perishable and rental effects on cards held in hand +[[patches]] +[patches.pattern] +target = "functions/state_events.lua" +pattern = "local effects = {[1] = {playing_card = G.hand.cards[i]:get_end_of_round_effect()}}" +position = "after" +payload = ''' +-- these are already calculated +-- does mean this patch is pointless now, but i want to leave it here just so it's clear, maybe remove later +-- G.hand.cards[i]:calculate_rental() +-- G.hand.cards[i]:calculate_perishable() +''' +match_indent = true + +# Yellow Stake - perishable and rental effects on cards in deck and discard pile +# Double Down +[[patches]] +[patches.pattern] +target = "functions/state_events.lua" +pattern = "G.FUNCS.draw_from_hand_to_discard()" +position = "before" +payload = ''' +local i = 1 +while i <= #G.hand.cards do + local gone = G.hand.cards[i]:calculate_banana() + if not gone then i = i + 1 end +end +for i = 1, #G.discard.cards do + G.discard.cards[i]:calculate_perishable() +end +i = 1 +while i <= #G.deck.cards do + G.deck.cards[i]:calculate_perishable() + local gone = G.deck.cards[i]:calculate_banana() + if not gone then i = i + 1 end +end +if G.GAME.used_vouchers.v_cry_double_down then + local function update_dbl(area) + for i = 1, #area.cards do + if area.cards[i].dbl_side then + --tweak to do deck effects with on the flip side + Cryptid.misprintize(area.cards[i].dbl_side, {min = 1.5, max = 1.5}, nil, true) + card_eval_status_text(area.cards[i], "extra", nil, nil, nil, { message = localize("k_upgrade_ex") }) + end + end + end + update_dbl(G.jokers) + update_dbl(G.consumeables) + update_dbl(G.hand) + update_dbl(G.discard) + update_dbl(G.deck) +end +''' +match_indent = true + +# Yellow Stake - Hanged Man can't be used on Eternal cards, Death can't remove Eternal +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "if self.ability.name == 'The Hermit' or self.ability.consumeable.hand_type or self.ability.name == 'Temperance' or self.ability.name == 'Black Hole' then" +position = "before" +payload = ''' +if self.ability.name == "The Hanged Man" then + for i = 1, #G.hand.highlighted do + if G.hand.highlighted[i].ability.eternal then return false end + end +end +if self.ability.name == "Death" then + local rightmost = G.hand.highlighted[1] + for i=1, #G.hand.highlighted-1 do if G.hand.highlighted[i].T.x > rightmost.T.x then rightmost = G.hand.highlighted[i] end end + for i=1, #G.hand.highlighted do if G.hand.highlighted[i].ability.eternal and rightmost ~= G.hand.highlighted[i] then return false end end +end +''' +match_indent = true + + +# Yellow Stake - Immolate can't be used on Eternal cards +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "for k, v in ipairs(G.hand.cards) do temp_hand[#temp_hand+1] = v end" +position = "at" +payload = ''' +for k, v in ipairs(G.hand.cards) do + if not v.ability.eternal then + temp_hand[#temp_hand+1] = v + end +end +''' +match_indent = true + + +# Yellow Stake - Death can't modify Eternal cards (redundant, but may help if Death can be used on more cards) +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "if G.hand.highlighted[i] ~= rightmost then" +position = "at" +payload = "if G.hand.highlighted[i] ~= rightmost and not G.hand.highlighted[i].ability.eternal then" +match_indent = true + + +# Yellow Stake - Trading Card can't destroy Eternals +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "G.GAME.current_round.discards_used <= 0 and #context.full_hand == 1 then" +position = "at" +payload = "G.GAME.current_round.discards_used <= 0 and #context.full_hand == 1 and not context.other_card.ability.eternal then" +match_indent = true + + +# Yellow Stake - Sixth Sense can't destroy Eternals +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "if self.ability.name == 'Sixth Sense' and #context.full_hand == 1 and context.full_hand[1]:get_id() == 6 and G.GAME.current_round.hands_played == 0 then" +position = "at" +payload = "if self.ability.name == 'Sixth Sense' and #context.full_hand == 1 and context.full_hand[1]:get_id() == 6 and not context.full_hand[1].ability.eternal and G.GAME.current_round.hands_played == 0 then" +match_indent = true + + +# Yellow Stake - enhancement tarots don't remove stickers +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "perma_bonus = self.ability and self.ability.perma_bonus or 0," +position = "after" +payload = ''' +eternal = self.ability and self.ability.eternal, +perishable = self.ability and self.ability.perishable, +perish_tally = self.ability and self.ability.perish_tally, +rental = self.ability and self.ability.rental, +''' +match_indent = true + + +# Amber Stake - edit number of booster packs +[[patches]] +[patches.pattern] +target = "game.lua" +pattern = "for i = 1, 2 do" +position = "at" +payload = "for i = 1, G.GAME.modifiers.cry_no_boosters and 0 or G.GAME.modifiers.cry_booster_packs or 2 do" +match_indent = true + +# Quartz Stake - pinned effect applies in every type of slot +[[patches]] +[patches.pattern] +target = "cardarea.lua" +pattern = "table.sort(self.cards, function (a, b) return a.T.x + a.T.w/2 < b.T.x + b.T.w/2 end)" +position = "at" +payload = "table.sort(self.cards, function (a, b) return a.T.x + a.T.w/2 - 100*((a.pinned and not a.ignore_pinned) and a.sort_id or 0) < b.T.x + b.T.w/2 - 100*((b.pinned and not b.ignore_pinned) and b.sort_id or 0) end)" +match_indent = true + +# Quartz Stake - render pinned sticker +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "elseif self.sprite_facing == 'back' then" +position = "before" +payload = ''' +if self.pinned then + G.shared_stickers['pinned'].role.draw_major = self + G.shared_stickers['pinned']:draw_shader('dissolve', nil, nil, nil, self.children.center) + G.shared_stickers['pinned']:draw_shader('voucher', nil, self.ARGS.send_to_shader, nil, self.children.center) +end +''' +match_indent = true + + +# Ruby Stake - big blind bosses +[[patches]] +[patches.pattern] +target = "game.lua" +pattern = "self.GAME.round_resets.blind_choices.Boss = get_new_boss()" +position = "before" +payload = ''' +if G.GAME.modifiers.cry_big_boss_rate and pseudorandom('cry_big_boss') < G.GAME.modifiers.cry_big_boss_rate then + self.GAME.round_resets.blind_choices.Big = get_new_boss() +elseif G.GAME.modifiers.cry_rush_hour_ii then + self.GAME.round_resets.blind_choices.Small = get_new_boss() + self.GAME.round_resets.blind_choices.Big = get_new_boss() +else + self.GAME.round_resets.blind_choices.Big = 'bl_big' +end +''' +match_indent = true + + +# Ruby Stake - big blind bosses +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = "G.GAME.round_resets.blind_choices.Boss = get_new_boss()" +position = "before" +payload = ''' +if G.GAME.modifiers.cry_big_boss_rate and pseudorandom('cry_big_boss') < G.GAME.modifiers.cry_big_boss_rate then + G.GAME.round_resets.blind_choices.Big = get_new_boss() +elseif G.GAME.modifiers.cry_rush_hour_ii then + G.GAME.round_resets.blind_choices.Small = get_new_boss() + G.GAME.round_resets.blind_choices.Big = get_new_boss() +else + G.GAME.round_resets.blind_choices.Big = 'bl_big' +end +''' +match_indent = true + + +# Ruby Stake - big blind doesn't increase ante +[[patches]] +[patches.pattern] +target = "functions/state_events.lua" +pattern = "if G.GAME.blind:get_type() == 'Boss' then" +position = "at" +payload = "if G.GAME.blind_on_deck == 'Boss' then" +match_indent = true + +# Ruby Stake - smaller showdown blinds don't win +# Win on any ante above win_ante +[[patches]] +[patches.pattern] +target = "functions/state_events.lua" +pattern = "if G.GAME.round_resets.ante == G.GAME.win_ante and G.GAME.blind:get_type() == 'Boss' then" +position = "at" +payload = "if G.GAME.round_resets.ante >= G.GAME.win_ante and G.GAME.blind_on_deck == 'Boss' then" +match_indent = true + + +# Rush Hour - mark small blind as defeated +[[patches]] +[patches.pattern] +target = "functions/state_events.lua" +pattern = "if G.GAME.round_resets.blind == G.P_BLINDS.bl_small then" +position = "at" +payload = "if G.GAME.blind_on_deck == 'Small' then" +match_indent = true + +# Ruby Stake - mark big blind as defeated +[[patches]] +[patches.pattern] +target = "functions/state_events.lua" +pattern = "elseif G.GAME.round_resets.blind == G.P_BLINDS.bl_big then" +position = "at" +payload = "elseif G.GAME.blind_on_deck == 'Big' then" +match_indent = true + + +# Sapphire Stake - ante tax +# The Joke boss effect +# Save game state for Revert +[[patches]] +[patches.pattern] +target = "functions/state_events.lua" +pattern = "delay(0.4); ease_ante(1); delay(0.4); check_for_unlock({type = 'ante_up', ante = G.GAME.round_resets.ante + 1})" +position = "at" +payload = "delay(0.4); ease_ante(G.GAME.blind and G.GAME.blind:cry_calc_ante_gain() or 1); Cryptid.apply_ante_tax(); delay(0.4); check_for_unlock({type = 'ante_up', ante = G.GAME.round_resets.ante + 1})" +match_indent = true + + +# Emerald Stake - Permanently flipped cards +[[patches]] +[patches.pattern] +target = "cardarea.lua" +pattern = "if card.facing == 'back' and self.config.type ~= 'discard' and self.config.type ~= 'deck' and not stay_flipped then" +position = "at" +payload = '''if card.cry_flipped then card.facing = 'back'; card.sprite_facing = 'back' end +if not (card.cry_flipped and (self == G.shop_jokers or self == G.shop_vouchers or self == G.shop_booster)) and card.facing == 'back' and self.config.type ~= 'discard' and self.config.type ~= 'deck' and not stay_flipped then''' +match_indent = true + + +# Emerald Stake - flipped packs +[[patches]] +[patches.pattern] +target = "game.lua" +pattern = "create_shop_card_ui(card, 'Booster', G.shop_booster)" +position = "before" +payload = ''' +if G.GAME.modifiers.cry_enable_flipped_in_shop and pseudorandom('cry_flip_pack'..G.GAME.round_resets.ante) > 0.7 then + card.cry_flipped = true +end''' +match_indent = true + + +# Emerald Stake - flipped vouchers +[[patches]] +[patches.pattern] +target = "game.lua" +pattern = "create_shop_card_ui(card, 'Voucher', G.shop_vouchers)" +position = "before" +payload = ''' +if G.GAME.modifiers.cry_enable_flipped_in_shop and pseudorandom('cry_flip_vouch'..G.GAME.round_resets.ante) > 0.7 then + card.cry_flipped = true +end''' +match_indent = true + + +# Platinum Stake - start with big blind ready to be selected +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = "G.GAME.blind_on_deck = 'Small'" +position = "at" +payload = "G.GAME.blind_on_deck = G.GAME.modifiers.cry_no_small_blind and 'Big' or 'Small'" +match_indent = true + + +# Platinum Stake - start with big blind ready to be selected +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +pattern = "G.GAME.blind_on_deck = 'Small'" +position = "at" +payload = "G.GAME.blind_on_deck = G.GAME.modifiers.cry_no_small_blind and 'Big' or 'Small'" +match_indent = true + + +# Platinum Stake - hide Small Blind +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = "G.GAME.round_resets.blind_states.Small = 'Upcoming'" +position = "at" +payload = "G.GAME.round_resets.blind_states.Small = G.GAME.modifiers.cry_no_small_blind and 'Hide' or 'Upcoming'" +match_indent = true + +# Ember Stake - grant no money on sell +# this is NOT ember stake grant no money on sell wtf +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = '''elseif v.boss.showdown and (G.GAME.round_resets.ante)%G.GAME.win_ante == 0 and G.GAME.round_resets.ante >= 2 then''' +position = "at" +payload = '''elseif v.boss.showdown and (((G.GAME.round_resets.ante)%G.GAME.win_ante == 0 and G.GAME.round_resets.ante >= 2) or G.GAME.modifiers.cry_big_showdown ) then''' +match_indent = true + +# Ember Stake - give no money for selling +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = '''ease_dollars(self.sell_cost)''' +position = "at" +payload = '''if (not G.GAME.modifiers.cry_no_sell_value) and self.sell_cost ~= 0 then + ease_dollars(self.sell_cost) +end''' +match_indent = true + +# Ember Stake - don't play coin sound +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = '''play_sound('coin2')''' +position = "at" +payload = '''if (not G.GAME.modifiers.cry_no_sell_value) and self.sell_cost ~= 0 then + play_sound('coin2') +end''' +match_indent = true + +# Ember Stake - red dissolve for swag points +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = '''self:start_dissolve({G.C.GOLD})''' +position = "at" +payload = '''if G.GAME.modifiers.cry_no_sell_value or self.sell_cost == 0 then + self:start_dissolve({G.C.RED}) +else + self:start_dissolve({G.C.GOLD}) +end''' +match_indent = true + +# Ember Stake - remove sell price visually +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = '''self.sell_cost_label = self.facing == 'back' and '?' or self.sell_cost''' +position = "at" +payload = '''self.sell_cost_label = (self.facing == 'back' and '?') or (G.GAME.modifiers.cry_no_sell_value and 0) or self.sell_cost''' +match_indent = true + +# Dawn Stake - change maximum allowed highlights (i have no idea what this code is meant to be doing?? whatever it is, it doesn't seem to be working -toneblock) +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = '''local cfg = (card and card.ability) or _c['config']''' +position = "after" +payload = '''if cfg and G.GAME.modifiers.cry_consumable_reduce and cfg.max_highlighted and (cfg.max_highlighted > 1) then + local new_table = {} + for i0, j0 in pairs(cfg) do + new_table[i0] = j0 + end + new_table.max_highlighted = new_table.max_highlighted - 1 + cfg = new_table +end''' +match_indent = true + +# Horizon Stake - create random card at start of blind +[[patches]] +[patches.pattern] +target = "functions/state_events.lua" +pattern = '''G.GAME.blind:set_blind(G.GAME.round_resets.blind)''' +position = "after" +payload = '''if G.GAME.modifiers.cry_card_each_round then + G.E_MANAGER:add_event(Event({ + func = function() + local front = pseudorandom_element(G.P_CARDS, pseudoseed('cry_horizon')) + G.playing_card = (G.playing_card and G.playing_card + 1) or 1 + local edition = G.P_CENTERS.c_base + local card = Card(G.play.T.x + G.play.T.w/2, G.play.T.y, G.CARD_W, G.CARD_H, front, G.P_CENTERS.c_base, {playing_card = G.playing_card}) + card:start_materialize() + if G.GAME.selected_back.effect.config.cry_force_edition and G.GAME.selected_back.effect.config.cry_force_edition ~= "random" then + local edition = {} + edition[G.GAME.selected_back.effect.config.cry_force_edition] = true + card:set_edition(edition, true, true); + end + G.play:emplace(card) + table.insert(G.playing_cards, card) + playing_card_joker_effects({true}) + return true + end})) + G.E_MANAGER:add_event(Event({ + func = function() + G.deck.config.card_limit = G.deck.config.card_limit + 1 + return true + end})) + draw_card(G.play,G.deck, 90,'up', nil) +end''' +match_indent = true + +# Blossom Stake - showdown blinds before the winning ante +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = '''elseif v.boss.showdown and (G.GAME.round_resets.ante)%G.GAME.win_ante == 0 and G.GAME.round_resets.ante >= 2 then''' +position = "at" +payload = '''elseif v.boss.showdown and (((G.GAME.round_resets.ante)%G.GAME.win_ante == 0 and G.GAME.round_resets.ante >= 2) or G.GAME.modifiers.cry_big_showdown ) then''' +match_indent = true + +# inject into vanilla calculate_perishable to prevent nil index bug (i don't know where it fails so i'm just patching every part of it...) +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = '''if self.ability.perishable and self.ability.perish_tally > 0 then''' +position = "before" +payload = '''if self.ability.perishable and not self.ability.perish_tally then self.ability.perish_tally = G.GAME.perishable_rounds end''' +match_indent = true + +# again in set_debuff +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = '''if self.ability.perishable and self.ability.perish_tally <= 0 then''' +position = "before" +payload = '''if self.ability.perishable and not self.ability.perish_tally then self.ability.perish_tally = G.GAME.perishable_rounds end''' +match_indent = true diff --git a/Cryptid/lovely/sticker.toml b/Cryptid/lovely/sticker.toml new file mode 100644 index 0000000..06582ae --- /dev/null +++ b/Cryptid/lovely/sticker.toml @@ -0,0 +1,156 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = -1 + +# initiate variables +[[patches]] +[patches.pattern] +target = "game.lua" +pattern = "rental_rate = 3," +position = "after" +payload = ''' +cry_voucher_perishable_rounds = 8, +cry_voucher_rental_rate = 2, +cry_consumeable_rental_rate = 2, +cry_voucher_banana_odds = 12, +cry_consumeable_banana_odds = 4, +cry_pinned_consumeables = 0, +cry_shop_joker_price_modifier = 1, +''' +match_indent = true + +# check for pinned +[[patches]] +[patches.pattern] +target = "functions/state_events.lua" +pattern = "G.GAME.current_round.voucher = get_next_voucher_key()" +position = "at" +payload = ''' +if G.GAME.current_round.cry_voucher_stickers.pinned == false then + G.GAME.current_round.voucher = get_next_voucher_key() +end +''' +match_indent = true + +# remove stickers if voucher is redeemed +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "self:apply_to_run()" +position = "before" +payload = ''' +G.GAME.current_round.cry_voucher_edition = nil +G.GAME.current_round.cry_voucher_stickers = {eternal = false, perishable = false, rental = false, pinned = false, banana = false} +''' +match_indent = true + +# consumeable sticker checking +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "local used_tarot = copier or self" +position = "after" +payload = ''' +if self.ability.rental then + G.E_MANAGER:add_event(Event({ + trigger = 'immediate', + blocking = false, + blockable = false, + func = (function() + ease_dollars(-G.GAME.cry_consumeable_rental_rate) + return true + end)})) +end +local gone = false +if self.ability.banana then + if not self.ability.extinct then + if (pseudorandom('oops_it_banana') < G.GAME.probabilities.normal/G.GAME.cry_consumeable_banana_odds) then + local gone = true + self.ability.extinct = true + G.E_MANAGER:add_event(Event({ + func = function() + play_sound('tarot1') + self.T.r = -0.2 + self:juice_up(0.3, 0.4) + self.states.drag.is = true + self.children.center.pinch.x = true + G.E_MANAGER:add_event(Event({trigger = 'after', delay = 0.3, blockable = false, + func = function() + if self.area then self.area:remove_card(self) end + self:remove() + self = nil + return true; end})) + return true + end + })) + card_eval_status_text(self, 'jokers', nil, nil, nil, {message = localize('k_extinct_ex'), delay = 0.1}) + return true + end + end +end +if gone == false then +''' +match_indent = true + +# end the wrap +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "function Card:can_use_consumeable(any_state, skip_check)" +position = "before" +payload = ''' +end +''' +match_indent = true + +# check for pinned +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "if G.STATE ~= G.STATES.HAND_PLAYED and G.STATE ~= G.STATES.DRAW_TO_HAND and G.STATE ~= G.STATES.PLAY_TAROT or any_state then" +position = "before" +payload = ''' +if G.GAME.cry_pinned_consumeables > 0 and not self.pinned then + return false +end +''' +match_indent = true + +# pinned consumeable remove, counterpart is in cryptid's create_card +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "if self.ability.queue_negative_removal then" +position = "before" +payload = ''' +if self.ability.consumeable and self.pinned and (G.GAME.cry_pinned_consumeables > 0) then + G.GAME.cry_pinned_consumeables = G.GAME.cry_pinned_consumeables - 1 +end +''' +match_indent = true + +# rental jank +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "if self.ability.rental then self.cost = 1 end" +position = "at" +payload = ''' +if self.ability.rental and (not (self.ability.set == "Planet" and #find_joker('Astronomer') > 0) and self.ability.set ~= "Booster") then self.cost = 1 end +''' +match_indent = true + +# apply stickers to packs +[[patches]] +[patches.pattern] +target = "game.lua" +pattern = "card.ability.booster_pos = i" +position = "before" +payload = ''' +local stickers = Cryptid.next_voucher_stickers(true) -- don't mind the name +for k, v in pairs(stickers) do + card.ability[k] = v +end +''' +match_indent = true diff --git a/Cryptid/lovely/universum.toml b/Cryptid/lovely/universum.toml new file mode 100644 index 0000000..45c7f6c --- /dev/null +++ b/Cryptid/lovely/universum.toml @@ -0,0 +1,44 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = -1 + +# Level up modifier +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = "amount = amount or 1" +position = "after" +payload = "if not next(find_joker('cry-Universum')) then" +match_indent = true + + +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = "G.GAME.hands[hand].mult = math.max(G.GAME.hands[hand].s_mult + G.GAME.hands[hand].l_mult*(G.GAME.hands[hand].level - 1), 1)" +position = "at" +payload = "G.GAME.hands[hand].mult = math.max(G.GAME.hands[hand].mult + G.GAME.hands[hand].l_mult*amount, 1)" +match_indent = true + + +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = "G.GAME.hands[hand].chips = math.max(G.GAME.hands[hand].s_chips + G.GAME.hands[hand].l_chips*(G.GAME.hands[hand].level - 1), 0)" +position = "at" +payload = ''' +G.GAME.hands[hand].chips = math.max(G.GAME.hands[hand].chips + G.GAME.hands[hand].l_chips*amount, 1) +else + universum_mod = 1 + local effects = {} + SMODS.calculate_context({cry_universum = true}, effects) + for i = 1, #effects do + universum_mod = universum_mod * (effects[i] and effects[i].jokers and effects[i].jokers.mod or 1) + end + G.GAME.hands[hand].level = math.max(0, G.GAME.hands[hand].level + amount) + G.GAME.hands[hand].mult = math.max(G.GAME.hands[hand].mult * (universum_mod)^amount, 1) + G.GAME.hands[hand].chips = math.max(G.GAME.hands[hand].chips * (universum_mod)^amount, 1) +end +''' +match_indent = true \ No newline at end of file diff --git a/Cryptid/lovely/very_fair.toml b/Cryptid/lovely/very_fair.toml new file mode 100644 index 0000000..79343b2 --- /dev/null +++ b/Cryptid/lovely/very_fair.toml @@ -0,0 +1,61 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = -1 + +# Remove voucher at start of run (also for Crimson Stake) +[[patches]] +[patches.pattern] +target = "game.lua" +pattern = "self.GAME.current_round.voucher = G.SETTINGS.tutorial_progress and G.SETTINGS.tutorial_progress.forced_voucher or SMODS.get_next_vouchers()" +position = "after" +payload = ''' +if self.GAME.modifiers.cry_no_vouchers then + very_fair_quip = pseudorandom_element(G.localization.misc.very_fair_quips, pseudoseed("cry_very_fair")) +end +''' +match_indent = true + + +# Remove voucher when defeating boss (also for Crimson Stake) +[[patches]] +[patches.pattern] +target = "functions/state_events.lua" +pattern = "G.GAME.current_round.voucher = SMODS.get_next_vouchers()" +position = "after" +payload = ''' +if G.GAME.modifiers.cry_no_vouchers then + very_fair_quip = pseudorandom_element(G.localization.misc.very_fair_quips, pseudoseed("cry_very_fair")) +end +''' +match_indent = true + +# Change empty voucher text on Very Fair Deck +# This ain't localized, but that's a vanilla issue anyway +[[patches]] +[patches.pattern] +target = "cardarea.lua" +pattern = "{n=G.UIT.T, config={text = 'DEFEAT', scale = 0.6, colour = G.C.WHITE}}" +position = "at" +payload = "{n=G.UIT.T, config={text = G.GAME.modifiers.cry_no_vouchers and (very_fair_quip[1] or '') or 'DEFEAT', scale = 0.6, colour = G.C.WHITE}}" +match_indent = true + + +[[patches]] +[patches.pattern] +target = "cardarea.lua" +pattern = "{n=G.UIT.T, config={text = 'BOSS BLIND', scale = 0.4, colour = G.C.WHITE}}" +position = "at" +payload = "{n=G.UIT.T, config={text = G.GAME.modifiers.cry_no_vouchers and (very_fair_quip[2] or '') or G.GAME.modifiers.cry_voucher_restock_antes and G.GAME.round_resets.ante % G.GAME.modifiers.cry_voucher_restock_antes == 0 and 'TWO BOSS BLINDS' or 'BOSS BLIND', scale = 0.4, colour = G.C.WHITE}}" +match_indent = true + + +[[patches]] +[patches.pattern] +target = "cardarea.lua" +pattern = "{n=G.UIT.T, config={text = 'TO RESTOCK', scale = 0.4, colour = G.C.WHITE}}" +position = "at" +payload = "{n=G.UIT.T, config={text = G.GAME.modifiers.cry_no_vouchers and (very_fair_quip[3] or '') or 'TO RESTOCK', scale = 0.4, colour = G.C.WHITE}}" +match_indent = true + + diff --git a/Steamodded/lovely/achievements.toml b/Steamodded/lovely/achievements.toml new file mode 100644 index 0000000..f9338e9 --- /dev/null +++ b/Steamodded/lovely/achievements.toml @@ -0,0 +1,118 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = -10 + +## Achievement API + +# fetch_achievements() +[[patches]] +[patches.regex] +target = "functions/common_events.lua" +pattern = '''(?[\t ]*)if G\.F_NO_ACHIEVEMENTS then return end[\n\s]*?--\|FROM LOCAL SETTINGS FILE''' +position = 'before' +# match_indent = true +line_prepend = '$indent' +payload = ''' +G.SETTINGS.ACHIEVEMENTS_EARNED = G.SETTINGS.ACHIEVEMENTS_EARNED or {} +for k, v in pairs(G.ACHIEVEMENTS) do + if not v.key then v.key = k end + for kk, vv in pairs(G.SETTINGS.ACHIEVEMENTS_EARNED) do + if G.ACHIEVEMENTS[kk] and G.ACHIEVEMENTS[kk].mod then + G.ACHIEVEMENTS[kk].earned = true + end + end +end +''' + +# check_for_unlock +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = '''if G.GAME.challenge then return end''' +position = "after" +payload = ''' +fetch_achievements() -- Refreshes achievements +for k, v in pairs(G.ACHIEVEMENTS) do + if (not v.earned) and (v.unlock_condition and type(v.unlock_condition) == 'function') and v:unlock_condition(args) then + unlock_achievement(k) + end +end''' +match_indent = true + +# unlock_achievement() +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = '''if G.PROFILES[G.SETTINGS.profile].all_unlocked then return end''' +position = "at" +payload = '''if G.PROFILES[G.SETTINGS.profile].all_unlocked and (G.ACHIEVEMENTS and G.ACHIEVEMENTS[achievement_name] and not G.ACHIEVEMENTS[achievement_name].bypass_all_unlocked and SMODS.config.achievements < 3) or (SMODS.config.achievements < 3 and (G.GAME.seeded or G.GAME.challenge)) then return true end''' +match_indent = true + +# unlock_achievement() - fix event queue leaking +# fixed smods achievements not unlocking due to above comment's memory leak fix +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = '''local achievement_set = false +if G.F_NO_ACHIEVEMENTS then return end''' +position = "at" +payload = '''local achievement_set = false +if not G.ACHIEVEMENTS then fetch_achievements() end +G.SETTINGS.ACHIEVEMENTS_EARNED[achievement_name] = true +G:save_progress() + +if G.ACHIEVEMENTS[achievement_name] and G.ACHIEVEMENTS[achievement_name].mod then + if not G.ACHIEVEMENTS[achievement_name].earned then + --|THIS IS THE FIRST TIME THIS ACHIEVEMENT HAS BEEN EARNED + achievement_set = true + G.FILE_HANDLER.force = true + end + G.ACHIEVEMENTS[achievement_name].earned = true +end + +if achievement_set then + notify_alert(achievement_name) + return true +end +if G.F_NO_ACHIEVEMENTS and not (G.ACHIEVEMENTS[achievement_name] or {}).mod then return true end''' +match_indent = true + +# create_UIBox_notify_alert +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +pattern = '''local t_s = Sprite(0,0,1.5*(_atlas.px/_atlas.py),1.5,_atlas, _c and _c.pos or {x=3, y=0})''' +position = "before" +payload = '''if SMODS.Achievements[_achievement] then _c = SMODS.Achievements[_achievement]; _atlas = G.ASSET_ATLAS[_c.atlas] end''' +match_indent = true + +# option to allow unlocks and discoveries in seeded runs +[[patches]] +[patches.regex] +target = 'functions/common_events.lua' +pattern = 'if G\.GAME\.seeded or G\.GAME\.challenge then return end' +position = 'at' +payload = 'if not SMODS.config.seeded_unlocks and (G.GAME.seeded or G.GAME.challenge) then return end' + +[[patches]] +[patches.pattern] +target = 'functions/state_events.lua' +match_indent = true +position = 'at' +pattern = 'if not G.GAME.seeded and not G.GAME.challenge then' +payload = 'if (not G.GAME.seeded and not G.GAME.challenge) or SMODS.config.seeded_unlocks then' + +[[patches]] +[patches.regex] +target = 'functions/common_events.lua' +pattern = 'if G\.GAME\.seeded then' +position = 'at' +payload = 'if false then' + +[[patches]] +[patches.regex] +target = 'functions/common_events.lua' +pattern = 'if G\.GAME\.challenge then' +position = 'at' +payload = 'if false then' diff --git a/Steamodded/lovely/atlas.toml b/Steamodded/lovely/atlas.toml new file mode 100644 index 0000000..8976a87 --- /dev/null +++ b/Steamodded/lovely/atlas.toml @@ -0,0 +1,62 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = -10 + +### Sprite API + +# get_front_spriteinfo() + +[[patches]] +[patches.pattern] +target = 'functions/misc_functions.lua' +pattern = 'return G.ASSET_ATLAS[_front.atlas] or G.ASSET_ATLAS["cards_"..(G.SETTINGS.colourblind_option and 2 or 1)], _front.pos' +position = 'at' +match_indent = true +payload = 'return G.ASSET_ATLAS[G.SETTINGS.colourblind_option and _front.hc_atlas or _front.lc_atlas or {}] or G.ASSET_ATLAS[_front.atlas] or G.ASSET_ATLAS["cards_"..(G.SETTINGS.colourblind_option and 2 or 1)], _front.pos' + + +# Game:set_render_settings() +[[patches]] +[patches.pattern] +target = 'functions/button_callbacks.lua' +pattern = "G:set_render_settings()" +position = 'at' +match_indent = true +payload = "SMODS.injectObjects(SMODS.Atlas)" + + +# create_UIBox_notify_alert() +[[patches]] +[patches.pattern] +target = 'functions/UI_definitions.lua' +pattern = 'G.ASSET_ATLAS["icons"]' +position = 'after' +match_indent = false +payload = ''' + local _smods_atlas = _c and ((G.SETTINGS.colourblind_option and _c.hc_atlas or _c.lc_atlas) or _c.atlas) + if _smods_atlas then + _atlas = G.ASSET_ATLAS[_smods_atlas] or _atlas + end''' + +## Set ability resizing fix +[[patches]] +[patches.pattern] +target = 'engine/moveable.lua' +pattern = '''Node.init(self, args)''' +position = 'after' +match_indent = true +payload = '''self.original_T = copy_table(self.T)''' +[[patches]] +[patches.pattern] +target = 'card.lua' +match_indent = true +position = 'before' +pattern = ''' +local X, Y, W, H = self.T.x, self.T.y, self.T.w, self.T.h +''' +payload = ''' +for key, _ in pairs(self.T) do + self.T[key] = self.original_T[key] +end +''' \ No newline at end of file diff --git a/Steamodded/lovely/back.toml b/Steamodded/lovely/back.toml new file mode 100644 index 0000000..24efafc --- /dev/null +++ b/Steamodded/lovely/back.toml @@ -0,0 +1,193 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = -10 + +### Back API + +# Back:init() +[[patches]] +[patches.pattern] +target = 'back.lua' +pattern = "if not selected_back then selected_back = G.P_CENTERS.b_red end" +position = 'after' +match_indent = true +payload = "self.atlas = selected_back.unlocked and selected_back.atlas or nil" + +# Back:change_to() +[[patches]] +[patches.pattern] +target = 'back.lua' +pattern = "if not new_back then new_back = G.P_CENTERS.b_red end" +position = 'after' +match_indent = true +payload = "self.atlas = new_back.unlocked and new_back.atlas or nil" + +# G.FUNCS.change_viewed_back +[[patches]] +[patches.pattern] +target = 'functions/button_callbacks.lua' +pattern = "G.PROFILES[G.SETTINGS.profile].MEMORY.deck = args.to_val" +position = 'after' +match_indent = true +payload = ''' +for key, val in pairs(G.sticker_card.area.cards) do + val.children.back = false + val:set_ability(val.config.center, true) +end''' + +# Back:apply_to_run() +[[patches]] +[patches.pattern] +target = 'back.lua' +pattern = "function Back:apply_to_run()" +position = 'after' +match_indent = true +payload = ''' + local obj = self.effect.center + if obj.apply and type(obj.apply) == 'function' then + obj:apply(self) + end''' + +[[patches]] +[patches.pattern] +target = 'back.lua' +pattern = "if self.effect.config.randomize_rank_suit then" +position = 'before' +match_indent = true +payload = ''' +G.E_MANAGER:add_event(Event({ + func = function() + G.E_MANAGER:add_event(Event({ + func = function() + save_run() + return true + end + })) + return true + end +})) +''' + +# Back:trigger_effect(args) +[[patches]] +[patches.pattern] +target = 'back.lua' +pattern = "if not args then return end" +position = 'after' +match_indent = true +payload = ''' + local obj = self.effect.center + if type(obj.calculate) == 'function' then + local o = {obj:calculate(self, args)} + if next(o) ~= nil then return unpack(o) end + elseif type(obj.trigger_effect) == 'function' then + -- kept for compatibility + local o = {obj:trigger_effect(args)} + if next(o) ~= nil then + sendWarnMessage(('Found `trigger_effect` function on SMODS.Back object "%s". This field is deprecated; please use `calculate` instead.'):format(obj.key), 'Back') + return unpack(o) + end + end''' + +## Back:generate_UI + +# Localization with `unlock` field in loc_txt, same as for Jokers +[[patches]] +[patches.pattern] +target = 'back.lua' +pattern = 'if not back_config.unlock_condition then' +position = 'at' +payload = ''' +local localized_by_smods +local key_override +if back_config.locked_loc_vars and type(back_config.locked_loc_vars) == 'function' then + local res = back_config:locked_loc_vars() or {} + loc_args = res.vars or {} + key_override = res.key +end +if G.localization.descriptions.Back[key_override or back_config.key].unlock_parsed then + localize{type = 'unlocks', key = key_override or back_config.key, set = 'Back', nodes = loc_nodes, vars = loc_args} + localized_by_smods = true +end +if not back_config.unlock_condition then''' +match_indent = true +[[patches]] +[patches.pattern] +target = 'back.lua' +pattern = '''localize{type = 'descriptions', key = 'demo_locked', set = "Other", nodes = loc_nodes, vars = loc_args}''' +position = 'at' +payload = ''' +if not localized_by_smods then + localize{type = 'descriptions', key = 'demo_locked', set = "Other", nodes = loc_nodes, vars = loc_args} +end''' +match_indent = true + +[[patches]] +[patches.pattern] +target = 'back.lua' +pattern = 'loc_args = {other_name}' +position = 'at' +payload = 'loc_args = loc_args or {other_name}' +match_indent = true +[[patches]] +[patches.pattern] +target = 'back.lua' +pattern = 'loc_args = {tostring(back_config.unlock_condition.amount)}' +position = 'at' +payload = 'loc_args = loc_args or {tostring(back_config.unlock_condition.amount)}' +match_indent = true +[[patches]] +[patches.pattern] +target = 'back.lua' +pattern = 'loc_args = {other_name, colours = {get_stake_col(back_config.unlock_condition.stake)}}' +position = 'at' +payload = 'loc_args = loc_args or {other_name, colours = {get_stake_col(back_config.unlock_condition.stake)}}' +match_indent = true + +[[patches]] +[patches.pattern] +target = 'back.lua' +pattern = "if name_to_check == 'Blue Deck'*" +position = 'at' +match_indent = true +payload = ''' +local key_override +if back_config.loc_vars and type(back_config.loc_vars) == 'function' then + local res = back_config:loc_vars() or {} + loc_args = res.vars or {} + key_override = res.key +elseif name_to_check == 'Blue Deck' then loc_args = {effect_config.hands}''' + +[[patches]] +[patches.regex] +target = 'back.lua' +pattern = "key = back_config\\.key" +position = 'at' +payload = "key = key_override or back_config.key" + +# Back:apply_to_run() - add jokers support to config +[[patches]] +[patches.pattern] +target = 'back.lua' +match_indent = true +position = 'before' +pattern = ''' +if self.effect.config.voucher then +''' +payload = ''' +if self.effect.config.jokers then + delay(0.4) + G.E_MANAGER:add_event(Event({ + func = function() + for k, v in ipairs(self.effect.config.jokers) do + local card = create_card('Joker', G.jokers, nil, nil, nil, nil, v, 'deck') + card:add_to_deck() + G.jokers:emplace(card) + card:start_materialize() + end + return true + end + })) + end +''' diff --git a/Steamodded/lovely/better_calc.toml b/Steamodded/lovely/better_calc.toml new file mode 100644 index 0000000..89917c9 --- /dev/null +++ b/Steamodded/lovely/better_calc.toml @@ -0,0 +1,1584 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = -10 + +## G.FUNCS.evaluate_play() +# evaluate main scoring + +[[patches]] +[patches.regex] +target = 'functions/state_events.lua' +pattern = '''(?[\t ]*)(?if modded then update_hand_text\(\{sound = 'chips2', modded = modded\}, \{chips = hand_chips, mult = mult\}\) end)(.*\n)*?\s+(?--\++--)''' +position = 'at' +line_prepend = '$indent' +payload = '''$handtext +delay(0.3) +for _, v in ipairs(SMODS.get_card_areas('playing_cards')) do + SMODS.calculate_main_scoring({cardarea = v, full_hand = G.play.cards, scoring_hand = scoring_hand, scoring_name = text, poker_hands = poker_hands}, v == G.play and scoring_hand or nil) + delay(0.3) +end +$delimiter''' +## eval_card() +# handle debuffed playing cards +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = ''' +function eval_card(card, context) + context = context or {} + local ret = {} +''' +position = 'at' +match_indent = true +payload = ''' +function eval_card(card, context) + context = context or {} + if not card:can_calculate(context.ignore_debuff) then return {}, {} end + local ret = {} +''' + +# built in config values +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = ''' +if context.cardarea == G.play then + local chips = card:get_chip_bonus() + if chips > 0 then + ret.chips = chips + end + + local mult = card:get_chip_mult() + if mult > 0 then + ret.mult = mult + end + + local x_mult = card:get_chip_x_mult(context) + if x_mult > 0 then + ret.x_mult = x_mult + end + + local p_dollars = card:get_p_dollars() + if p_dollars > 0 then + ret.p_dollars = p_dollars + end + + local jokers = card:calculate_joker(context) + if jokers then + ret.jokers = jokers + end + + local edition = card:get_edition(context) + if edition then + ret.edition = edition + end +end +''' +match_indent = true +position = "at" +payload = """ +if context.cardarea == G.play and context.main_scoring then + ret.playing_card = {} + local chips = card:get_chip_bonus() + if chips ~= 0 then + ret.playing_card.chips = chips + end + + local mult = card:get_chip_mult() + if mult ~= 0 then + ret.playing_card.mult = mult + end + + local x_mult = card:get_chip_x_mult(context) + if x_mult > 0 then + ret.playing_card.x_mult = x_mult + end + + local p_dollars = card:get_p_dollars() + if p_dollars ~= 0 then + ret.playing_card.p_dollars = p_dollars + end + + local x_chips = card:get_chip_x_bonus() + if x_chips > 0 then + ret.playing_card.x_chips = x_chips + end + + -- TARGET: main scoring on played cards + + local jokers = card:calculate_joker(context) + if jokers then + ret.jokers = jokers + end + + local edition = card:calculate_edition(context) + if edition then + ret.edition = edition + end +end +if context.end_of_round and context.cardarea == G.hand and context.playing_card_end_of_round then + local end_of_round = card:get_end_of_round_effect(context) + if end_of_round then + ret.end_of_round = end_of_round + end +end +""" +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = ''' +if context.cardarea == G.hand then + local h_mult = card:get_chip_h_mult() + if h_mult > 0 then + ret.h_mult = h_mult + end + + local h_x_mult = card:get_chip_h_x_mult() + if h_x_mult > 0 then + ret.x_mult = h_x_mult + end +''' +match_indent = true +position = "at" +payload = """ +if context.cardarea == G.hand and context.main_scoring then + ret.playing_card = {} + local h_mult = card:get_chip_h_mult() + if h_mult ~= 0 then + ret.playing_card.h_mult = h_mult + end + + local h_x_mult = card:get_chip_h_x_mult() + if h_x_mult > 0 then + ret.playing_card.x_mult = h_x_mult + end + + local h_chips = card:get_chip_h_bonus() + if h_chips ~= 0 then + ret.playing_card.h_chips = h_chips + end + + local h_x_chips = card:get_chip_h_x_bonus() + if h_x_chips > 0 then + ret.playing_card.x_chips = h_x_chips + end + + -- TARGET: main scoring on held cards +""" + +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = ''' +local seals = card:calculate_seal(context) +if seals then + ret.seals = seals +end +''' +match_indent = true +position = "at" +payload = """ +if card.ability.set == 'Enhanced' then + local enhancement = card:calculate_enhancement(context) + if enhancement then + ret.enhancement = enhancement + end +end +if card.edition then + local edition = card:calculate_edition(context) + if edition then + ret.edition = edition + end +end +if card.seal then + local seals = card:calculate_seal(context) + if seals then + ret.seals = seals + end +end +for k,v in pairs(SMODS.Stickers) do + local sticker = card:calculate_sticker(context, k) + if sticker then + ret[v] = sticker + end +end + +-- TARGET: evaluate your own repetition effects +""" +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = "if context.cardarea == G.jokers or context.card == G.consumeables then" +match_indent = true +position = "before" +payload = """ +if card.ability.set == 'Enhanced' then + local enhancement = card:calculate_enhancement(context) + if enhancement then + ret.enhancement = enhancement + end +end +if card.edition then + local edition = card:calculate_edition(context) + if edition then + ret.edition = edition + end +end +if card.seal and not card.ability.extra_enhancement then + local seals = card:calculate_seal(context) + if seals then + ret.seals = seals + end +end +for k,v in pairs(SMODS.Stickers) do + local sticker = card:calculate_sticker(context, k) + if sticker then + ret[v] = sticker + end +end + +-- TARGET: evaluate your own general effects +""" +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = ''' +if context.cardarea == G.jokers or context.card == G.consumeables then + local jokers = nil + if context.edition then + jokers = card:get_edition(context) + elseif context.other_joker then + jokers = context.other_joker:calculate_joker(context) + else + jokers = card:calculate_joker(context) + end + if jokers then + ret.jokers = jokers + end +end + +return ret''' +match_indent = true +position = "at" +payload = """ +local post_trig = {} +local areas = SMODS.get_card_areas('jokers') +local area_set = {} +for _,v in ipairs(areas) do area_set[v] = true end +if card.area and area_set[card.area] then + local jokers, triggered = card:calculate_joker(context) + if jokers == true then jokers = { remove = true } end + if type(jokers) ~= 'table' then jokers = nil end + if jokers or triggered then + ret.jokers = jokers + if not (context.retrigger_joker_check or context.retrigger_joker) and not (jokers and jokers.no_retrigger) then + local retriggers = SMODS.calculate_retriggers(card, context, ret) + if next(retriggers) then + ret.retriggers = retriggers + end + end + if not context.post_trigger and not context.retrigger_joker_check 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 = ret}, post_trig) + end + end +end + +return ret, post_trig +""" +# patch card_eval_status_text to allow G.deck usage +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = ''' +elseif card.area == G.hand then''' +match_indent = true +position = "at" +payload = """ +elseif card.area == G.hand or card.area == G.deck then +""" + +# card_eval_status_text alignment patches +[[patches]] +[patches.pattern] +target = 'functions/common_events.lua' +match_indent = true +position = 'before' +pattern = '''elseif card.area == G.hand or card.area == G.deck then''' +payload = '''elseif card == G.deck then + y_off = -0.05*G.CARD_H + card_aligned = 'tm' +elseif card.area == G.discard or card.area == G.vouchers then + y_off = card.area == G.discard and -0.35*G.CARD_H or -0.65*G.CARD_H + card = G.deck.cards[1] or G.deck + card_aligned = 'tm' +''' + +# G.FUNCS.evaluate_play() + + +# Add deck/discard individual contexts +[[patches]] +[patches.pattern] +target = 'functions/state_events.lua' +position = 'before' +match_indent = true +pattern = ''' +--+++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- +--Joker Effects +--+++++++++++++++++++++++++++++++++++++++++++++++++++++++++--''' +payload = ''' + +''' + +# Joker Effects +# Edition effects +[[patches]] +[patches.pattern] +target = "functions/state_events.lua" +pattern = ''' +--calculate the joker edition effects +local edition_effects = eval_card(_card, {cardarea = G.jokers, full_hand = G.play.cards, scoring_hand = scoring_hand, scoring_name = text, poker_hands = poker_hands, edition = true}) +if edition_effects.jokers then + edition_effects.jokers.edition = true + if edition_effects.jokers.chip_mod then + hand_chips = mod_chips(hand_chips + edition_effects.jokers.chip_mod) + update_hand_text({delay = 0}, {chips = hand_chips}) + card_eval_status_text(_card, 'jokers', nil, percent, nil, { + message = localize{type='variable',key='a_chips',vars={edition_effects.jokers.chip_mod}}, + chip_mod = edition_effects.jokers.chip_mod, + colour = G.C.EDITION, + edition = true}) + end + if edition_effects.jokers.mult_mod then + mult = mod_mult(mult + edition_effects.jokers.mult_mod) + update_hand_text({delay = 0}, {mult = mult}) + card_eval_status_text(_card, 'jokers', nil, percent, nil, { + message = localize{type='variable',key='a_mult',vars={edition_effects.jokers.mult_mod}}, + mult_mod = edition_effects.jokers.mult_mod, + colour = G.C.DARK_EDITION, + edition = true}) + end + percent = percent+percent_delta +end''' +match_indent = true +position = "at" +payload = ''' +local effects = {} +-- remove base game joker edition calc +local eval = eval_card(_card, {cardarea = G.jokers, full_hand = G.play.cards, scoring_hand = scoring_hand, scoring_name = text, poker_hands = poker_hands, edition = true, pre_joker = true}) +if eval.edition then effects[#effects+1] = eval end + +''' +# Edition mult effects +## extra end to fix syntax from adding joker-like areas +[[patches]] +[patches.pattern] +target = "functions/state_events.lua" +pattern = ''' + if edition_effects.jokers then + if edition_effects.jokers.x_mult_mod then + mult = mod_mult(mult*edition_effects.jokers.x_mult_mod) + update_hand_text({delay = 0}, {mult = mult}) + card_eval_status_text(_card, 'jokers', nil, percent, nil, { + message = localize{type='variable',key='a_xmult',vars={edition_effects.jokers.x_mult_mod}}, + x_mult_mod = edition_effects.jokers.x_mult_mod, + colour = G.C.EDITION, + edition = true}) + end + percent = percent+percent_delta + end +end''' +match_indent = false +position = "at" +payload = ''' + -- calculate edition multipliers + local eval = eval_card(_card, {cardarea = G.jokers, full_hand = G.play.cards, scoring_hand = scoring_hand, scoring_name = text, poker_hands = poker_hands, edition = true, post_joker = true}) + if eval.edition then effects[#effects+1] = eval end + + SMODS.trigger_effects(effects, _card) + end end +''' +# Joker effects + +# allows adding other areas (syntax is fixed further down) +[[patches]] +[patches.pattern] +target = 'functions/state_events.lua' +match_indent = true +position = 'at' +pattern = '''for i=1, #G.jokers.cards + #G.consumeables.cards do + local _card = G.jokers.cards[i] or G.consumeables.cards[i - #G.jokers.cards]''' +payload = '''for _, area in ipairs(SMODS.get_card_areas('jokers')) do for _, _card in ipairs(area.cards) do''' + +## I am NOT converting this to regex (yet) +[[patches]] +[patches.pattern] +target = "functions/state_events.lua" +pattern = ''' + --calculate the joker effects + local effects = eval_card(_card, {cardarea = G.jokers, full_hand = G.play.cards, scoring_hand = scoring_hand, scoring_name = text, poker_hands = poker_hands, joker_main = true}) + + --Any Joker effects + if effects.jokers then + local extras = {mult = false, hand_chips = false} + if effects.jokers.mult_mod then mult = mod_mult(mult + effects.jokers.mult_mod);extras.mult = true end + if effects.jokers.chip_mod then hand_chips = mod_chips(hand_chips + effects.jokers.chip_mod);extras.hand_chips = true end + if effects.jokers.Xmult_mod then mult = mod_mult(mult*effects.jokers.Xmult_mod);extras.mult = true end + update_hand_text({delay = 0}, {chips = extras.hand_chips and hand_chips, mult = extras.mult and mult}) + card_eval_status_text(_card, 'jokers', nil, percent, nil, effects.jokers) + percent = percent+percent_delta + end''' +match_indent = true +position = "at" +payload = ''' +-- Calculate context.joker_main +local joker_eval, post = eval_card(_card, {cardarea = G.jokers, full_hand = G.play.cards, scoring_hand = scoring_hand, scoring_name = text, poker_hands = poker_hands, joker_main = true}) +if next(joker_eval) then + if joker_eval.edition then joker_eval.edition = {} end + table.insert(effects, joker_eval) + for _, v in ipairs(post) do effects[#effects+1] = v end + if joker_eval.retriggers then + for rt = 1, #joker_eval.retriggers do + local rt_eval, rt_post = eval_card(_card, {cardarea = G.jokers, full_hand = G.play.cards, scoring_hand = scoring_hand, scoring_name = text, poker_hands = poker_hands, joker_main = true, retrigger_joker = true}) + table.insert(effects, {joker_eval.retriggers[rt]}) + table.insert(effects, rt_eval) + for _, v in ipairs(rt_post) do effects[#effects+1] = v end + end + end +end''' +# Joker on Joker effects +[[patches]] +[patches.pattern] +target = "functions/state_events.lua" +pattern = ''' +--Joker on Joker effects +for _, v in ipairs(G.jokers.cards) do + local effect = v:calculate_joker{full_hand = G.play.cards, scoring_hand = scoring_hand, scoring_name = text, poker_hands = poker_hands, other_joker = _card} + if effect then + local extras = {mult = false, hand_chips = false} + if effect.mult_mod then mult = mod_mult(mult + effect.mult_mod);extras.mult = true end + if effect.chip_mod then hand_chips = mod_chips(hand_chips + effect.chip_mod);extras.hand_chips = true end + if effect.Xmult_mod then mult = mod_mult(mult*effect.Xmult_mod);extras.mult = true end + if extras.mult or extras.hand_chips then update_hand_text({delay = 0}, {chips = extras.hand_chips and hand_chips, mult = extras.mult and mult}) end + if extras.mult or extras.hand_chips then card_eval_status_text(v, 'jokers', nil, percent, nil, effect) end + percent = percent+percent_delta + end +end''' +match_indent = true +position = "at" +payload = ''' +-- Calculate context.other_joker effects +for _, _area in ipairs(SMODS.get_card_areas('jokers')) do + for _, _joker in ipairs(_area.cards) do + local other_key = 'other_unknown' + if _card.ability.set == 'Joker' then other_key = 'other_joker' end + if _card.ability.consumeable then other_key = 'other_consumeable' end + if _card.ability.set == 'Voucher' then other_key = 'other_voucher' end + -- TARGET: add context.other_something identifier to your cards + local joker_eval,post = eval_card(_joker, {full_hand = G.play.cards, scoring_hand = scoring_hand, scoring_name = text, poker_hands = poker_hands, [other_key] = _card, other_main = _card }) + if next(joker_eval) then + if joker_eval.edition then joker_eval.edition = {} end + joker_eval.jokers.juice_card = _joker + table.insert(effects, joker_eval) + for _, v in ipairs(post) do effects[#effects+1] = v end + if joker_eval.retriggers then + for rt = 1, #joker_eval.retriggers do + local rt_eval, rt_post = eval_card(_joker, {full_hand = G.play.cards, scoring_hand = scoring_hand, scoring_name = text, poker_hands = poker_hands, [other_key] = _card, retrigger_joker = true}) + table.insert(effects, {joker_eval.retriggers[rt]}) + table.insert(effects, rt_eval) + for _, v in ipairs(rt_post) do effects[#effects+1] = v end + end + end + end + end +end +for _, _area in ipairs(SMODS.get_card_areas('individual')) do + local other_key = 'other_unknown' + if _card.ability.set == 'Joker' then other_key = 'other_joker' end + if _card.ability.consumeable then other_key = 'other_consumeable' end + if _card.ability.set == 'Voucher' then other_key = 'other_voucher' end + -- TARGET: add context.other_something identifier to your cards + local _eval,post = SMODS.eval_individual(_area, {full_hand = G.play.cards, scoring_hand = scoring_hand, scoring_name = text, poker_hands = poker_hands, [other_key] = _card, other_main = _card }) + if next(_eval) then + _eval.individual.juice_card = _area.scored_card + table.insert(effects, _eval) + for _, v in ipairs(post) do effects[#effects+1] = v end + if _eval.retriggers then + for rt = 1, #_eval.retriggers do + local rt_eval, rt_post = SMODS.eval_individual(_area, {full_hand = G.play.cards, scoring_hand = scoring_hand, scoring_name = text, poker_hands = poker_hands, [other_key] = _card, retrigger_joker = true}) + table.insert(effects, {_eval.retriggers[rt]}) + table.insert(effects, rt_eval) + for _, v in ipairs(rt_post) do effects[#effects+1] = v end + end + end + end +end +''' + +## Fix other evaluations +# Discarding cards +[[patches]] +[patches.pattern] +target = "functions/state_events.lua" +pattern = ''' +for j = 1, #G.jokers.cards do + local eval = nil + eval = G.jokers.cards[j]:calculate_joker({discard = true, other_card = G.hand.highlighted[i], full_hand = G.hand.highlighted}) + if eval then + if eval.remove then removed = true end + card_eval_status_text(G.jokers.cards[j], 'jokers', nil, 1, nil, eval) + end +end''' +match_indent = true +position = "at" +payload = ''' +local effects = {} +SMODS.calculate_context({discard = true, other_card = G.hand.highlighted[i], full_hand = G.hand.highlighted}, effects) +SMODS.trigger_effects(effects) +for _, eval in pairs(effects) do + if type(eval) == 'table' then + for key, eval2 in pairs(eval) do + if key == 'remove' or (type(eval2) == 'table' and eval2.remove) then removed = true end + end + end +end''' + +# context.before +[[patches]] +[patches.pattern] +target = "functions/state_events.lua" +pattern = ''' +for i=1, #G.jokers.cards do + --calculate the joker effects + local effects = eval_card(G.jokers.cards[i], {cardarea = G.jokers, full_hand = G.play.cards, scoring_hand = scoring_hand, scoring_name = text, poker_hands = poker_hands, before = true}) + if effects.jokers then + card_eval_status_text(G.jokers.cards[i], 'jokers', nil, percent, nil, effects.jokers) + percent = percent + percent_delta + if effects.jokers.level_up then + level_up_hand(G.jokers.cards[i], text) + end + end +end''' +match_indent = true +position = "at" +payload = ''' +-- context.before calculations +SMODS.calculate_context({full_hand = G.play.cards, scoring_hand = scoring_hand, scoring_name = text, poker_hands = poker_hands, before = true}) + +-- TARGET: effects before scoring starts''' + +# context.final_scoring_step +[[patches]] +[patches.pattern] +target = "functions/state_events.lua" +pattern = '''local nu_chip, nu_mult = G.GAME.selected_back:trigger_effect{context = 'final_scoring_step', chips = hand_chips, mult = mult}''' +match_indent = true +position = "before" +payload = ''' +-- context.final_scoring_step calculations +SMODS.calculate_context({full_hand = G.play.cards, scoring_hand = scoring_hand, scoring_name = text, poker_hands = poker_hands, final_scoring_step = true}) + +-- TARGET: effects before deck final_scoring_step +''' + +# context.destroying_card +[[patches]] +[patches.pattern] +target = "functions/state_events.lua" +pattern = ''' +for j = 1, #G.jokers.cards do + destroyed = G.jokers.cards[j]:calculate_joker({destroying_card = scoring_hand[i], full_hand = G.play.cards}) + if destroyed then break end +end + +if scoring_hand[i].ability.name == 'Glass Card' and not scoring_hand[i].debuff and pseudorandom('glass') < G.GAME.probabilities.normal/scoring_hand[i].ability.extra then + destroyed = true +end''' +match_indent = true +position = "at" +payload = ''' +-- context.destroying_card calculations +for j = 1, #G.jokers.cards do + local eval, post = eval_card(G.jokers.cards[j], {destroying_card = scoring_hand[i], full_hand = G.play.cards}) + SMODS.trigger_effects({eval, post}, scoring_hand[i]) + if eval.jokers then destroyed = true end + +end + +if SMODS.has_enhancement(scoring_hand[i], 'm_glass') and scoring_hand[i]:can_calculate() and pseudorandom('glass') < G.GAME.probabilities.normal/(scoring_hand[i].ability.name == 'Glass Card' and scoring_hand[i].ability.extra or G.P_CENTERS.m_glass.config.extra) then + destroyed = true +end + +local eval, post = eval_card(scoring_hand[i], {destroying_card = scoring_hand[i], full_hand = G.play.cards, scoring_hand = scoring_hand, scoring_name = text, poker_hands = poker_hands, cardarea = G.play}) +local self_destroy = false +for key, effect in pairs(eval) do + self_destroy = SMODS.calculate_effect(effect, scoring_hand[i]) +end +SMODS.trigger_effects({post}, scoring_hand[i]) +if self_destroy then destroyed = true end + +-- TARGET: card destroyed when played +''' + +# context.remove_playing_cards +[[patches]] +[patches.regex] +target = "functions/state_events.lua" +pattern = '''(?[\t ]*)local cards_destroyed = \{\}\n(.*\n)*?\s+for j=1, #G\.jokers\.cards do\n\s+eval_card\(G\.jokers\.cards\[j\], \{cardarea = G\.jokers, remove_playing_cards = true, removed = cards_destroyed\}\)\n\s+end''' +line_prepend = '$indent' +position = "at" +payload = ''' +local cards_destroyed = {} +for _,v in ipairs(SMODS.get_card_areas('playing_cards', 'destroying_cards')) do + SMODS.calculate_destroying_cards({ full_hand = G.play.cards, scoring_hand = scoring_hand, scoring_name = text, poker_hands = poker_hands, cardarea = v }, cards_destroyed, v == G.play and scoring_hand or nil) +end + +-- context.remove_playing_cards calculations +if cards_destroyed[1] then + SMODS.calculate_context({scoring_hand = scoring_hand, remove_playing_cards = true, removed = cards_destroyed}) +end + +-- TARGET: effects when cards are removed + +''' + +[[patches]] +[patches.regex] +target = 'card.lua' +line_prepend = '$indent' +position = 'at' +pattern = '(?[\t ]*)for i = 1, #G.jokers.cards do[\n\s]*G.jokers.cards\[i\]:calculate_joker\(\{remove_playing_cards = true, removed = destroyed_cards\}\)[\s\n]*end' +payload = '''SMODS.calculate_context({ remove_playing_cards = true, removed = destroyed_cards })''' + +# context.remove_playing_cards from discard +[[patches]] +[patches.pattern] +target = "functions/state_events.lua" +pattern = ''' +if destroyed_cards[1] then + for j=1, #G.jokers.cards do + eval_card(G.jokers.cards[j], {cardarea = G.jokers, remove_playing_cards = true, removed = destroyed_cards}) + end +end +''' +position = "at" +match_indent = true +payload = ''' +-- context.remove_playing_cards from discard +if destroyed_cards[1] then + SMODS.calculate_context({remove_playing_cards = true, removed = destroyed_cards}) +end + +-- TARGET: effects after cards destroyed in discard''' + + +# context.debuffed_hand +[[patches]] +[patches.pattern] +target = "functions/state_events.lua" +pattern = ''' +for i=1, #G.jokers.cards do + + --calculate the joker effects + local effects = eval_card(G.jokers.cards[i], {cardarea = G.jokers, full_hand = G.play.cards, scoring_hand = scoring_hand, scoring_name = text, poker_hands = poker_hands, debuffed_hand = true}) + + --Any Joker effects + if effects.jokers then + card_eval_status_text(G.jokers.cards[i], 'jokers', nil, percent, nil, effects.jokers) + percent = percent+percent_delta + end +end''' +match_indent = true +position = "at" +payload = ''' +-- context.debuffed_hand calculations +SMODS.calculate_context({full_hand = G.play.cards, scoring_hand = scoring_hand, scoring_name = text, poker_hands = poker_hands, debuffed_hand = true}) + +-- TARGET: effects after hand debuffed by blind''' + +# context.after +[[patches]] +[patches.pattern] +target = "functions/state_events.lua" +pattern = ''' +for i=1, #G.jokers.cards do + --calculate the joker after hand played effects + local effects = eval_card(G.jokers.cards[i], {cardarea = G.jokers, full_hand = G.play.cards, scoring_hand = scoring_hand, scoring_name = text, poker_hands = poker_hands, after = true}) + if effects.jokers then + card_eval_status_text(G.jokers.cards[i], 'jokers', nil, percent, nil, effects.jokers) + percent = percent + percent_delta + end +end''' +match_indent = true +position = "at" +payload = ''' +-- context.after calculations +SMODS.calculate_context({full_hand = G.play.cards, scoring_hand = scoring_hand, scoring_name = text, poker_hands = poker_hands, after = true}) + +-- TARGET: effects after hand evaluation''' + +# calc_dollar_bonus call through consumeables +[[patches]] +[patches.pattern] +target = 'functions/state_events.lua' +pattern = ''' +for i = 1, #G.jokers.cards do + local ret = G.jokers.cards[i]:calculate_dollar_bonus() + if ret then + add_round_eval_row({dollars = ret, bonus = true, name='joker'..i, pitch = pitch, card = G.jokers.cards[i]}) + pitch = pitch + 0.06 + dollars = dollars + ret + end +end +''' +position = 'at' +match_indent = true +payload = ''' +local i = 0 +for _, area in ipairs(SMODS.get_card_areas('jokers')) do + for _, _card in ipairs(area.cards) do + local ret = _card:calculate_dollar_bonus() + + -- TARGET: calc_dollar_bonus per card + if ret then + i = i+1 + add_round_eval_row({dollars = ret, bonus = true, name='joker'..i, pitch = pitch, card = _card}) + pitch = pitch + 0.06 + dollars = dollars + ret + end + end +end +''' + +# context.end_of_round +[[patches]] +[patches.pattern] +target = 'functions/state_events.lua' +pattern = ''' +for i = 1, #G.jokers.cards do + local eval = nil + eval = G.jokers.cards[i]:calculate_joker({end_of_round = true, game_over = game_over}) + if eval then + if eval.saved then + game_over = false + end + card_eval_status_text(G.jokers.cards[i], 'jokers', nil, nil, nil, eval) + end + G.jokers.cards[i]:calculate_rental() + G.jokers.cards[i]:calculate_perishable() +end +''' +position = 'at' +match_indent = true +payload = ''' +-- context.end_of_round calculations +SMODS.saved = false +SMODS.calculate_context({end_of_round = true, game_over = game_over }) +if SMODS.saved then game_over = false end +-- TARGET: main end_of_round evaluation +''' + +# context.end_of_round individual effects +[[patches]] +[patches.regex] +target = 'functions/state_events.lua' +position = 'at' +pattern = '''(?[\t ]*)for i=1, #G\.hand\.cards do\n\s+--Check for hand doubling\n(.*\n)*?\s+delay\(0\.3\)''' +line_prepend = '$indent' +payload = '''for _,v in ipairs(SMODS.get_card_areas('playing_cards', 'end_of_round')) do + SMODS.calculate_end_of_round_effects({ cardarea = v, end_of_round = true }) +end +''' + + +# context.setting_blind +[[patches]] +[patches.pattern] +target = 'functions/state_events.lua' +pattern = ''' +for i = 1, #G.jokers.cards do + G.jokers.cards[i]:calculate_joker({setting_blind = true, blind = G.GAME.round_resets.blind}) +end +''' +position = 'at' +match_indent = true +payload = ''' +SMODS.calculate_context({setting_blind = true, blind = G.GAME.round_resets.blind}) + +-- TARGET: setting_blind effects +''' + +# context.pre_discard +[[patches]] +[patches.pattern] +target = 'functions/state_events.lua' +pattern = ''' +for j = 1, #G.jokers.cards do + G.jokers.cards[j]:calculate_joker({pre_discard = true, full_hand = G.hand.highlighted, hook = hook}) +end +''' +position = 'at' +match_indent = true +payload = ''' +SMODS.calculate_context({pre_discard = true, full_hand = G.hand.highlighted, hook = hook}) + +-- TARGET: pre_discard +''' + +# context.selling_self in cards +[[patches]] +[patches.pattern] +target = 'card.lua' +pattern = ''' +self:calculate_joker{selling_self = true} +''' +position = 'at' +match_indent = true +payload = ''' +local eval, post = eval_card(self, {selling_self = true}) +local effects = {eval} +for _,v in ipairs(post) do effects[#effects+1] = v end +if eval.retriggers then + for rt = 1, #eval.retriggers do + local rt_eval, rt_post = eval_card(self, { selling_self = true, retrigger_joker = true}) + table.insert(effects, {eval.retriggers[rt]}) + table.insert(effects, rt_eval) + for _, v in ipairs(rt_post) do effects[#effects+1] = v end + end +end +SMODS.trigger_effects(effects, self) +''' + +# context.open_booster +[[patches]] +[patches.pattern] +target = 'card.lua' +pattern = ''' + for i = 1, #G.jokers.cards do + G.jokers.cards[i]:calculate_joker({open_booster = true, card = self}) + end +''' +position = 'at' +match_indent = true +payload = ''' +SMODS.calculate_context({open_booster = true, card = self}) +''' + +# context.buying_card +[[patches]] +[patches.pattern] +target = 'card.lua' +pattern = ''' + for i = 1, #G.jokers.cards do + G.jokers.cards[i]:calculate_joker({buying_card = true, card = self}) + end +''' +position = 'at' +match_indent = true +payload = ''' +SMODS.calculate_context({buying_card = true, card = self}) +''' + +# context.first_hand_drawn +[[patches]] +[patches.pattern] +target = 'game.lua' +pattern = ''' +if G.GAME.current_round.hands_played == 0 and + G.GAME.current_round.discards_used == 0 and G.GAME.facing_blind then + for i = 1, #G.jokers.cards do + G.jokers.cards[i]:calculate_joker({first_hand_drawn = true}) + end +end +''' +position = 'at' +match_indent = true +payload = ''' +-- removed first hand drawn context +''' +# Hand Drawn Contexts +[[patches]] +[patches.pattern] +target = 'cardarea.lua' +match_indent = true +position = 'at' +pattern = ''' +self:emplace(card, nil, stay_flipped) +return true +''' +payload = ''' +self:emplace(card, nil, stay_flipped) +return card +''' +[[patches]] +[patches.pattern] +target = 'functions/common_events.lua' +match_indent = true +position = 'at' +pattern = ''' +if to:draw_card_from(from, stay_flipped, discarded_only) then drawn = true end +''' +payload = ''' +card = to:draw_card_from(from, stay_flipped, discarded_only) +if card then drawn = true end +''' +[[patches]] +[patches.pattern] +target = 'functions/common_events.lua' +match_indent = true +position = 'after' +pattern = ''' +if sort then + to:sort() +end +''' +payload = ''' +SMODS.drawn_cards = SMODS.drawn_cards or {} +if card and card.playing_card then SMODS.drawn_cards[#SMODS.drawn_cards+1] = card end +''' +[[patches]] +[patches.pattern] +target = 'functions/state_events.lua' +match_indent = true +position = 'before' +pattern = ''' +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 + 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) + end +end +''' +payload = ''' +SMODS.drawn_cards = {} +''' +[[patches]] +[patches.pattern] +target = 'functions/state_events.lua' +match_indent = true +position = 'after' +pattern = ''' +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 + 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) + end +end +''' +payload = ''' +G.E_MANAGER:add_event(Event({ + trigger = 'before', + delay = 0.4, + func = function() + if #SMODS.drawn_cards > 0 then + SMODS.calculate_context({first_hand_drawn = not G.GAME.current_round.any_hand_drawn and G.GAME.facing_blind, + hand_drawn = G.GAME.facing_blind and SMODS.drawn_cards, + other_drawn = not G.GAME.facing_blind and SMODS.drawn_cards}) + SMODS.drawn_cards = {} + if G.GAME.facing_blind then G.GAME.current_round.any_hand_drawn = true end + end + return true + end +})) +''' + +# Used to identify first hand of round +# new_round +[[patches]] +[patches.pattern] +target = 'functions/state_events.lua' +match_indent = true +position = 'after' +pattern = 'G.GAME.current_round.discards_used = 0' +payload = ''' +G.GAME.current_round.any_hand_drawn = nil +''' + + +# context.using_consumeable +[[patches]] +[patches.pattern] +target = 'functions/button_callbacks.lua' +pattern = ''' + for i = 1, #G.jokers.cards do + G.jokers.cards[i]:calculate_joker({using_consumeable = true, consumeable = card}) + end +''' +position = 'at' +match_indent = true +payload = ''' +SMODS.calculate_context({using_consumeable = true, consumeable = card, area = card.from_area}) +''' +# save area of used card +[[patches]] +[patches.pattern] +target = 'functions/button_callbacks.lua' +match_indent = true +position = 'before' +pattern = ''' +c1.area:remove_card(c1) +''' +payload = ''' +c1.from_area = c1.area +''' + +# context.selling_card +[[patches]] +[patches.pattern] +target = 'functions/button_callbacks.lua' +pattern = ''' + for i = 1, #G.jokers.cards do + if G.jokers.cards[i] ~= card then + G.jokers.cards[i]:calculate_joker({selling_card = true, card = card}) + end + end +''' +position = 'at' +match_indent = true +payload = ''' +SMODS.calculate_context({selling_card = true, card = card}) +''' + + +# context.buying_card +[[patches]] +[patches.pattern] +target = 'functions/button_callbacks.lua' +pattern = ''' +G.E_MANAGER:add_event(Event({func = function() c1:calculate_joker({buying_card = true, card = c1}) return true end})) +''' +position = 'at' +match_indent = true +payload = ''' +G.E_MANAGER:add_event(Event({func = function() + local eval, post = eval_card(c1, {buying_card = true, card = c1}) + SMODS.trigger_effects({eval, post}, c1) + return true + end})) +''' + +# context.buying_card +[[patches]] +[patches.pattern] +target = 'functions/button_callbacks.lua' +pattern = ''' + for i = 1, #G.jokers.cards do + G.jokers.cards[i]:calculate_joker({buying_card = true, card = c1}) + end +''' +position = 'at' +match_indent = true +payload = ''' +SMODS.calculate_context({buying_card = true, card = c1}) +''' +# context.starting_shop +[[patches]] +[patches.pattern] +target = 'game.lua' +pattern = ''' +G.CONTROLLER:snap_to({node = G.shop:get_UIE_by_ID('next_round_button')}) +''' +position = 'before' +match_indent = true +payload = ''' +if not nosave_shop then SMODS.calculate_context({starting_shop = true}) end +''' +# context.ending_shop +[[patches]] +[patches.pattern] +target = 'functions/button_callbacks.lua' +pattern = ''' + for i = 1, #G.jokers.cards do + G.jokers.cards[i]:calculate_joker({ending_shop = true}) + end +''' +position = 'at' +match_indent = true +payload = ''' +SMODS.calculate_context({ending_shop = true}) +''' + +# context.skipping_booster +[[patches]] +[patches.pattern] +target = 'functions/button_callbacks.lua' +pattern = ''' + for i = 1, #G.jokers.cards do + G.jokers.cards[i]:calculate_joker({skipping_booster = true}) + end +''' +position = 'at' +match_indent = true +payload = ''' +SMODS.calculate_context({skipping_booster = true, booster = booster_obj}) +''' +# context.skip_blind +[[patches]] +[patches.pattern] +target = 'functions/button_callbacks.lua' +pattern = ''' + for i = 1, #G.jokers.cards do + G.jokers.cards[i]:calculate_joker({skip_blind = true}) + end +''' +position = 'at' +match_indent = true +payload = ''' +SMODS.calculate_context({skip_blind = true}) +''' + +# context.reroll_shop +[[patches]] +[patches.pattern] +target = 'functions/button_callbacks.lua' +pattern = ''' + for i = 1, #G.jokers.cards do + G.jokers.cards[i]:calculate_joker({reroll_shop = true}) + end +''' +position = 'at' +match_indent = true +payload = ''' +SMODS.calculate_context({reroll_shop = true, cost = reroll_cost}) +''' +# reroll_cost for context +[[patches]] +[patches.pattern] +target = 'functions/button_callbacks.lua' +match_indent = true +position = 'before' +pattern = ''' +if G.GAME.current_round.reroll_cost > 0 then +''' +payload = ''' +local reroll_cost = G.GAME.current_round.reroll_cost +''' + + + +# Fix purple seal calc +[[patches]] +[patches.pattern] +target = 'card.lua' +pattern = ''' +if context.discard then + if self.seal == 'Purple' and #G.consumeables.cards + G.GAME.consumeable_buffer < G.consumeables.config.card_limit then''' +position = 'at' +match_indent = true +payload = ''' +if context.discard and context.other_card == self then + if self.seal == 'Purple' and #G.consumeables.cards + G.GAME.consumeable_buffer < G.consumeables.config.card_limit then''' + +# Fix context.blueprint persisting +[[patches]] +[patches.pattern] +target = 'card.lua' +match_indent = true +position = 'after' +pattern = 'local other_joker_ret = other_joker:calculate_joker(context)' +payload = ''' +context.blueprint = nil +local eff_card = context.blueprint_card or self +context.blueprint_card = nil''' + +[[patches]] +[patches.pattern] +target = 'card.lua' +match_indent = true +position = 'at' +pattern = 'other_joker_ret.card = context.blueprint_card or self' +payload = '''other_joker_ret.card = eff_card''' + +# Auto deal with negative chips card_eval_status_text() +[[patches]] +[patches.pattern] +target = 'functions/common_events.lua' +match_indent = true +position = 'at' +pattern = ''' +text = localize{type='variable',key='a_chips',vars={amt}} +''' +payload = ''' +text = localize{type='variable',key='a_chips'..(amt<0 and '_minus' or ''),vars={math.abs(amt)}} +''' + +# Auto deal with negative mult card_eval_status_text() +[[patches]] +[patches.pattern] +target = 'functions/common_events.lua' +match_indent = true +position = 'at' +pattern = ''' +text = localize{type='variable',key='a_mult',vars={amt}} +''' +payload = ''' +text = localize{type='variable',key='a_mult'..(amt<0 and '_minus' or ''),vars={math.abs(amt)}} +''' + +# Auto deal with negative xmult card_eval_status_text() +[[patches]] +[patches.pattern] +target = 'functions/common_events.lua' +match_indent = true +position = 'at' +pattern = ''' +text = localize{type='variable',key='a_xmult',vars={amt}} +''' +payload = ''' +text = localize{type='variable',key='a_xmult'..(amt<0 and '_minus' or ''),vars={math.abs(amt)}} +''' +# Make percent and percent_delta globals +[[patches]] +[patches.pattern] +target = 'functions/state_events.lua' +match_indent = true +position = 'at' +pattern = '''local percent = 0.3 +local percent_delta = 0.08 +''' +payload = '''percent = 0.3 +percent_delta = 0.08 +''' + +[[patches]] +[patches.pattern] +target = 'functions/state_events.lua' +match_indent = true +position = 'at' +pattern = '''local percent = (i-0.999)/(#G.hand.cards-0.998) + (j-1)*0.1''' +payload = '''percent = (i-0.999)/(#G.hand.cards-0.998) + (j-1)*0.1''' + +# Add support for pitch and volume returns in effects +[[patches]] +[patches.pattern] +target = 'functions/common_events.lua' +match_indent = true +position = 'after' +pattern = ''' +volume = extra.edition and 0.3 or sound == 'multhit2' and 0.7 or 1 +''' +payload = ''' +sound = extra.sound or sound +percent = extra.pitch or percent +volume = extra.volume or volume +''' + +# Voucher cardarea +[[patches]] +[patches.pattern] +target = 'game.lua' +match_indent = true +position = 'before' +pattern = 'self.deck = CardArea(' +payload = '''self.vouchers = CardArea( + G.discard.T.x, G.discard.T.y, + G.discard.T.w, G.discard.T.h, + { type = "discard", card_limit = 1e308 } +) +''' + +[[patches]] +[patches.pattern] +target = 'card.lua' +match_indent = true +position = 'after' +pattern = 'function Card:apply_to_run(center)' +payload = ''' + local card_to_save = self and copy_card(self) or Card(0, 0, G.CARD_W, G.CARD_H, G.P_CARDS.empty, center) + card_to_save.VT.x, card_to_save.VT.y = G.vouchers.T.x, G.vouchers.T.y + G.vouchers:emplace(card_to_save) + SMODS.enh_cache:clear() +''' + +[[patches]] +[patches.pattern] +target = 'card.lua' +position = 'at' +match_indent = false +pattern = '''if self.ability.set == "Planet" and not self.debuff then + if context.joker_main then + if G.GAME.used_vouchers.v_observatory and self.ability.consumeable.hand_type == context.scoring_name then + return { + message = localize{type = 'variable', key = 'a_xmult', vars = {G.P_CENTERS.v_observatory.config.extra}}, + Xmult_mod = G.P_CENTERS.v_observatory.config.extra + } + end + end +end''' +payload = '' + +[[patches]] +[patches.regex] +target = 'back.lua' +position = 'at' +line_prepend = '$indent' +pattern = '(?[\t ]*)(?Card.apply_to_run\(nil, G\.P_CENTERS\[.*?\]\))' +payload = '''G.E_MANAGER:add_event(Event({ + func = function() + $line + return true + end +}))''' + +#wtf +[[patches]] +[patches.pattern] +target = 'card.lua' +match_indent = true +position = 'at' +pattern = '''self.discard_pos = { + r = 3.6*(math.random()-0.5), + x = math.random(), + y = math.random() +}''' +payload = '''self.discard_pos = { + r = 0, + x = 0, + y = 0, +} +''' + +# xchip support +[[patches]] +[patches.pattern] +target = 'functions/common_events.lua' +match_indent = true +position = 'before' +pattern = ''' +elseif (eval_type == 'x_mult') or (eval_type == 'h_x_mult') then +''' +payload = ''' +elseif eval_type == 'x_chips' then + sound = 'xchips' + volume = 0.7 + amt = amt + text = localize{type='variable',key='a_xchips'..(amt<0 and '_minus' or ''),vars={math.abs(amt)}} + colour = G.C.BLUE + config.type = 'fade' + config.scale = 0.7 +''' +[[patches]] +[patches.pattern] +target = 'functions/common_events.lua' +match_indent = true +position = 'at' +pattern = ''' +if extra.chip_mod then +''' +payload = ''' +if extra.chip_mod or extra.Xchip_mod then +''' + +# Modify scoring hand context +[[patches]] +[patches.pattern] +target = 'functions/state_events.lua' +match_indent = true +position = 'at' +pattern = ''' +--Add all the pure bonus cards to the scoring hand +local pures = {} +for i=1, #G.play.cards do + if next(find_joker('Splash')) then + scoring_hand[i] = G.play.cards[i] + else + if G.play.cards[i].ability.effect == 'Stone Card' then + local inside = false + for j=1, #scoring_hand do + if scoring_hand[j] == G.play.cards[i] then + inside = true + end + end + if not inside then table.insert(pures, G.play.cards[i]) end + end + end +end +for i=1, #pures do + table.insert(scoring_hand, pures[i]) +end +table.sort(scoring_hand, function (a, b) return a.T.x < b.T.x end ) +''' +payload = ''' +local final_scoring_hand = {} +for i=1, #G.play.cards do + local splashed = SMODS.always_scores(G.play.cards[i]) or next(find_joker('Splash')) + local unsplashed = SMODS.never_scores(G.play.cards[i]) + if not splashed then + for _, card in pairs(scoring_hand) do + if card == G.play.cards[i] then splashed = true end + end + end + local effects = {} + SMODS.calculate_context({modify_scoring_hand = true, other_card = G.play.cards[i], full_hand = G.play.cards, scoring_hand = scoring_hand}, effects) + local flags = SMODS.trigger_effects(effects, G.play.cards[i]) + if flags.add_to_hand then splashed = true end + if flags.remove_from_hand then unsplashed = true end + if splashed and not unsplashed then table.insert(final_scoring_hand, G.play.cards[i]) end +end +-- TARGET: adding to hand effects +scoring_hand = final_scoring_hand +''' + +# Add ending_booster calculation context +[[patches]] +[patches.pattern] +target = 'functions/button_callbacks.lua' +match_indent = true +position = 'before' +pattern = ''' +for i = 1, #G.GAME.tags do + if G.GAME.tags[i]:apply_to_run({type = 'new_blind_choice'}) then break end +end + +G.E_MANAGER:add_event(Event({trigger = 'after',delay = 0.2*delayfac, + func = function() + save_run() + return true + end})) +''' +payload = ''' +SMODS.calculate_context({ending_booster = true, booster = booster_obj}) +''' + +# Fix playing_card_added jank +[[patches]] +[patches.pattern] +target = 'card.lua' +match_indent = true +position = 'at' +pattern = ''' +G.E_MANAGER:add_event(Event({ + func = function() + local _card = create_playing_card({ + front = pseudorandom_element(G.P_CARDS, pseudoseed('cert_fr')), + center = G.P_CENTERS.c_base}, G.hand, nil, nil, {G.C.SECONDARY_SET.Enhanced}) + local seal_type = pseudorandom(pseudoseed('certsl')) + if seal_type > 0.75 then _card:set_seal('Red', true) + elseif seal_type > 0.5 then _card:set_seal('Blue', true) + elseif seal_type > 0.25 then _card:set_seal('Gold', true) + else _card:set_seal('Purple', true) + end + G.GAME.blind:debuff_card(_card) + G.hand:sort() + if context.blueprint_card then context.blueprint_card:juice_up() else self:juice_up() end + return true + end})) + +playing_card_joker_effects({true}) +''' +payload = ''' +local _card = create_playing_card({ + front = pseudorandom_element(G.P_CARDS, pseudoseed('cert_fr')), + center = G.P_CENTERS.c_base}, G.discard, true, nil, {G.C.SECONDARY_SET.Enhanced}, true) +local seal_type = pseudorandom(pseudoseed('certsl')) +if seal_type > 0.75 then _card:set_seal('Red', true) +elseif seal_type > 0.5 then _card:set_seal('Blue', true) +elseif seal_type > 0.25 then _card:set_seal('Gold', true) +else _card:set_seal('Purple', true) +end +G.E_MANAGER:add_event(Event({ + func = function() + G.hand:emplace(_card) + _card:start_materialize() + G.GAME.blind:debuff_card(_card) + G.hand:sort() + if context.blueprint_card then context.blueprint_card:juice_up() else self:juice_up() end + return true + end})) +playing_card_joker_effects({_card}) + +''' +# create_playing_card +[[patches]] +[patches.pattern] +target = 'functions/common_events.lua' +match_indent = true +position = 'at' +pattern = ''' +function create_playing_card(card_init, area, skip_materialize, silent, colours) +''' +payload = ''' +function create_playing_card(card_init, area, skip_materialize, silent, colours, skip_emplace) +''' +[[patches]] +[patches.pattern] +target = 'functions/common_events.lua' +match_indent = true +position = 'at' +pattern = ''' +if area then area:emplace(card) end +''' +payload = ''' +if area and not skip_emplace then area:emplace(card) end +''' + +# Marble Joker +[[patches]] +[patches.pattern] +target = 'card.lua' +match_indent = true +position = 'at' +pattern = ''' +G.E_MANAGER:add_event(Event({ + func = function() + local front = pseudorandom_element(G.P_CARDS, pseudoseed('marb_fr')) + G.playing_card = (G.playing_card and G.playing_card + 1) or 1 + local card = Card(G.play.T.x + G.play.T.w/2, G.play.T.y, G.CARD_W, G.CARD_H, front, G.P_CENTERS.m_stone, {playing_card = G.playing_card}) + card:start_materialize({G.C.SECONDARY_SET.Enhanced}) + G.play:emplace(card) + table.insert(G.playing_cards, card) + return true + end})) +card_eval_status_text(context.blueprint_card or self, 'extra', nil, nil, nil, {message = localize('k_plus_stone'), colour = G.C.SECONDARY_SET.Enhanced}) + +G.E_MANAGER:add_event(Event({ + func = function() + G.deck.config.card_limit = G.deck.config.card_limit + 1 + return true + end})) + draw_card(G.play,G.deck, 90,'up', nil) + +playing_card_joker_effects({true}) +''' +payload = ''' +local front = pseudorandom_element(G.P_CARDS, pseudoseed('marb_fr')) +G.playing_card = (G.playing_card and G.playing_card + 1) or 1 +local card = Card(G.discard.T.x + G.discard.T.w/2, G.discard.T.y, G.CARD_W, G.CARD_H, front, G.P_CENTERS.m_stone, {playing_card = G.playing_card}) +G.E_MANAGER:add_event(Event({ + func = function() + card:start_materialize({G.C.SECONDARY_SET.Enhanced}) + G.play:emplace(card) + table.insert(G.playing_cards, card) + return true + end})) +card_eval_status_text(context.blueprint_card or self, 'extra', nil, nil, nil, {message = localize('k_plus_stone'), colour = G.C.SECONDARY_SET.Enhanced}) + +G.E_MANAGER:add_event(Event({ + func = function() + G.deck.config.card_limit = G.deck.config.card_limit + 1 + return true + end})) + draw_card(G.play,G.deck, 90,'up', nil) + +playing_card_joker_effects({card}) +''' + +## Remove unneeded area check +# Card:calculate_joker +[[patches]] +[patches.pattern] +target = 'card.lua' +match_indent = true +position = 'at' +pattern = 'if context.cardarea == G.jokers then' +payload = 'do' + +[[patches]] +[patches.regex] +target = 'game.lua' +position = 'at' +pattern = 'G.GAME.blind:get_loc_debuff_text\(\)' +payload = 'SMODS.debuff_text or G.GAME.blind:get_loc_debuff_text()' \ No newline at end of file diff --git a/Steamodded/lovely/blind.toml b/Steamodded/lovely/blind.toml new file mode 100644 index 0000000..4ec899e --- /dev/null +++ b/Steamodded/lovely/blind.toml @@ -0,0 +1,467 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = -10 + +### Blind API + +## Set debuffed_by_blind, use it for Matador behavior +## Blind:debuff_card() +[[patches]] +[patches.pattern] +target = 'blind.lua' +pattern = 'card:set_debuff(true)' +position = 'after' +payload = "if card.debuff then card.debuffed_by_blind = true end" +match_indent = true +[[patches]] +[patches.regex] +target = 'blind.lua' +pattern = 'card:set_debuff\(true\); return end' +position = 'at' +payload = """ +card:set_debuff(true); if card.debuff then card.debuffed_by_blind = true end; return end""" + +## Card:set_debuff() +[[patches]] +[patches.regex] +target = 'card.lua' +pattern = ''' +self\.debuff = should_debuff +(?[\t ]*)end +''' +position = 'after' +payload = """if not self.debuff then self.debuffed_by_blind = false end + +""" +line_prepend = '$indent' + +## Blind functions + +# Blind:set_blind() +[[patches]] +[patches.pattern] +target = 'blind.lua' +pattern = "G.GAME.last_blind = G.GAME.last_blind or {}" +position = 'before' +match_indent = true +payload = ''' +local obj = self.config.blind +self.children.animatedSprite.atlas = G.ANIMATION_ATLAS[obj.atlas] or G.ANIMATION_ATLAS['blind_chips']''' + +[[patches]] +[patches.pattern] +target = 'blind.lua' +pattern = "if self.name == 'The Eye' and not reset then" +position = 'at' +payload = ''' +if blind then + self.in_blind = true +end +local obj = self.config.blind +if not reset and obj.set_blind and type(obj.set_blind) == 'function' then + obj:set_blind() +elseif self.name == 'The Eye' and not reset then''' +match_indent = true + +# Blind:disable() +[[patches]] +[patches.pattern] +target = 'blind.lua' +pattern = "if self.name == 'The Water' then" +position = 'before' +match_indent = true +payload = ''' +local obj = self.config.blind +if obj.disable and type(obj.disable) == 'function' then + obj:disable() +end''' + +# Blind:defeat() +[[patches]] +[patches.pattern] +target = 'blind.lua' +pattern = "if self.name == 'The Manacle' and not self.disabled then" +position = 'before' +match_indent = true +payload = ''' +local obj = self.config.blind +if obj.defeat and type(obj.defeat) == 'function' then + obj:defeat() +end''' + +# Blind:debuff_card() +[[patches]] +[patches.pattern] +target = 'blind.lua' +pattern = "if self.debuff and not self.disabled and card.area ~= G.jokers then" +position = 'before' +match_indent = true +payload = ''' +local obj = self.config.blind +if not self.disabled and obj.recalc_debuff and type(obj.recalc_debuff) == 'function' then + if obj:recalc_debuff(card, from_blind) then + card:set_debuff(true) + if card.debuff then card.debuffed_by_blind = true end + else + card:set_debuff(false) + end + return +elseif not self.disabled and obj.debuff_card and type(obj.debuff_card) == 'function' then + sendWarnMessage(("Blind object %s has debuff_card function, recalc_debuff is preferred"):format(obj.key), obj.set) + if obj:debuff_card(card, from_blind) then + card:set_debuff(true) + if card.debuff then card.debuffed_by_blind = true end + else + card:set_debuff(false) + end + return +end''' + +# Blind:stay_flipped() + +[[patches]] +[patches.pattern] +target = 'blind.lua' +pattern = "function Blind:stay_flipped(area, card)" +position = 'at' +match_indent = true +payload = '''function Blind:stay_flipped(area, card, from_area)''' + +[[patches]] +[patches.pattern] +target = 'blind.lua' +pattern = "if area == G.hand then" +position = 'before' +match_indent = true +payload = ''' +local obj = self.config.blind +if obj.stay_flipped and type(obj.stay_flipped) == 'function' then + return obj:stay_flipped(area, card, from_area) +end''' + + +[[patches]] +[patches.pattern] +target = 'cardarea.lua' +pattern = "local stay_flipped = G.GAME and G.GAME.blind and G.GAME.blind:stay_flipped(self, card)" +position = 'at' +match_indent = true +payload = '''local stay_flipped = G.GAME and G.GAME.blind and G.GAME.blind:stay_flipped(self, card, area)''' + +[[patches]] +[patches.pattern] +target = 'functions/common_events.lua' +pattern = "local stay_flipped = G.GAME and G.GAME.blind and G.GAME.blind:stay_flipped(to, card)" +position = 'at' +match_indent = true +payload = '''local stay_flipped = G.GAME and G.GAME.blind and G.GAME.blind:stay_flipped(to, card, from)''' + +# Blind:drawn_to_hand() +[[patches]] +[patches.regex] +target = 'blind.lua' +pattern = "(?[\t ]*)if self.name == 'Cerulean Bell' then\n" +position = 'before' +line_prepend = '$indent' +payload = ''' +local obj = self.config.blind +if obj.drawn_to_hand and type(obj.drawn_to_hand) == 'function' then + obj:drawn_to_hand() +end +''' + +# Blind:debuff_hand() +[[patches]] +[patches.pattern] +target = 'blind.lua' +pattern = "if self.debuff then" +position = 'before' +match_indent = true +payload = ''' +local obj = self.config.blind +if obj.debuff_hand and type(obj.debuff_hand) == 'function' then + return obj:debuff_hand(cards, hand, handname, check) +end''' + +# Blind:modify_hand() +[[patches]] +[patches.pattern] +target = 'blind.lua' +pattern = "if self.disabled then return mult, hand_chips, false end" +position = 'after' +match_indent = true +payload = ''' +local obj = self.config.blind +if obj.modify_hand and type(obj.modify_hand) == 'function' then + return obj:modify_hand(cards, poker_hands, text, mult, hand_chips) +end''' + +[[patches]] +[patches.pattern] +target = 'blind.lua' +pattern = "function Blind:modify_hand(cards, poker_hands, text, mult, hand_chips)" +position = 'at' +match_indent = true +payload = '''function Blind:modify_hand(cards, poker_hands, text, mult, hand_chips, scoring_hand)''' + +[[patches]] +[patches.pattern] +target = 'functions/state_events.lua' +pattern = "mult, hand_chips, modded = G.GAME.blind:modify_hand(G.play.cards, poker_hands, text, mult, hand_chips)" +position = 'at' +match_indent = true +payload = '''mult, hand_chips, modded = G.GAME.blind:modify_hand(G.play.cards, poker_hands, text, mult, hand_chips, scoring_hand)''' + +# Blind:press_play() +[[patches]] +[patches.pattern] +target = 'blind.lua' +pattern = 'if self.name == "The Hook" then' +position = 'before' +match_indent = true +payload = ''' +local obj = self.config.blind +if obj.press_play and type(obj.press_play) == 'function' then + return obj:press_play() +end''' + +# Blind:get_loc_debuff_text() +[[patches]] +[patches.pattern] +target = 'blind.lua' +pattern = 'function Blind:get_loc_debuff_text()' +position = 'after' +match_indent = true +payload = ''' + local obj = self.config.blind + if obj.get_loc_debuff_text and type(obj.get_loc_debuff_text) == 'function' then + return obj:get_loc_debuff_text() + end''' + +# Blind:set_text() +[[patches]] +[patches.pattern] +target = 'blind.lua' +pattern = "local loc_target = localize{type = 'raw_descriptions', key = self.config.blind.key, set = 'Blind', vars = loc_vars or self.config.blind.vars}" +position = 'at' +match_indent = true +payload = ''' +local target = {type = 'raw_descriptions', key = self.config.blind.key, set = 'Blind', vars = loc_vars or self.config.blind.vars} +local obj = self.config.blind +if obj.loc_vars and type(obj.loc_vars) == 'function' then + local res = obj:loc_vars() or {} + target.vars = res.vars or target.vars + target.key = res.key or target.key +end +local loc_target = localize(target)''' + +# Blind:load() +[[patches]] +[patches.pattern] +target = 'blind.lua' +pattern = 'if G.P_BLINDS[blindTable.config_blind] then' +position = 'after' +match_indent = true +payload = ''' +if self.config.blind.atlas then + self.children.animatedSprite.atlas = G.ANIMATION_ATLAS[self.config.blind.atlas] +end''' + + +# create_UIBox_blind_choice() +# create_UIBox_round_scores_row() +[[patches]] +[patches.regex] +target = 'functions/UI_definitions.lua' +pattern = "(?[\t ]*)blind_choice.animation = AnimatedSprite\\(0,0, 1.4, 1.4, (?G.ANIMATION_ATLAS\\['blind_chips'\\]), blind_choice.config.pos\\)" +position = 'at' +root_capture = 'atlas' +payload = "G.ANIMATION_ATLAS[blind_choice.config.atlas] or G.ANIMATION_ATLAS['blind_chips']" + +# create_UIBox_your_collection_blinds() +[[patches]] +[patches.regex] +target = 'functions/UI_definitions.lua' +pattern = "(?[\t ]*)local temp_blind = AnimatedSprite\\(0,0,1.3,1.3, G.ANIMATION_ATLAS\\['blind_chips'\\], discovered and v.pos or G.b_undiscovered.pos\\)" +position = 'at' +payload = ''' + +local s = 1.3 +if math.ceil(#blind_tab/6) > 6 then + s = s * 6/math.ceil(#blind_tab/6) +end +local temp_blind = AnimatedSprite(0,0,s,s, G.ANIMATION_ATLAS[discovered and v.atlas or 'blind_chips'], discovered and v.pos or G.b_undiscovered.pos)''' +line_prepend = '$indent' + +[[patches]] +[patches.pattern] +target = 'functions/UI_definitions.lua' +pattern = 'blind_matrix[math.ceil((k-1)/5+0.001)][1+((k-1)%5)] = {n=G.UIT.C, config={align = "cm", padding = 0.1}, nodes={' +match_indent = true +position = 'at' +payload = ''' +local blinds_per_row = math.ceil(#blind_tab / 6) +local row = math.ceil((k - 1) / blinds_per_row + 0.001) +table.insert(blind_matrix[row], { + n = G.UIT.C, + config = { align = "cm", padding = 0.1 }, + nodes = { + ((k - blinds_per_row) % (2 * blinds_per_row) == 1) and { n = G.UIT.B, config = { h = 0.2, w = 0.5 } } or nil, + { n = G.UIT.O, config = { object = temp_blind, focus_with_object = true } }, + ((k - blinds_per_row) % (2 * blinds_per_row) == 0) and { n = G.UIT.B, config = { h = 0.2, w = 0.5 } } or nil, + } +})''' + +[[patches]] +[patches.regex] +target = 'functions/UI_definitions.lua' +pattern = '[\t ]*\(k==6 or k ==16 or k == 26\) and \{n=G.UIT.B, config=\{h=0.2,w=0.5\}\} or nil,\n[\t ]*\{n=G.UIT.O, config=\{object = temp_blind, focus_with_object = true\}\},\n[\t ]*\(k==5 or k ==15 or k == 25\) and \{n=G.UIT.B, config=\{h=0.2,w=0.5\}\} or nil,\n[\t ]*\}\}' +position = 'at' +payload = '' + +[[patches]] +[patches.pattern] +target = 'functions/UI_definitions.lua' +pattern = 'table.sort(blind_tab, function (a, b) return a.order < b.order end)' +match_indent = true +position = 'at' +payload = ''' +table.sort(blind_tab, function(a, b) return a.order + (a.boss and a.boss.showdown and 1000 or 0) < b.order + (b.boss and b.boss.showdown and 1000 or 0) end)''' + +# add_round_eval_row() +[[patches]] +[patches.pattern] +target = 'functions/common_events.lua' +pattern = "local blind_sprite = AnimatedSprite(0, 0, 1.2,1.2, G.ANIMATION_ATLAS['blind_chips'], copy_table(G.GAME.blind.pos))" +match_indent = true +position = 'at' +payload = ''' +local obj = G.GAME.blind.config.blind +local blind_sprite = AnimatedSprite(0, 0, 1.2, 1.2, G.ANIMATION_ATLAS[obj.atlas] or G.ANIMATION_ATLAS['blind_chips'], copy_table(G.GAME.blind.pos))''' + +# display blind descriptions in info_queue +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = "elseif _c.set == 'Tarot' then" +position = "before" +match_indent = true +payload = '''elseif _c.set == 'Blind' then + local coll_loc_vars = (_c.collection_loc_vars and type(_c.collection_loc_vars) == 'function' and _c:collection_loc_vars()) or {} + loc_vars = coll_loc_vars.vars or _c.vars + localize{type = 'descriptions', key = coll_loc_vars.key or _c.key, set = _c.set, nodes = desc_nodes, vars = loc_vars} +''' + +# create_UIBox_blind_choice() +[[patches]] +[patches.pattern] +target = 'functions/UI_definitions.lua' +pattern = "local loc_target = localize{type = 'raw_descriptions', key = blind_choice.config.key, set = 'Blind', vars = {localize(G.GAME.current_round.most_played_poker_hand, 'poker_hands')}}" +match_indent = true +position = 'at' +payload = ''' +local target = {type = 'raw_descriptions', key = blind_choice.config.key, set = 'Blind', vars = {}} +if blind_choice.config.name == 'The Ox' then + target.vars = {localize(G.GAME.current_round.most_played_poker_hand, 'poker_hands')} +end +local obj = blind_choice.config +if obj.loc_vars and _G['type'](obj.loc_vars) == 'function' then + local res = obj:loc_vars() or {} + target.vars = res.vars or target.vars + target.key = res.key or target.key +end +local loc_target = localize(target)''' + +# create_UIBox_blind_popup() +[[patches]] +[patches.pattern] +target = 'functions/UI_definitions.lua' +pattern = '''local loc_target = localize{type = 'raw_descriptions', key = blind.key, set = 'Blind', vars = vars or blind.vars}''' +match_indent = true +position = 'at' +payload = ''' +local target = {type = 'raw_descriptions', key = blind.key, set = 'Blind', vars = vars or blind.vars} +if blind.collection_loc_vars and type(blind.collection_loc_vars) == 'function' then + local res = blind:collection_loc_vars() or {} + target.vars = res.vars or target.vars + target.key = res.key or target.key +end +local loc_target = localize(target)''' + +# get_new_boss() +[[patches]] +[patches.pattern] +target = 'functions/common_events.lua' +pattern = 'elseif not v.boss.showdown*' +match_indent = true +position = 'before' +payload = ''' +elseif v.in_pool and type(v.in_pool) == 'function' then + local res, options = v:in_pool() + if + ( + ((G.GAME.round_resets.ante)%G.GAME.win_ante == 0 and G.GAME.round_resets.ante >= 2) == + (v.boss.showdown or false) + ) or + (options or {}).ignore_showdown_check + then + eligible_bosses[k] = res and true or nil + end''' + +# G.UIDEF.challenge_description_tab +[[patches]] +[patches.pattern] +target = 'functions/UI_definitions.lua' +pattern = "local temp_blind = AnimatedSprite(0,0,1,1, G.ANIMATION_ATLAS['blind_chips'], v.pos)" +position = 'at' +match_indent = true +payload = "local temp_blind = AnimatedSprite(0,0,1,1, G.ANIMATION_ATLAS[v.atlas or ''] or G.ANIMATION_ATLAS['blind_chips'], v.pos)" + +## elseif-ify some if chains +[[patches]] +[patches.regex] +target = 'blind.lua' +pattern = "end\n(?[\t ]*)if self.name == ['\"](?.*?)['\"]" +position = 'at' +payload = "elseif self.name == '$ability'" + +# revert the change for The Pillar +[[patches]] +[patches.regex] +target = 'blind.lua' +pattern = "(?[\t ]*)elseif self.name == 'The Pillar' and card.ability.played_this_ante then" +position = 'at' +line_prepend = '$indent' +payload = '''end +if self.name == 'The Pillar' and card.ability.played_this_ante then''' + +# revert the change for The Eye in debuff_hand +[[patches]] +[patches.regex] +target = 'blind.lua' +pattern = "(?[\t ]*)elseif self.name == 'The Eye' then" +position = 'at' +line_prepend = '$indent' +payload = '''end +if self.name == 'The Eye' then''' + +# revert the change for The Arm in debuff_hand +[[patches]] +[patches.regex] +target = 'blind.lua' +pattern = "(?[\t ]*)elseif self.name == 'The Arm' then" +position = 'at' +line_prepend = '$indent' +payload = '''end +if self.name == 'The Arm' then''' + +# revert the change for Crimson Heart in debuff_card +[[patches]] +[patches.regex] +target = 'blind.lua' +pattern = '''(?[\t ]*)elseif self\.name == 'Crimson Heart' and not self\.disabled''' +position = 'at' +line_prepend = '$indent' +payload = '''end +if self.name == 'Crimson Heart' and not self.disabled''' \ No newline at end of file diff --git a/Steamodded/lovely/blind_ui.toml b/Steamodded/lovely/blind_ui.toml new file mode 100644 index 0000000..d1dd83d --- /dev/null +++ b/Steamodded/lovely/blind_ui.toml @@ -0,0 +1,172 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = -10 + +### Allow blinds to have more than 2 lines + +# create_UIBox_blind_choice() +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +pattern = "if blind_state == 'Select' then blind_state = 'Current' end" +position = 'after' +payload = ''' +local blind_desc_nodes = {} +for k, v in ipairs(text_table) do + blind_desc_nodes[#blind_desc_nodes+1] = {n=G.UIT.R, config={align = "cm", maxw = 2.8}, nodes={ + {n=G.UIT.T, config={text = v or '-', scale = 0.32, colour = disabled and G.C.UI.TEXT_INACTIVE or G.C.WHITE, shadow = not disabled}} + }} +end''' +match_indent = true + +[[patches]] +[patches.regex] +target = "functions/UI_definitions.lua" +pattern = ''' +(?[\t ]*)text_table\[1\] and \{n=G\.UIT\.R, config=\{align = "cm", minh = 0\.7, padding = 0\.05, minw = 2\.9}, nodes=\{ +[\t ]* text_table\[1\] and \{n=G\.UIT\.R, config=\{align = "cm", maxw = 2\.8\}, nodes=\{ +[\t ]* \{n=G\.UIT\.T, config=\{id = blind_choice\.config\.key, ref_table = \{val = ''\}, ref_value = 'val', scale = 0\.32, colour = disabled and G\.C\.UI\.TEXT_INACTIVE or G\.C\.WHITE, shadow = not disabled, func = 'HUD_blind_debuff_prefix'\}\}, +[\t ]* \{n=G\.UIT\.T, config=\{text = text_table\[1\] or '\-', scale = 0\.32, colour = disabled and G\.C\.UI\.TEXT_INACTIVE or G\.C\.WHITE, shadow = not disabled\}\} +[\t ]* \}\} or nil, +[\t ]* text_table\[2\] and \{n=G\.UIT\.R, config=\{align = "cm", maxw = 2\.8\}, nodes=\{ +[\t ]* \{n=G\.UIT\.T, config=\{text = text_table\[2\] or '\-', scale = 0\.32, colour = disabled and G\.C\.UI\.TEXT_INACTIVE or G\.C\.WHITE, shadow = not disabled\}\} +[\t ]* \}\} or nil, +[\t ]*\}\} or nil,''' +position = "at" +payload = ''' +text_table[1] and {n=G.UIT.R, config={align = "cm", minh = 0.7, padding = 0.05, minw = 2.9}, nodes = blind_desc_nodes} or nil,''' +line_prepend = '$indent' + +# create_UIBox_HUD_blind() +# Padding and contained nodes are set in G.FUNCS.HUD_blind_debuff (overrides.lua) +[[patches]] +[patches.regex] +target = "functions/UI_definitions.lua" +pattern = ''' +(?[\t ]*)\{n=G\.UIT\.R, config=\{align = "cm", padding = 0\.05\}, nodes=\{ +[\t ]* \{n=G\.UIT\.R, config=\{align = "cm", minh = 0\.3, maxw = 4\.2\}, nodes=\{ +[\t ]* \{n=G\.UIT\.T, config=\{ref_table = \{val = ''\}, ref_value = 'val', scale = scale\*0\.9, colour = G\.C\.UI\.TEXT_LIGHT, func = 'HUD_blind_debuff_prefix'\}\}, +[\t ]* \{n=G\.UIT\.T, config=\{ref_table = G\.GAME\.blind\.loc_debuff_lines, ref_value = 1, scale = scale\*0\.9, colour = G\.C\.UI\.TEXT_LIGHT, id = 'HUD_blind_debuff_1', func = 'HUD_blind_debuff'\}\} +[\t ]* \}\}, +[\t ]* \{n=G\.UIT\.R, config=\{align = "cm", minh = 0\.3, maxw = 4\.2\}, nodes=\{ +[\t ]* \{n=G\.UIT\.T, config=\{ref_table = G\.GAME\.blind\.loc_debuff_lines, ref_value = 2, scale = scale\*0\.9, colour = G\.C\.UI\.TEXT_LIGHT, id = 'HUD_blind_debuff_2', func = 'HUD_blind_debuff'\}\} +[\t ]* \}\}, +[\t ]*\}\},''' +position = "at" +payload = ''' +{n=G.UIT.R, config={align = "cm", id = 'HUD_blind_debuff', func = 'HUD_blind_debuff'}, nodes={}},''' +line_prepend = '$indent' + +# Blind:set_text +[[patches]] +[patches.regex] +target = "blind.lua" +pattern = """ +(?[\t ]*)self\\.loc_debuff_lines\\[1\\] = '' +[\t ]*self\\.loc_debuff_lines\\[2\\] = ''""" +position = 'at' +payload = 'EMPTY(self.loc_debuff_lines)' +line_prepend = '$indent' + +[[patches]] +[patches.pattern] +target = "blind.lua" +pattern = "for k, v in ipairs(loc_target) do" +position = 'before' +payload = 'EMPTY(self.loc_debuff_lines)' +match_indent = true + +[[patches]] +[patches.pattern] +target = "blind.lua" +pattern = "self.loc_debuff_text = self.loc_debuff_text..v..(k <= #loc_target and ' ' or '')" +position = 'after' +payload = "self.loc_debuff_lines[k] = v" +match_indent = true + +[[patches]] +[patches.regex] +target = "blind.lua" +pattern = """ +(?[\t ]*)self\\.loc_debuff_lines\\[1\\] = loc_target\\[1\\] or '' +[\t ]*self\\.loc_debuff_lines\\[2\\] = loc_target\\[2\\] or '' +""" +position = 'at' +payload = '' + +## Add a box with h=3.64 (magic number equal to the height of HUD_blind) +## centered inside 'row_blind' +# create_UIBox_HUD +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +pattern = """{n=G.UIT.R, config={align = "cm", id = 'row_blind', minw = 1, minh = 3.75}, nodes={}},""" +position = 'at' +payload = """{n=G.UIT.R, config={align = "cm", id = 'row_blind', minw = 1, minh = 3.75}, nodes={ + {n=G.UIT.B, config={w=0, h=3.64, id = 'row_blind_bottom'}, nodes={}} +}},""" +match_indent = true + +## Blind UI's bottom edge is aligned to it +[[patches]] +[patches.pattern] +target = "game.lua" +pattern = "config = {major = G.HUD:get_UIE_by_ID('row_blind'), align = 'cm', offset = {x=0,y=-10}, bond = 'Weak'}" +position = 'at' +payload = "config = {major = G.HUD:get_UIE_by_ID('row_blind_bottom'), align = 'bmi', offset = {x=0,y=-10}, bond = 'Weak'}" +match_indent = true + +## Patch G.GAME.blind:juice_up() across all files + +[[patches]] +[patches.regex] +target = "functions/common_events.lua" +pattern = ''' +(?[\t ]*)G\.HUD_blind:get_UIE_by_ID\('HUD_blind_debuff_1'\):juice_up\(0\.3, 0\) +[\t ]*G\.HUD_blind:get_UIE_by_ID\('HUD_blind_debuff_2'\):juice_up\(0\.3, 0\) +[\t ]*G\.GAME\.blind:juice_up\(\)''' +position = 'at' +payload = 'SMODS.juice_up_blind()' +line_prepend = '$indent' + +[[patches]] +[patches.regex] +target = "functions/state_events.lua" +pattern = ''' +(?[\t ]*)G\.HUD_blind:get_UIE_by_ID\('HUD_blind_debuff_1'\):juice_up\(0\.3, 0\) +[\t ]*G\.HUD_blind:get_UIE_by_ID\('HUD_blind_debuff_2'\):juice_up\(0\.3, 0\) +[\t ]*G\.GAME\.blind:juice_up\(\)''' +position = 'at' +payload = 'SMODS.juice_up_blind()' +line_prepend = '$indent' + +[[patches]] +[patches.regex] +target = "functions/state_events.lua" +pattern = '''hand_chips = mod_chips\(0\)(\n.*)*?\n[\t ]*(?SMODS.juice_up_blind\(\))''' +position = 'at' +root_capture = 'juice' +payload = 'if SMODS.hand_debuff_source then SMODS.hand_debuff_source:juice_up(0.3,0) else SMODS.juice_up_blind() end' +times = 1 + +[[patches]] +[patches.pattern] +target = 'game.lua' +pattern = 'G.GAME.blind.children.animatedSprite:juice_up(0.05, 0.02)' +position = 'at' +match_indent = true +payload = '''if SMODS.hand_debuff_source then + SMODS.hand_debuff_source:juice_up(0.05, 0.1) +else + G.GAME.blind.children.animatedSprite:juice_up(0.05, 0.02) +end +''' + +# remove statically added 1 from The Wheel's collection description +[[patches]] +[patches.regex] +target = 'functions/UI_definitions.lua' +pattern = '''\(k ==1 and blind\.name == 'The Wheel' and '1' or ''\)\.\.''' +position = 'at' +payload = '' diff --git a/Steamodded/lovely/booster.toml b/Steamodded/lovely/booster.toml new file mode 100644 index 0000000..fd1af8a --- /dev/null +++ b/Steamodded/lovely/booster.toml @@ -0,0 +1,325 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = -10 + +## Booster Pack API + +# Card:open +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = ''' +if self.ability.name:find('Arcana') then + G.STATE = G.STATES.TAROT_PACK + G.GAME.pack_size = self.ability.extra + elseif self.ability.name:find('Celestial') then + G.STATE = G.STATES.PLANET_PACK + G.GAME.pack_size = self.ability.extra + elseif self.ability.name:find('Spectral') then + G.STATE = G.STATES.SPECTRAL_PACK + G.GAME.pack_size = self.ability.extra + elseif self.ability.name:find('Standard') then + G.STATE = G.STATES.STANDARD_PACK + G.GAME.pack_size = self.ability.extra + elseif self.ability.name:find('Buffoon') then + G.STATE = G.STATES.BUFFOON_PACK + G.GAME.pack_size = self.ability.extra + end + + G.GAME.pack_choices = self.config.center.config.choose or 1''' +match_indent = true +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 + SMODS.OPENED_BOOSTER = self +end +G.GAME.pack_choices = self.ability.choose or self.config.center.config.choose or 1 +""" + +# Card:open +[[patches]] +[patches.regex] +target = "card.lua" +pattern = '''(?[\t ]*)if self\.ability\.name:find\('Arcana'\) then[\t\n ]*if G\.GAME\.used_vouchers\.v_omen_globe and pseudorandom\('omen_globe'\) > 0\.8 then''' # Possibly try to target something else +position = "at" +payload = '''if booster_obj.create_card and type(booster_obj.create_card) == "function" then + local _card_to_spawn = booster_obj:create_card(self, i) + if type((_card_to_spawn or {}).is) == 'function' and _card_to_spawn:is(Card) then + card = _card_to_spawn + else + card = SMODS.create_card(_card_to_spawn) + end +elseif self.ability.name:find('Arcana') then + if G.GAME.used_vouchers.v_omen_globe and pseudorandom('omen_globe') > 0.8 then''' +line_prepend = '$indent' + +# Game:set_globals +[[patches]] +[patches.regex] +target = "globals.lua" +pattern = '''(?[\t ]*)self\.STATES = \{''' +position = "after" +payload = ''' + + SMODS_BOOSTER_OPENED = 999,''' +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]] +[patches.regex] +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''' + +# CardArea:draw() +[[patches]] +[patches.pattern] +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''' +match_indent = true + +# G.FUNCS.use_card +[[patches]] +[patches.pattern] +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''' +match_indent = true + +# CardArea:align_cards() +[[patches]] +[patches.pattern] +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" +match_indent = true + +# CardArea:align_cards() +[[patches]] +[patches.pattern] +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" +match_indent = true + +# Card:can_use_consumable() +[[patches]] +[patches.pattern] +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" +match_indent = true + +# G.FUNCS.use_card() +[[patches]] +[patches.pattern] +target = "functions/button_callbacks.lua" +pattern = "if G.STATE == G.STATES.TAROT_PACK or G.STATE == G.STATES.PLANET_PACK or G.STATE == G.STATES.SPECTRAL_PACK then" +position = "at" +payload = """ +if nc then + if area then area:remove_from_highlighted(card) end + 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""" +match_indent = true + +# G.FUNC.use_card() +[[patches]] +[patches.pattern] +target = "functions/button_callbacks.lua" +pattern = 'if area == G.consumeables then' +position = 'before' +match_indent = true +payload = ''' +if nc and area == G.pack_cards and not select_to then G.pack_cards:remove_card(card); G.consumeables:emplace(card) end''' + +# G.FUNC.use_card() +[[patches]] +[patches.pattern] +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''' + +# G.FUNC.use_card() +[[patches]] +[patches.pattern] +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''' + +# G.FUNC.use_card() +[[patches]] +[patches.pattern] +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" +match_indent = true + +# G.FUNC.use_card() +[[patches]] +[patches.pattern] +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" +match_indent = true + +# Card:use_consumeable() +[[patches]] +[patches.regex] +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},''' +line_prepend = '$indent' + +# G.FUNCS.use_card() +[[patches]] +[patches.pattern] +target = "functions/button_callbacks.lua" +pattern = "e.config.ref_table:redeem()" +position = "before" +payload = "if area == G.pack_cards then e.config.ref_table.cost = 0 end" +match_indent = true + +## Stopping ease_dollars anim from playing when voucher is free +# Card:redeem() +[[patches]] +[patches.regex] +target = "card.lua" +pattern = '''(?[\t ]*)ease_dollars\(-self\.cost\)\n[\s\S]{8}inc_career_stat\('c_shop_dollars_spent', self\.cost\)''' +position = "at" +payload = ''' +if self.cost ~= 0 then + ease_dollars(-self.cost) + inc_career_stat('c_shop_dollars_spent', self.cost) +end''' +line_prepend = '$indent' + +# Add support for saving consumables +# comment +[[patches]] +[patches.pattern] +target = 'functions/UI_definitions.lua' +match_indent = true +position = 'before' +pattern = ''' +if card.ability.consumeable then + if (card.area == G.pack_cards and G.pack_cards) then +''' +payload = ''' +if card.ability.consumeable and card.area == G.pack_cards and booster_obj and booster_obj.select_card and card:selectable_from_pack(booster_obj) then + if (card.area == G.pack_cards and G.pack_cards) then + return {n=G.UIT.ROOT, config = {padding = 0, colour = G.C.CLEAR}, nodes={ + {n=G.UIT.R, config={ref_table = card, r = 0.08, padding = 0.1, align = "bm", minw = 0.5*card.T.w - 0.15, maxw = 0.9*card.T.w - 0.15, minh = 0.3*card.T.h, hover = true, shadow = true, colour = G.C.UI.BACKGROUND_INACTIVE, one_press = true, button = 'use_card', func = 'can_select_from_booster'}, nodes={ + {n=G.UIT.T, config={text = localize('b_select'),colour = G.C.UI.TEXT_LIGHT, scale = 0.45, shadow = true}} + }}, + }} + end +end +''' + +# comment +[[patches]] +[patches.pattern] +target = 'functions/button_callbacks.lua' +match_indent = true +position = 'at' +pattern = ''' +if card.ability.consumeable then + if nc then +''' +payload = ''' +if select_to then + card:add_to_deck() + G[select_to]:emplace(card) + if card.config.center.on_select and type(card.config.center.on_select) == 'function' then + card.config.center:on_select(card) + end + play_sound('card1', 0.8, 0.6) + play_sound('generic1') + dont_dissolve = true + delay_fac = 0.2 +elseif card.ability.consumeable then + if nc then +''' +# comment +[[patches]] +[patches.pattern] +target = 'functions/button_callbacks.lua' +match_indent = true +position = 'before' +pattern = ''' +for i = 1, #G.GAME.tags do + if G.GAME.tags[i]:apply_to_run({type = 'new_blind_choice'}) then break end +end + +G.E_MANAGER:add_event(Event({trigger = 'after',delay = 0.2*delayfac, + func = function() + save_run() + return true + end})) +''' +payload = ''' +booster_obj = nil +''' +# comment +[[patches]] +[patches.pattern] +target = 'functions/button_callbacks.lua' +match_indent = true +position = 'before' +pattern = ''' +G.FUNCS.end_consumeable(e) +''' +payload = ''' +booster_obj = nil +''' + +# G.FUNCS.can_select_card +# Support negative-ish on Jokers +[[patches]] +[patches.pattern] +target = 'functions/button_callbacks.lua' +match_indent = true +position = 'at' +pattern = "if e.config.ref_table.ability.set ~= 'Joker' or (e.config.ref_table.edition and e.config.ref_table.edition.negative) or #G.jokers.cards < G.jokers.config.card_limit then" +payload = '''local card = e.config.ref_table +local card_limit = card.edition and card.edition.card_limit or 0 +if card.ability.set ~= 'Joker' or #G.jokers.cards < G.jokers.config.card_limit + card_limit then''' diff --git a/Steamodded/lovely/calculate_card_added.toml b/Steamodded/lovely/calculate_card_added.toml new file mode 100644 index 0000000..478067b --- /dev/null +++ b/Steamodded/lovely/calculate_card_added.toml @@ -0,0 +1,25 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = -5 + +# Add card_added context +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = '''if G.GAME.blind and G.GAME.blind.in_blind then G.E_MANAGER:add_event(Event({ func = function() G.GAME.blind:set_blind(nil, true, nil); return true end })) end''' +position = "after" +match_indent = true +payload = ''' +if not from_debuff and G.hand then + local is_playing_card = self.ability.set == 'Default' or self.ability.set == 'Enhanced' + + -- TARGET: calculate card_added + + if not is_playing_card then + SMODS.calculate_context({card_added = true, card = self}) + SMODS.enh_cache:clear() + end +end +''' +times = 1 diff --git a/Steamodded/lovely/can_calculate.toml b/Steamodded/lovely/can_calculate.toml new file mode 100644 index 0000000..3b2c01e --- /dev/null +++ b/Steamodded/lovely/can_calculate.toml @@ -0,0 +1,63 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = -5 + +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = '''function Card:get_end_of_round_effect(context) + if self.debuff then return {} end''' +position = "at" +match_indent = true +payload = ''' +function Card:get_end_of_round_effect(context)''' + +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = '''function Card:calculate_dollar_bonus() + if self.debuff then return end''' +position = "at" +match_indent = true +payload = ''' +function Card:calculate_dollar_bonus() + if not self:can_calculate() then return end''' + +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = '''function Card:calculate_seal(context) + if self.debuff then return nil end''' +position = "at" +match_indent = true +payload = ''' +function Card:calculate_seal(context)''' + +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = '''function Card:calculate_joker(context) + if self.debuff then return nil end''' +position = "at" +match_indent = true +payload = ''' +function Card:calculate_joker(context)''' + + +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = '''if self.ability.set == "Joker" and not self.debuff then''' +position = "at" +match_indent = true +payload = '''if self.ability.set == "Joker" then''' + + +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = '''if self.debuff then return 0 end''' +position = "at" +match_indent = true +payload = '' \ No newline at end of file diff --git a/Steamodded/lovely/center.toml b/Steamodded/lovely/center.toml new file mode 100644 index 0000000..e183c8e --- /dev/null +++ b/Steamodded/lovely/center.toml @@ -0,0 +1,538 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = -10 + +### Center API + +# Card:set_ability() +[[patches]] +[patches.regex] +target = "card.lua" +pattern = "(?[\t ]*)if not G\\.OVERLAY_MENU then \n" +position = 'before' +payload = ''' +local obj = self.config.center +if obj.set_ability and type(obj.set_ability) == 'function' then + obj:set_ability(self, initial, delay_sprites) +end + +''' +line_prepend = '$indent' +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "self.ability.bonus = (self.ability.bonus or 0) + (center.config.bonus or 0)" +position = "after" +payload = """ +for k, v in pairs(center.config) do + if k ~= 'bonus' then + if type(v) == 'table' then + self.ability[k] = copy_table(v) + else + self.ability[k] = v + end + end +end""" +match_indent = true + +# Card:calculate_joker() +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = '''function Card:calculate_joker(context) + if self.debuff then return nil end +''' +position = 'after' +payload = ''' + local obj = self.config.center + if self.ability.set ~= "Enhanced" and obj.calculate and type(obj.calculate) == 'function' then + local o, t = obj:calculate(self, context) + if o or t then return o, t end + end''' +match_indent = true + +# Card:update() +[[patches]] +[patches.pattern] +target = 'card.lua' +pattern = 'if G.STAGE == G.STAGES.RUN then' +position = 'before' +match_indent = true +payload = ''' +local obj = self.config.center +if obj.update and type(obj.update) == 'function' then + obj:update(self, dt) +end''' + +# Card:generate_UIBox_ability_table() +[[patches]] +[patches.regex] +target = 'card.lua' +pattern = "(?else)\n[\t ]*if self.ability.name == 'Loyalty Card' then\n[\t ]*self.ability.loyalty_remaining" +root_capture = 'else' +position = 'at' +payload = 'elseif context.joker_main then' + + +[[patches]] +[patches.pattern] +target = 'card.lua' +pattern = 'return generate_card_ui(self.config.center, nil, loc_vars, card_type, badges, hide_desc, main_start, main_end)' +position = 'at' +match_indent = true +payload = 'return generate_card_ui(self.config.center, nil, loc_vars, card_type, badges, hide_desc, main_start, main_end, self)' + +[[patches]] +[patches.pattern] +target = 'functions/common_events.lua' +pattern = "full_UI_table.name = localize{type = 'name', set = _c.set, key = _c.key, nodes = full_UI_table.name}" +position = 'at' +match_indent = true +payload = ''' +if not _c.generate_ui or type(_c.generate_ui) ~= 'function' then + full_UI_table.name = localize{type = 'name', set = _c.set, key = _c.key, nodes = full_UI_table.name} +end''' + +[[patches]] +[patches.pattern] +target = 'functions/common_events.lua' +pattern = "elseif specific_vars and specific_vars.debuffed then" +position = 'before' +match_indent = true +payload = ''' +elseif _c.generate_ui and type(_c.generate_ui) == 'function' then + _c:generate_ui(info_queue, card, desc_nodes, specific_vars, full_UI_table) + if specific_vars and specific_vars.pinned then info_queue[#info_queue+1] = {key = 'pinned_left', set = 'Other'} end + if specific_vars and specific_vars.sticker then info_queue[#info_queue+1] = {key = string.lower(specific_vars.sticker)..'_sticker', set = 'Other'} end''' + +[[patches]] +[patches.regex] +target = 'functions/common_events.lua' +pattern = "(?[\t ]+)if (?_c.name == 'Golden Ticket' then)" +line_prepend = '$indent' +position = 'at' +payload = ''' +local res = {} +if _c.locked_loc_vars and type(_c.locked_loc_vars) == 'function' then + local _card = _c.create_fake_card and _c:create_fake_card() + res = _c:locked_loc_vars(info_queue, _card) or {} + loc_vars = res.vars or {} + specific_vars = specific_vars or {} + specific_vars.not_hidden = res.not_hidden or specific_vars.not_hidden + if res.main_start then desc_nodes[#desc_nodes+1] = res.main_start end + main_end = res.main_end or main_end +elseif $rest''' + +[[patches]] +[patches.pattern] +target = 'functions/common_events.lua' +position = 'at' +match_indent = true +pattern = "localize{type = 'unlocks', key = 'joker_locked_legendary', set = 'Other', nodes = desc_nodes, vars = loc_vars}" +payload = "localize{type = 'unlocks', key = res.key or 'joker_locked_legendary', set = res.set or 'Other', nodes = desc_nodes, vars = loc_vars, text_colour = res.text_colour, scale = res.scale}" + +[[patches]] +[patches.pattern] +target = 'functions/common_events.lua' +position = 'at' +match_indent = true +pattern = "localize{type = 'unlocks', key = _c.key, set = _c.set, nodes = desc_nodes, vars = loc_vars}" +payload = "localize{type = 'unlocks', key = res.key or _c.key, set = res.set or _c.set, nodes = desc_nodes, vars = loc_vars, text_colour = res.text_colour, scale = res.scale}" + +[[patches]] +[patches.pattern] +target = 'functions/common_events.lua' +position = 'at' +match_indent = true +pattern = 'elseif desc_nodes ~= full_UI_table.main then' +payload = 'elseif desc_nodes ~= full_UI_table.main and not desc_nodes.name then' + + + +# check_for_unlock() +[[patches]] +[patches.regex] +target = 'functions/common_events.lua' +pattern = "(?[\t ]*)if not card.unlocked and card.unlock_condition and args.type == 'career_stat' then" +line_prepend = '$indent' +position = 'before' +payload = ''' + +local custom_check +if not card.unlocked and card.check_for_unlock and type(card.check_for_unlock) == 'function' then + ret = card:check_for_unlock(args) + if ret then unlock_card(card) end + custom_check = true +end''' + +[[patches]] +[patches.regex] +target = 'functions/common_events.lua' +pattern = "(?[\t ]*)if(? )not card.unlocked and card.unlock_condition and args.type == 'career_stat' then" +position = 'at' +root_capture = 'a' +payload = ' not custom_check and ' + +[[patches]] +[patches.regex] +target = 'functions/common_events.lua' +pattern = "(?[\t ]*)if(? )not card.unlocked and card.unlock_condition and card.unlock_condition.type == args.type then" +position = 'at' +root_capture = 'a' +payload = ' not custom_check and ' + +#Card:use_consumable() +[[patches]] +[patches.regex] +target = 'card.lua' +pattern = "(?[\t ]*)if self.ability.consumeable.mod_conv or self.ability.consumeable.suit_conv then" +line_prepend = '$indent' +position = 'before' +payload = ''' +local obj = self.config.center +if obj.use and type(obj.use) == 'function' then + obj:use(self, area, copier) + return +end''' + +# Card:can_use_consumable() +[[patches]] +[patches.regex] +target = 'card.lua' +pattern = "(?[\t ]*)if self.ability.name == 'The Hermit' or self.ability.consumeable.hand_type" +line_prepend = '$indent' +position = 'before' +payload = ''' +local obj = self.config.center +if obj.can_use and type(obj.can_use) == 'function' then + return obj:can_use(self) +end''' + +# G.UIDEF.card_h_popup() +[[patches]] +[patches.regex] +target = 'functions/UI_definitions.lua' +pattern = "(?[\t ]*)(?if AUT.badges.card_type or AUT.badges.force_rarity then)\n[\t ]*(?.*)\n[\t ]*end" +line_prepend = '$indent' +position = 'at' +payload = ''' +local obj = card.config.center +$if + if obj and (obj.set_card_type_badge or obj.type and obj.type.set_card_type_badge) then + if obj.type and type(obj.type.set_card_type_badge) == 'function' then + obj.type:set_card_type_badge(obj, card, badges) + end + if type(obj.set_card_type_badge) == 'function' then + obj:set_card_type_badge(card, badges) + end + else + $rest + end +end +if obj and obj.set_badges and type(obj.set_badges) == 'function' then + obj:set_badges(card, badges) +end''' + +[[patches]] +[patches.regex] +target = 'functions/UI_definitions.lua' +pattern = "(?[\t ]*)if AUT.badges then\n([\t ]*.*\n){4}[\t ]*end" +line_prepend = '$indent' +position = 'after' +payload = ''' +if AUT.card_type ~= 'Locked' and AUT.card_type ~= 'Undiscovered' then + SMODS.create_mod_badges(card.config.center, badges) + if card.base then + SMODS.create_mod_badges(SMODS.Ranks[card.base.value], badges) + SMODS.create_mod_badges(SMODS.Suits[card.base.suit], badges) + end + if card.config and card.config.tag then + SMODS.create_mod_badges(SMODS.Tags[card.config.tag.key], badges) + end + badges.mod_set = nil +end''' + +# set_discover_tallies() +[[patches]] +[patches.regex] +target = 'functions/misc_functions.lua' +pattern = "(?[\t ]*)if v.set == 'Planet' then(\n[\t ]*.*){15}" +line_prepend = '$indent' +position = 'at' +payload = ''' +local tally = G.DISCOVER_TALLIES[v.set:lower()..'s'] +if tally then + tally.of = tally.of + 1 + if v.discovered then + tally.tally = tally.tally + 1 + end +end''' + +[[patches]] +[patches.regex] +target = 'functions/misc_functions.lua' +pattern = "[\t ]*tarots = \\{tally = 0, of = 0\\},\n(.*\n){2}" +line_prepend = '$indent' +position = 'at' +payload = '' + +[[patches]] +[patches.regex] +target = 'functions/misc_functions.lua' +pattern = "(?[\t ]*)for _, v in pairs\\(G.DISCOVER_TALLIES\\) do" +line_prepend = '$indent' +position = 'before' +payload = ''' +for _, v in ipairs(SMODS.ConsumableType.ctype_buffer) do + G.DISCOVER_TALLIES[v:lower()..'s'] = {tally = 0, of = 0} +end''' + +# create_UIBox_your_collection() +[[patches]] +[patches.regex] +target = 'functions/UI_definitions.lua' +pattern = "(?[\t ]*)local t = create_UIBox_generic_options\\(\\{ back_func = G.STAGE" +line_prepend = '$indent' +position = 'before' +payload = ''' +local consumable_nodes = {} +if #SMODS.ConsumableType.ctype_buffer <= 3 then + for _, key in ipairs(SMODS.ConsumableType.ctype_buffer) do + local id = 'your_collection_'..key:lower()..'s' + consumable_nodes[#consumable_nodes+1] = UIBox_button({button = id, label = {localize('b_'..key:lower()..'_cards')}, count = G.DISCOVER_TALLIES[key:lower()..'s'], minw = 4, id = id, colour = G.C.SECONDARY_SET[key]}) + end +else + consumable_nodes[#consumable_nodes+1] = UIBox_button({ button = 'your_collection_consumables', label = {localize('b_stat_consumables'), localize{ type = 'variable', key = 'c_types', vars = {#SMODS.ConsumableType.ctype_buffer} } }, count = G.DISCOVER_TALLIES['consumeables'], minw = 4, minh = 4, id = 'your_collection_consumables', colour = G.C.FILTER }) +end +''' + +[[patches]] +[patches.regex] +target = 'functions/UI_definitions.lua' +pattern = "(?[\t ]*)nodes=\\{\n[\t ]*UIBox_button\\(\\{button = 'your_collection_tarots'(.*\n){3}[\t ]*}" +line_prepend = '$indent' +position = 'at' +payload = 'nodes = consumable_nodes' + +# Card:apply_to_run() +[[patches]] +[patches.regex] +target = 'card.lua' +pattern = "(?[\t ]*)if center_table.name == 'Overstock'" +line_prepend = '$indent' +position = 'before' +payload = ''' +local obj = center or self.config.center +if obj.redeem and type(obj.redeem) == 'function' then + obj:redeem(card_to_save) + return +end''' + +# create_card_for_shop() +[[patches]] +[patches.pattern] +target = 'functions/UI_definitions.lua' +pattern = "local total_rate = G.GAME.joker_rate + G.GAME.tarot_rate + G.GAME.planet_rate + G.GAME.playing_card_rate + G.GAME.spectral_rate" +match_indent = true +position = 'at' +payload = ''' +local total_rate = G.GAME.joker_rate + G.GAME.playing_card_rate +for _,v in ipairs(SMODS.ConsumableType.ctype_buffer) do + total_rate = total_rate + G.GAME[v:lower()..'_rate'] +end''' + +[[patches]] +[patches.regex] +target = 'functions/UI_definitions.lua' +pattern = '(?[\t ]*)for _, v in ipairs\((?
  • \{\n(.*\n){5}[\t ]*\})\) do' +line_prepend = '$indent' +position = 'at' +payload = ''' +-- need to preserve order to leave RNG unchanged +local rates = $li +for _, v in ipairs(SMODS.ConsumableType.ctype_buffer) do + if not (v == 'Tarot' or v == 'Planet' or v == 'Spectral') then + table.insert(rates, { type = v, val = G.GAME[v:lower()..'_rate'] }) + end +end +for _, v in ipairs(rates) do''' + +# create_card() +[[patches]] +[patches.pattern] +target = 'functions/common_events.lua' +pattern = "if not forced_key and soulable and (not G.GAME.banned_keys['c_soul']) then" +match_indent = true +position = 'after' +payload = ''' + for _, v in ipairs(SMODS.Consumable.legendaries) do + if (_type == v.type.key or _type == v.soul_set) and not (G.GAME.used_jokers[v.key] and not next(find_joker("Showman")) and not v.can_repeat_soul) and (not v.in_pool or (type(v.in_pool) ~= "function") or v:in_pool()) then + if pseudorandom('soul_'..v.key.._type..G.GAME.round_resets.ante) > (1 - v.soul_rate) then + forced_key = v.key + end + end + end''' + +[[patches]] +[patches.pattern] +target = 'functions/common_events.lua' +pattern = "{bypass_discovery_center = area==G.shop_jokers or area == G.pack_cards or area == G.shop_vouchers or (G.shop_demo and area==G.shop_demo) or area==G.jokers or area==G.consumeables," +match_indent = true +position = 'at' +payload = ''' +{bypass_discovery_center = SMODS.bypass_create_card_discovery_center or area==G.shop_jokers or area == G.pack_cards or area == G.shop_vouchers or (G.shop_demo and area==G.shop_demo) or area==G.jokers or area==G.consumeables,''' + +[[patches]] +[patches.pattern] +target = 'functions/common_events.lua' +pattern = "bypass_discovery_ui = area==G.shop_jokers or area == G.pack_cards or area==G.shop_vouchers or (G.shop_demo and area==G.shop_demo)," +match_indent = true +position = 'at' +payload = ''' +bypass_discovery_ui = SMODS.bypass_create_card_discovery_center or area==G.shop_jokers or area == G.pack_cards or area==G.shop_vouchers or (G.shop_demo and area==G.shop_demo),''' + +[[patches]] +[patches.pattern] +target = 'functions/common_events.lua' +pattern = "discover = area==G.jokers or area==G.consumeables, " +match_indent = true +position = 'at' +payload = ''' +discover = SMODS.bypass_create_card_discover or area==G.jokers or area==G.consumeables, ''' + +# Card:add_to_deck() +[[patches]] +[patches.regex] +target = 'card.lua' +pattern = '(?[\t ]*)if self.ability.h_size ~= 0 then\n[\t ]*G\.hand:change_size\(self.ability.h_size\)' +line_prepend = '$indent' +position = 'before' +payload = ''' +local obj = self.config.center +if obj and obj.add_to_deck and type(obj.add_to_deck) == 'function' then + obj:add_to_deck(self, from_debuff) +end''' + +# Card:remove_from_deck() +[[patches]] +[patches.regex] +target = 'card.lua' +pattern = '(?[\t ]*)if self.ability.h_size ~= 0 then\n[\t ]*G\.hand:change_size\(-self.ability.h_size\)' +line_prepend = '$indent' +position = 'before' +payload = ''' +local obj = self.config.center +if obj and obj.remove_from_deck and type(obj.remove_from_deck) == 'function' then + obj:remove_from_deck(self, from_debuff) +end''' + +# G.FUNCS.use_card() +[[patches]] +[patches.pattern] +target = 'functions/button_callbacks.lua' +pattern = "if card.area then card.area:remove_card(card) end" +match_indent = true +position = 'at' +payload = ''' +local nc +local select_to = card.area == G.pack_cards and booster_obj and booster_obj.select_card and card:selectable_from_pack(booster_obj) +if card.ability.consumeable and not select_to then + local obj = card.config.center + if obj.keep_on_use and type(obj.keep_on_use) == 'function' then + nc = obj:keep_on_use(card) + end +end +if not card.from_area then card.from_area = card.area end +if card.area and (not nc or card.area == G.pack_cards) then card.area:remove_card(card) end''' +[[patches]] +[patches.pattern] +target = 'functions/button_callbacks.lua' +match_indent = true +position = 'before' +pattern = ''' +if area and area.cards[1] then +''' +payload = ''' +if nc and not area then G.consumeables:emplace(card) end +''' +[[patches]] +[patches.pattern] +target = 'functions/button_callbacks.lua' +pattern = "else draw_card(G.hand, G.play, 1, 'up', true, card, nil, mute) end" +match_indent = true +position = 'at' +payload = '''elseif not nc then draw_card(G.hand, G.play, 1, 'up', true, card, nil, mute) end''' + + +# Card:load() +[[patches]] +[patches.pattern] +target = 'card.lua' +pattern = 'if self.config.center.name == "Half Joker" then' +match_indent = true +position = 'at' +payload = ''' +local obj = self.config.center +if obj.load and type(obj.load) == 'function' then + obj:load(self, cardTable, other_card) +elseif self.config.center.name == "Half Joker" then''' + +# Card:calculate_dollar_bonus() +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = """function Card:calculate_dollar_bonus() + if self.debuff then return end""" +position = "after" +match_indent = true +payload = ''' + local obj = self.config.center + if obj.calc_dollar_bonus and type(obj.calc_dollar_bonus) == 'function' then + return obj:calc_dollar_bonus(self) + end +''' + +# no_blueprint check +[[patches]] +[patches.pattern] +target = 'card.lua' +match_indent = true +position = 'at' +pattern = 'if other_joker and other_joker ~= self then' +payload = 'if other_joker and other_joker ~= self and not context.no_blueprint then' + +# extract joker loc_vars +[[patches]] +[patches.pattern] +target = 'card.lua' +match_indent = true +position = 'at' +pattern = 'function Card:generate_UIBox_ability_table()' +payload = 'function Card:generate_UIBox_ability_table(vars_only)' + +[[patches]] +[patches.pattern] +target = 'card.lua' +match_indent = true +position = 'before' +pattern = 'local badges = {}' +payload = 'if vars_only then return loc_vars, main_start, main_end end' + +[[patches]] +[patches.pattern] +target = 'functions/common_events.lua' +match_indent = true +position = 'after' +pattern = "elseif _c.set == 'Joker' then" +payload = ''' + if not card then + local ability = copy_table(_c.config) + ability.set = 'Joker' + ability.name = _c.name + local ret = {Card.generate_UIBox_ability_table({ ability = ability, config = { center = _c }, bypass_lock = true}, true)} + specific_vars = ret[1] + if ret[2] then desc_nodes[#desc_nodes+1] = ret[2] end + main_end = ret[3] + end + ''' \ No newline at end of file diff --git a/Steamodded/lovely/challenge.toml b/Steamodded/lovely/challenge.toml new file mode 100644 index 0000000..0db9203 --- /dev/null +++ b/Steamodded/lovely/challenge.toml @@ -0,0 +1,21 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = -5 + +# function G.UIDEF.challenge_list_page() +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +pattern = "local challenge_unlocked = G.PROFILES[G.SETTINGS.profile].challenges_unlocked and (G.PROFILES[G.SETTINGS.profile].challenges_unlocked >= k)" +position = 'after' +payload = """ +if v.unlocked and type(v.unlocked) == 'function' then + challenge_unlocked = v:unlocked() +elseif type(v.unlocked) == 'boolean' then + challenge_unlocked = v.unlocked +end +challenge_unlocked = challenge_unlocked or G.PROFILES[G.SETTINGS.profile].all_unlocked + +""" +match_indent = true diff --git a/Steamodded/lovely/compact_cashout.toml b/Steamodded/lovely/compact_cashout.toml new file mode 100644 index 0000000..98676f3 --- /dev/null +++ b/Steamodded/lovely/compact_cashout.toml @@ -0,0 +1,65 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = -5 + + +# +# End of round money +# + +# Hide off screen rows + +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = "if config.name ~= 'bottom' then" +position = "after" +payload = ''' + total_cashout_rows = (total_cashout_rows or 0) + 1 + 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 + diff --git a/Steamodded/lovely/compat_0_9_8.toml b/Steamodded/lovely/compat_0_9_8.toml new file mode 100644 index 0000000..a61c552 --- /dev/null +++ b/Steamodded/lovely/compat_0_9_8.toml @@ -0,0 +1,38 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = -5 + +# fallback for card.ability.name +# Card:set_ability() +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "self.ability.bonus = (self.ability.bonus or 0) + (center.config.bonus or 0)" +position = 'after' +payload = "if not self.ability.name then self.ability.name = center.key end" +match_indent = true + +# generate_card_ui() +# `card_type` is used to check whether card should be nil; non-recursive calls +# to generate_card_ui always have that arg set +[[patches]] +[patches.regex] +target = "functions/common_events.lua" +pattern = '(?[\t ]*)function generate_card_ui\([^)]*\)\n' +position = "after" +line_prepend = '$indent' +payload = """ + if card == nil and card_type then + card = SMODS.compat_0_9_8.generate_UIBox_ability_table_card + end + +""" +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = "for _, v in ipairs(info_queue) do" +position = 'before' +payload = "SMODS.compat_0_9_8.generate_UIBox_ability_table_card = nil" +match_indent = true + diff --git a/Steamodded/lovely/core.toml b/Steamodded/lovely/core.toml new file mode 100644 index 0000000..899b0cc --- /dev/null +++ b/Steamodded/lovely/core.toml @@ -0,0 +1,24 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = -5 + +[[patches]] +[patches.pattern] +target = "game.lua" +pattern = "self.SPEEDFACTOR = 1" +position = "after" +payload = "initSteamodded()" +match_indent = true + +[[patches]] +[patches.copy] +target = "main.lua" +position = "append" +sources = ["src/core.lua"] + +[[patches]] +[patches.module] +before = "main.lua" +source = "version.lua" +name = "SMODS.version" diff --git a/Steamodded/lovely/crash_handler.toml b/Steamodded/lovely/crash_handler.toml new file mode 100644 index 0000000..cd590af --- /dev/null +++ b/Steamodded/lovely/crash_handler.toml @@ -0,0 +1,20 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = -10 + +[[patches]] +[patches.pattern] +target = "main.lua" +pattern = "function love.errhand(msg)" +position = "at" +payload = "if false then" +match_indent = true + +[[patches]] +[patches.copy] +target = "main.lua" +position = "prepend" +sources = [ + "src/crash_handler.lua", +] diff --git a/Steamodded/lovely/deck_skins.toml b/Steamodded/lovely/deck_skins.toml new file mode 100644 index 0000000..c4e5c9f --- /dev/null +++ b/Steamodded/lovely/deck_skins.toml @@ -0,0 +1,218 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = -10 + +#========================================================# +# Choose any rank for custom deck and use provided atlas # +#========================================================# +[[patches]] +[patches.regex] +target = "functions/misc_functions.lua" +pattern = '''if _front and _front.suit and \(_front.value == 'Jack' or _front.value == 'Queen' or _front.value == 'King'\) then([\s\S]*?)end([\s\S]*?)end([\s\S]*?)end''' +position = "at" +payload = ''' +if _front and _front.suit and G.SETTINGS.CUSTOM_DECK and G.SETTINGS.CUSTOM_DECK.Collabs then + local collab = G.SETTINGS.CUSTOM_DECK.Collabs[_front.suit] + if collab then + local deckSkin = SMODS.DeckSkins[collab] + if deckSkin then + if deckSkin.outdated then + local hasRank = false + for i = 1, #deckSkin.ranks do + if deckSkin.ranks[i] == _front.value then hasRank = true break end + end + if hasRank then + local atlas = G.ASSET_ATLAS[G.SETTINGS.colour_palettes[_front.suit] == 'hc' and deckSkin.hc_atlas or deckSkin.lc_atlas] + if atlas then + if deckSkin.pos_style == 'collab' then + return atlas, G.COLLABS.pos[_front.value] + elseif deckSkin.pos_style == 'suit' then + return atlas, { x = _front.pos.x, y = 0} + elseif deckSkin.pos_style == 'deck' then + return atlas, _front.pos + elseif deckSkin.pos_style == 'ranks' or nil then + for i, rank in ipairs(deckSkin.ranks) do + if rank == _front.value then + return atlas, { x = i - 1, y = 0} + end + end + end + end + end + return G.ASSET_ATLAS[G.SETTINGS.colour_palettes[_front.suit] == 'hc' and _front.hc_atlas or _front.lc_atlas or {}] or G.ASSET_ATLAS[_front.atlas] or G.ASSET_ATLAS["cards_"..(G.SETTINGS.colour_palettes[_front.suit] == 'hc' and 2 or 1)], _front.pos + else + local palette = deckSkin.palette_map and deckSkin.palette_map[G.SETTINGS.colour_palettes[_front.suit] or ''] or (deckSkin.palettes or {})[1] + local hasRank = false + for i = 1, #palette.ranks do + if palette.ranks[i] == _front.value then hasRank = true break end + end + if hasRank then + local atlas = G.ASSET_ATLAS[palette.atlas] + if type(palette.pos_style) == "table" then + if palette.pos_style[_front.value] then + if palette.pos_style[_front.value].atlas then + atlas = G.ASSET_ATLAS[palette.pos_style[_front.value].atlas] + end + if palette.pos_style[_front.value].pos then + return atlas, palette.pos_style[_front.value].pos + end + elseif palette.pos_style.fallback_style then + if palette.pos_style.fallback_style == 'collab' then + return atlas, G.COLLABS.pos[_front.value] + elseif palette.pos_style.fallback_style == 'suit' then + return atlas, { x = _front.pos.x, y = 0} + elseif palette.pos_style.fallback_style == 'deck' then + return atlas, _front.pos + end + end + elseif palette.pos_style == 'collab' then + return atlas, G.COLLABS.pos[_front.value] + elseif palette.pos_style == 'suit' then + return atlas, { x = _front.pos.x, y = 0} + elseif palette.pos_style == 'deck' then + return atlas, _front.pos + elseif palette.pos_style == 'ranks' or nil then + for i, rank in ipairs(palette.ranks) do + if rank == _front.value then + return atlas, { x = i - 1, y = 0} + end + end + end + end + return G.ASSET_ATLAS[palette.hc_default and _front.hc_atlas or _front.lc_atlas or {}] or G.ASSET_ATLAS[_front.atlas] or G.ASSET_ATLAS["cards_"..(palette.hc_default and 2 or 1)], _front.pos + end + end + end +end +''' + +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +pattern = "{n=G.UIT.O, config={object = face_cards}}" +position = "at" +payload = "{n=G.UIT.O, config={object = G.cdds_cards}}" +match_indent = true +overwrite = false + +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +pattern = "table.insert(t, create_toggle({label = localize('b_high_contrast_cards'), ref_table = G.SETTINGS, ref_value = 'colourblind_option', callback = G.FUNCS.refresh_contrast_mode}))" +position = "at" +payload = ''' +local deckskin_key = G.COLLABS.options[_suit][current_option] + +local palette_loc_options = SMODS.DeckSkin.get_palette_loc_options(deckskin_key, _suit) + +local selected_palette = 1 +for i, v in ipairs(G.COLLABS.colour_palettes[deckskin_key]) do + if G.SETTINGS.colour_palettes[_suit] == v then + selected_palette = i + end +end + +table.insert(t, + {n=G.UIT.R, config={align = "cm", id = 'palette_selector'}, nodes={ + create_option_cycle({options = palette_loc_options, w = 5.5, cycle_shoulders = false, curr_suit = _suit, curr_skin = deckskin_key, opt_callback = 'change_colour_palette', current_option = selected_palette, colour = G.C.ORANGE, focus_args = {snap_to = true, nav = 'wide'}}), + }} + ) +''' +match_indent = true +overwrite = false + +#=======================# +# Extend custom deck ui # +#=======================# +[[patches]] +[patches.regex] +target = "functions/UI_definitions.lua" +pattern = '''local face_cards = CardArea\(([\s\S]*?)\)''' +position = "at" +payload = ''' +local rankCount = 0 +local lookup = {} +for i, s in ipairs(SMODS.Suit:obj_list(true)) do + local options = G.COLLABS.options[s.key] + for i = 1, #options do + local skin = SMODS.DeckSkins[options[i]] + if skin.palettes and not (skin.display_ranks or skin.ranks) then + for _, p in ipairs(skin.palettes) do + local p_ranks = p.display_ranks or p.ranks + for j = 1, #p_ranks do + if not lookup[p_ranks[j]] then + lookup[p_ranks[j]] = true + rankCount = rankCount + 1 + end + end + end + elseif not skin.palettes and (skin.display_ranks or skin.ranks) then + local ranks = skin.display_ranks or skin.ranks + for j = 1, #ranks do + if not lookup[skin.ranks[j]] then + lookup[skin.ranks[j]] = true + rankCount = rankCount + 1 + end + end + end + + end +end + +G.cdds_cards = CardArea( + 0,0, + math.min(math.max(rankCount*G.CARD_W*0.6, 4*G.CARD_W), 10*G.CARD_W), + 1.4*G.CARD_H, + {card_limit = rankCount, type = 'title', highlight_limit = 0}) + +G.cdds_cards.rankCount = rankCount + +''' + +[[patches]] +[patches.regex] +target = "functions/UI_definitions.lua" +pattern = '''for i = 1, 3 do([\s\S]*?)end''' +position = "at" +payload = ''' +G.FUNCS.update_collab_cards(current_option, _suit, true) +''' + +[[patches]] +[patches.regex] +target = "functions/UI_definitions.lua" +pattern = '''function create_UIBox_customize_deck()([\s\S]*?)end''' +position = "at" +payload = ''' +function create_UIBox_customize_deck() + local suitTabs = {} + + local index = 1 + for i, suit in ipairs(SMODS.Suit:obj_list(true)) do + if G.COLLABS.options[suit.key] then + suitTabs[index] = { + label = localize(suit.key, 'suits_plural'), + tab_definition_function = G.UIDEF.custom_deck_tab, + tab_definition_function_args = suit.key + } + index = index + 1 + end + end + + if suitTabs[1] then + suitTabs[1].chosen = true + end + + local t = create_UIBox_generic_options({ back_func = 'options', snap_back = nil, contents = { + {n=G.UIT.R, config={align = "cm", padding = 0}, nodes={ + create_tabs( + {tabs = suitTabs, snap_to_nav = true, no_shoulders = true} + )}}} + }) + + return t +end +''' + + diff --git a/Steamodded/lovely/dollar_row.toml b/Steamodded/lovely/dollar_row.toml new file mode 100644 index 0000000..0a02b1c --- /dev/null +++ b/Steamodded/lovely/dollar_row.toml @@ -0,0 +1,77 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = -10 + +### Dollar row patches (API removed) + + +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = "if num_dollars > 60 then" +position = "at" +payload = ''' +if num_dollars > 60 or num_dollars < -60 then''' +match_indent = true + +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = "local dollar_string = localize('$')..num_dollars" +position = "at" +payload = ''' +if num_dollars < 0 then --if negative + G.E_MANAGER:add_event(Event({ + trigger = 'before',delay = 0.38, + func = function() + G.round_eval:add_child( + {n=G.UIT.R, config={align = "cm", id = 'dollar_row_'..(dollar_row+1)..'_'..config.name}, nodes={ + {n=G.UIT.O, config={object = DynaText({string = {localize('$')..format_ui_value(num_dollars)}, colours = {G.C.RED}, shadow = true, pop_in = 0, scale = 0.65, float = true})}} + }}, + G.round_eval:get_UIE_by_ID('dollar_'..config.name)) + play_sound('coin3', 0.9+0.2*math.random(), 0.7) + play_sound('coin6', 1.3, 0.8) + return true + end + })) +else --if positive +''' +match_indent = true + +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = "for i = 1, num_dollars or 1 do" +position = "at" +payload = ''' +local dollars_to_loop +if num_dollars < 0 then dollars_to_loop = (num_dollars*-1)+1 else dollars_to_loop = num_dollars end +for i = 1, dollars_to_loop do''' +match_indent = true + +[[patches]] +[patches.regex] +target = "functions/common_events.lua" +pattern = '''(?[\t ]*)else\n[\t ]*local dollars_to_loop''' +position = "before" +line_prepend = "$indent" +payload = ''' +--asdf +end''' + +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = "local r = {n=G.UIT.T, config={text = localize('$'), colour = G.C.MONEY, scale = ((num_dollars > 20 and 0.28) or (num_dollars > 9 and 0.43) or 0.58), shadow = true, hover = true, can_collide = false, juice = true}}" +position = "at" +payload = ''' +local r +if i == 1 and num_dollars < 0 then + r = {n=G.UIT.T, config={text = '-', colour = G.C.RED, scale = ((num_dollars < -20 and 0.28) or (num_dollars < -9 and 0.43) or 0.58), shadow = true, hover = true, can_collide = false, juice = true}} + play_sound('coin3', 0.9+0.2*math.random(), 0.7 - (num_dollars < -20 and 0.2 or 0)) +else + if num_dollars < 0 then r = {n=G.UIT.T, config={text = localize('$'), colour = G.C.RED, scale = ((num_dollars > 20 and 0.28) or (num_dollars > 9 and 0.43) or 0.58), shadow = true, hover = true, can_collide = false, juice = true}} + else r = {n=G.UIT.T, config={text = localize('$'), colour = G.C.MONEY, scale = ((num_dollars > 20 and 0.28) or (num_dollars > 9 and 0.43) or 0.58), shadow = true, hover = true, can_collide = false, juice = true}} end +end''' +match_indent = true diff --git a/Steamodded/lovely/edition.toml b/Steamodded/lovely/edition.toml new file mode 100644 index 0000000..4c502ed --- /dev/null +++ b/Steamodded/lovely/edition.toml @@ -0,0 +1,281 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = -10 + +# Fix debug mode edition cycling +[[patches]] +[patches.regex] +target = "engine/controller.lua" +pattern = ''' +(?[\t ]*)local _edition = \{ +[\t ]*foil = not _card\.edition, +[\t ]*holo = _card\.edition and _card\.edition\.foil, +[\t ]*polychrome = _card\.edition and _card\.edition\.holo, +[\t ]*negative = _card\.edition and _card\.edition\.polychrome, +[\t ]*\}''' +position = "at" +payload = ''' +local found_index = 1 +if _card.edition then + for i, v in ipairs(G.P_CENTER_POOLS.Edition) do + if v.key == _card.edition.key then + found_index = i + break + end + end +end +found_index = found_index + 1 +if found_index > #G.P_CENTER_POOLS.Edition then found_index = found_index - #G.P_CENTER_POOLS.Edition end +local _edition = G.P_CENTER_POOLS.Edition[found_index].key''' +line_prepend = "$indent" + + +# Sort P_CENTER_POOLS["Editions"] +[[patches]] +[patches.pattern] +target = 'game.lua' +pattern = 'table.sort(self.P_CENTER_POOLS["Enhanced"], function (a, b) return a.order < b.order end)' +position = 'after' +payload = 'table.sort(self.P_CENTER_POOLS["Edition"], function (a, b) return a.order < b.order end)' +match_indent = true + + +# generate_card_ui() +# Adds tooltips for all editions +[[patches]] +[patches.regex] +target = 'functions/common_events.lua' +pattern = ''' +(?[\t ]*)if v == 'foil' then info_queue\[#info_queue\+1\] = G\.P_CENTERS\['e_foil'\] end +[\t ]*if v == 'holographic' then info_queue\[#info_queue\+1\] = G\.P_CENTERS\['e_holo'\] end +[\t ]*if v == 'polychrome' then info_queue\[#info_queue\+1\] = G\.P_CENTERS\['e_polychrome'\] end +[\t ]*if v == 'negative' then info_queue\[#info_queue\+1\] = G\.P_CENTERS\['e_negative'\] end +[\t ]*if v == 'negative_consumable' then info_queue\[#info_queue\+1\] = \{key = 'e_negative_consumable', set = 'Edition', config = \{extra = 1\}\} end''' +position = 'at' +payload = ''' +v = (v == 'holographic' and 'holo' or v) +if v:sub(1,9) == 'negative_' then + info_queue[#info_queue+1] = {key = 'e_'..v, set = 'Edition', config = {extra = G.P_CENTERS['e_negative'].config.card_limit}} +end +if G.P_CENTERS[v] and G.P_CENTERS[v].set == 'Edition' then + info_queue[#info_queue + 1] = G.P_CENTERS[v] +end +if G.P_CENTERS['e_'..v] and G.P_CENTERS['e_'..v].set == 'Edition' then + local t = {key = 'e_'..v, set = 'Edition', config = {}} + info_queue[#info_queue + 1] = t + if G.P_CENTERS['e_'..v].loc_vars and type(G.P_CENTERS['e_'..v].loc_vars) == 'function' then + local res = G.P_CENTERS['e_'..v]:loc_vars(info_queue, card) or {} + t.vars = res.vars + t.key = res.key or t.key + t.set = res.set or t.set + end +end''' +line_prepend = "$indent" +[[patches]] +[patches.pattern] +target = 'functions/common_events.lua' +pattern = '''localize{type = 'descriptions', key = _c.key, set = _c.set, nodes = desc_nodes, vars = loc_vars}''' +position = 'at' +match_indent = true +payload = '''localize{type = 'descriptions', key = _c.key, set = _c.set, nodes = desc_nodes, vars = _c.vars or loc_vars}''' + + +# get_badge_colour() +[[patches]] +[patches.pattern] +target = 'functions/UI_definitions.lua' +pattern = 'return G.BADGE_COL[key] or {1, 0, 0, 1}' +position = 'before' +match_indent = true +payload = ''' +for _, v in ipairs(G.P_CENTER_POOLS.Edition) do + G.BADGE_COL[v.key:sub(3)] = v.badge_colour +end''' + +# Remove prefix from shader key when calling send() +[[patches]] +[patches.pattern] +target = "engine/sprite.lua" +pattern = "if _send then G.SHADERS[_shader or 'dissolve']:send(_shader,_send) end" +position = "at" +payload = ''' +if _send then + G.SHADERS[_shader or 'dissolve']:send((SMODS.Shaders[_shader or 'dissolve'] and SMODS.Shaders[_shader or 'dissolve'].original_key) or _shader,_send) +end''' +match_indent = true + +# Inject change to edition cost in shop +[[patches]] +[patches.regex] +target = "card.lua" +pattern = '(?[\t ]*)self.ex([a-z._\s=+(0-9)]*)\n([\t ]*)([a-z._\s=+(0-9)]*)or 0\)' +position = "at" +payload = ''' +for k, v in pairs(G.P_CENTER_POOLS.Edition) do + if self.edition[v.key:sub(3)] then + if v.extra_cost then + self.extra_cost = self.extra_cost + v.extra_cost + end + end +end''' +line_prepend = "$indent" + +## Fix card_limit logic +# Card:add_to_deck() +[[patches]] +[patches.regex] +target = "card.lua" +pattern = '''(?[\t ]*)if self\.edition[A-z\.\:\n\t _(',)~=+\-0-9]*limit \+ 1''' +position = "at" +payload = ''' +if true then + if from_debuff then + self.ability.joker_added_to_deck_but_debuffed = nil + else + if self.edition and self.edition.card_limit then + if self.ability.consumeable then + G.consumeables.config.card_limit = G.consumeables.config.card_limit + self.edition.card_limit + else + G.jokers.config.card_limit = G.jokers.config.card_limit + self.edition.card_limit + end''' +line_prepend = "$indent" +# Card:remove_from_deck() +[[patches]] +[patches.regex] +target = "card.lua" +pattern = '''(?[\t ]*)if self\.edition[A-z\.\:\n\t _(',)~=+\-0-9]*limit \- 1''' +position = "at" +payload = ''' +if G.jokers then + if from_debuff then + self.ability.joker_added_to_deck_but_debuffed = true + else + if self.edition and self.edition.card_limit then + if self.ability.consumeable then + G.consumeables.config.card_limit = G.consumeables.config.card_limit - self.edition.card_limit + elseif self.ability.set == 'Joker' then + G.jokers.config.card_limit = G.jokers.config.card_limit - self.edition.card_limit + end''' +line_prepend = "$indent" +# Card:remove() +[[patches]] +[patches.regex] +target = "card.lua" +pattern = '''(?[\t ]*)if self\.ability\.queue_neg[A-z\.\:\n\t _(',)~=+\-0-9]*limit \- 1''' +position = "at" +payload = ''' +if self.ability.joker_added_to_deck_but_debuffed then + if self.edition and self.edition.card_limit then + if self.ability.consumeable then + G.consumeables.config.card_limit = G.consumeables.config.card_limit - self.edition.card_limit + elseif self.ability.set == 'Joker' then + G.jokers.config.card_limit = G.jokers.config.card_limit - self.edition.card_limit + end''' +line_prepend = "$indent" +# Card:save() +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "added_to_deck = self.added_to_deck," +position = "after" +payload = "joker_added_to_deck_but_debuffed = self.joker_added_to_deck_but_debuffed," +match_indent = true + + +## Negative playing card logic +# CardArea:emplace() +[[patches]] +[patches.pattern] +target = "cardarea.lua" +pattern = "function CardArea:emplace(*" +position = "after" +payload = ''' + if not card.debuff and card.edition and card.edition.card_limit and (self == G.hand) then + self.config.real_card_limit = (self.config.real_card_limit or self.config.card_limit) + card.edition.card_limit + self.config.card_limit = math.max(0, self.config.real_card_limit) + end''' +match_indent = true +# CardArea:remove_card() +[[patches]] +[patches.pattern] +target = "cardarea.lua" +pattern = "card:remove_from_area()" +position = "before" +payload = ''' +if not card.debuff and card.edition and card.edition.card_limit and (self == G.hand) then + self.config.real_card_limit = (self.config.real_card_limit or self.config.card_limit) - card.edition.card_limit + self.config.card_limit = math.max(0, self.config.real_card_limit) +end''' +match_indent = true + +# G.FUNCS.draw_from_deck_to_hand() +[[patches]] +[patches.pattern] +target = "functions/state_events.lua" +pattern = "local hand_space = e or*" +position = "at" +payload = """local hand_space = e +if not hand_space then + local limit = G.hand.config.card_limit - #G.hand.cards + local n = 0 + while n < #G.deck.cards do + local card = G.deck.cards[#G.deck.cards-n] + limit = limit - 1 + (not card.debuff and card.edition and card.edition.card_limit or 0) + if limit < 0 then break end + n = n + 1 + end + hand_space = n +end""" +match_indent = true + +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "badges[#badges + 1] = 'negative_consumable'" +position = "after" +payload = """ +elseif self.edition.type == 'negative' and (self.ability.set == 'Enhanced' or self.ability.set == 'Default') then + badges[#badges + 1] = 'negative_playing_card'""" +match_indent = true + +[[patches]] +[patches.pattern] +target = "engine/sprite.lua" +pattern = "love.graphics.setShader( G.SHADERS[_shader or 'dissolve'], G.SHADERS[_shader or 'dissolve'])" +position = "before" +payload = ''' +local p_shader = SMODS.Shader.obj_table[_shader or 'dissolve'] +if p_shader and type(p_shader.send_vars) == "function" then + local sh = G.SHADERS[_shader or 'dissolve'] + local parent_card = self.role.major and self.role.major:is(Card) and self.role.major + local send_vars = p_shader.send_vars(self, parent_card) + + if type(send_vars) == "table" then + for key, value in pairs(send_vars) do + sh:send(key, value) + end + end +end +''' +match_indent = true + +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +pattern = "if v == 'negative_consumable' then v = 'negative' end" +position = "at" +payload = '''if v == 'negative_consumable' or v == 'negative_playing_card' then v = 'negative' end''' +match_indent = true + +# +[[patches]] +[patches.regex] +target = 'functions/common_events.lua' +pattern = '''(?[\t ]*)(?local edition = poll_edition\('edi'\.\.\(key_append or ''\)\.\.G\.GAME\.round_resets\.ante\)(\n.*){2})''' +position = 'at' +line_prepend = '$indent' +payload = ''' +if not SMODS.bypass_create_card_edition then + $edi +end''' diff --git a/Steamodded/lovely/enhancement.toml b/Steamodded/lovely/enhancement.toml new file mode 100644 index 0000000..b8b0856 --- /dev/null +++ b/Steamodded/lovely/enhancement.toml @@ -0,0 +1,327 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = -10 + +## no_rank, no_suit, all_suits + +# Card:get_id() +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "if self.ability.effect == 'Stone Card' and not self.vampired then" +match_indent = true +position = "at" +payload = '''if SMODS.has_no_rank(self) and not self.vampired then''' + +# Card:get_chip_bonus() +[[patches]] +[patches.regex] +target = "card.lua" +pattern = ''' +(?[\t ]*)if self\.ability\.effect == 'Stone Card' then +[\t ]* return self\.ability\.bonus \+ \(self\.ability\.perma_bonus or 0\) +[\t ]*end''' +position = "at" +payload = ''' +if self.ability.effect == 'Stone Card' or self.config.center.replace_base_card then + return self.ability.bonus + (self.ability.perma_bonus or 0) +end''' +line_prepend = '$indent' + +# Card:calculate_joker() +# Raised Fist +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "if temp_ID >= G.hand.cards[i].base.id and G.hand.cards[i].ability.effect ~= 'Stone Card' then temp_Mult = G.hand.cards[i].base.nominal; temp_ID = G.hand.cards[i].base.id; raised_card = G.hand.cards[i] end" +match_indent = true +position = "at" +payload = """if temp_ID >= G.hand.cards[i].base.id and not SMODS.has_no_rank(G.hand.cards[i]) then + temp_Mult = G.hand.cards[i].base.nominal + temp_ID = G.hand.cards[i].base.id + raised_card = G.hand.cards[i] +end""" +# Flower Pot, Seeing Double +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "if context.scoring_hand[i].ability.name ~= 'Wild Card' then" +match_indent = true +position = "at" +payload = '''if not SMODS.has_any_suit(context.scoring_hand[i]) then''' + +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "if context.scoring_hand[i].ability.name == 'Wild Card' then" +match_indent = true +position = "at" +payload = '''if SMODS.has_any_suit(context.scoring_hand[i]) then''' + +# Card:get_suit() +[[patches]] +[patches.regex] +target = "card.lua" +pattern = '''(?[\t ]*)if self\.ability\.effect == 'Stone Card' then''' +line_prepend = '$indent' +position = "at" +payload = '''if SMODS.has_no_suit(self) then''' +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = 'if self.ability.name == "Wild Card" then' +match_indent = true +position = "at" +payload = '''if SMODS.has_any_suit(self) then''' +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = 'if self.ability.name == "Wild Card" and not self.debuff then' +match_indent = true +position = "at" +payload = '''if SMODS.has_any_suit(self) and self:can_calculate() then''' + +# check_for_unlock +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = "if v.ability.name ~= 'Stone Card' and v.base.suit == 'Hearts' then" +match_indent = true +position = "at" +payload = "if not SMODS.has_no_suit(v) and v.base.suit == 'Hearts' then" + +# reset_idol_card() +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = "valid_idol_cards[#valid_idol_cards+1] = v" +match_indent = true +position = "at" +payload = """if not SMODS.has_no_suit(v) and not SMODS.has_no_rank(v) then + valid_idol_cards[#valid_idol_cards+1] = v +end""" + +# reset_mail_rank() +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = "valid_mail_cards[#valid_mail_cards+1] = v" +match_indent = true +position = "at" +payload = """if not SMODS.has_no_rank(v) then + valid_mail_cards[#valid_mail_cards+1] = v +end""" + +# reset_castle_card() +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = "valid_castle_cards[#valid_castle_cards+1] = v" +match_indent = true +position = "at" +payload = """if not SMODS.has_no_suit(v) then + valid_castle_cards[#valid_castle_cards+1] = v +end""" + +# G.FUNCS.evaluate_play() +[[patches]] +[patches.pattern] +target = "functions/state_events.lua" +pattern = "if scoring_hand[i].ability.effect ~= 'Stone Card' then" +match_indent = true +position = "at" +payload = '''if not SMODS.has_no_rank(scoring_hand[i]) then''' +[[patches]] +[patches.pattern] +target = "functions/state_events.lua" +pattern = "G.GAME.cards_played[scoring_hand[i].base.value].suits[scoring_hand[i].base.suit] = true" +match_indent = true +position = "at" +payload = """if not SMODS.has_no_suit(scoring_hand[i]) then + G.GAME.cards_played[scoring_hand[i].base.value].suits[scoring_hand[i].base.suit] = true +end""" + +# Add the delayed property to sprites that are delayed +[[patches]] +[patches.pattern] +target = 'card.lua' +match_indent = true +position = 'at' +pattern = ''' +if delay_sprites then + G.E_MANAGER:add_event(Event({ + func = function() + if not self.REMOVED then + self:set_sprites(center) + end + return true + end + })) +''' +payload = ''' +if delay_sprites == 'quantum' then +elseif delay_sprites then + self.ability.delayed = true + G.E_MANAGER:add_event(Event({ + func = function() + if not self.REMOVED then + self:set_sprites(center) + self.ability.delayed = false + end + return true + end + })) +''' + + + +# Card:generate_UIBox_ability_table() +# replaces two consecutive lines +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = "if (_c.name == 'Stone Card') then full_UI_table.name = true end" +match_indent = true +position = "at" +payload = "if _c.name == 'Stone Card' or _c.replace_base_card then full_UI_table.name = true" +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = "if (specific_vars.playing_card and (_c.name ~= 'Stone Card')) then" +match_indent = true +position = "at" +payload = "elseif specific_vars.playing_card then" + + +## Allow cards to function as multiple enhancements (e.g. from jokers) +# Calculate extra enhancements when held in hand at end of round +[[patches]] +[patches.pattern] +target = "functions/state_events.lua" +pattern = "local effects = {G.hand.cards[i]:get_end_of_round_effect()}" +position = "at" +payload = ''' +local effects = {[1] = {playing_card = G.hand.cards[i]:get_end_of_round_effect()}} +local extra_enhancements = SMODS.get_enhancements(G.hand.cards[i], true) +local old_ability = copy_table(G.hand.cards[i].ability) +local old_center = G.hand.cards[i].config.center +local old_center_key = G.hand.cards[i].config.center_key +for k, _ in pairs(extra_enhancements) do + if G.P_CENTERS[k] then + G.hand.cards[i]:set_ability(G.P_CENTERS[k]) + G.hand.cards[i].ability.extra_enhancement = k + effects[#effects+1] = {[1] = {playing_card = G.hand.cards[i]:get_end_of_round_effect()}} + end +end +G.hand.cards[i].ability = old_ability +G.hand.cards[i].config.center = old_center +G.hand.cards[i].config.center_key = old_center_key +G.hand.cards[i]:set_sprites(old_center) +''' +match_indent = true + +# Prevent blue seal effect on extra enhancements at end of round +[[patches]] +[patches.pattern] +target = "card" +pattern = "if self.seal == 'Blue' and #G.consumeables.cards + G.GAME.consumeable_buffer < G.consumeables.config.card_limit then" +position = "before" +payload = ''' +if self.extra_enhancement then return ret end +''' +match_indent = true + +# Use the has enhancement function for enhancement gates +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = "if vv.config.center.key == v.enhancement_gate then" +position = "at" +payload = "if SMODS.has_enhancement(vv, v.enhancement_gate) then" +match_indent = true + +# Glass Card shattering +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "if card.ability.name == 'Glass Card' then" +position = "at" +payload = "if SMODS.shatters(card) then" +match_indent = true + +[[patches]] +[patches.pattern] +target = "functions/state_events.lua" +pattern = "if G.hand.highlighted[i].ability.name == 'Glass Card' then" +position = "at" +payload = "if SMODS.shatters(G.hand.highlighted[i]) then" +match_indent = true + +[[patches]] +[patches.pattern] +target = "functions/state_events.lua" +pattern = "if scoring_hand[i].ability.name == 'Glass Card' then" +position = "at" +payload = "if SMODS.shatters(scoring_hand[i]) then" +match_indent = true + +[[patches]] +[patches.pattern] +target = "functions/state_events.lua" +pattern = "if cards_destroyed[i].ability.name == 'Glass Card' then" +position = "at" +payload = "if cards_destroyed[i].shattered then" +match_indent = true + +# Prevent blue seals from applying on quantum enhancement calc +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "if self.seal == 'Blue' and #G.consumeables.cards + G.GAME.consumeable_buffer < G.consumeables.config.card_limit then" +position = "at" +payload = "if self.seal == 'Blue' and #G.consumeables.cards + G.GAME.consumeable_buffer < G.consumeables.config.card_limit and not self.ability.extra_enhancement then" +match_indent = true + +# Reset enh cache on game update +[[patches]] +[patches.pattern] +target = "game.lua" +pattern = "modulate_sound(dt)" +position = "after" +payload = "SMODS.enh_cache:clear()" +match_indent = true + +# Invalidate enhancement cache when card changes +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "function Card:set_ability(center, initial, delay_sprites)" +position = "after" +payload = "SMODS.enh_cache:write(self, nil)" +match_indent = true + +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "function Card:set_base(card, initial)" +position = "after" +payload = "SMODS.enh_cache:write(self, nil)" +match_indent = true + +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "function Card:set_seal(_seal, silent, immediate)" +position = "after" +payload = "SMODS.enh_cache:write(self, nil)" +match_indent = true + +# safeguards an infloop with debuff context +[[patches]] +[patches.pattern] +target = 'card.lua' +pattern = 'if not initial then G.GAME.blind:debuff_card(self) end' +position = 'at' +payload = 'if not initial and delay_sprites ~= "quantum" and G.GAME.blind then G.GAME.blind:debuff_card(self) end' +match_indent = true \ No newline at end of file diff --git a/Steamodded/lovely/fixes.toml b/Steamodded/lovely/fixes.toml new file mode 100644 index 0000000..78e86a7 --- /dev/null +++ b/Steamodded/lovely/fixes.toml @@ -0,0 +1,696 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = -10 + +### Fixes for either base game code or general mod compatibility + +## Mods assume Game:start_run() is called with non-nil argument +# G.FUNCS.start_run() +[[patches]] +[patches.pattern] +target = 'functions/button_callbacks.lua' +pattern = "G.FUNCS.start_run = function(e, args)" +position = 'after' +match_indent = true +payload = "args = args or {}" + +## Allows running the game without Steam being active +# love.load() +[[patches]] +[patches.regex] +target = 'main.lua' +pattern = "(?[\t ]*)if not \\(st.init and st:init\\(\\)\\) then\n[\t ]*(?love.event.quit\\(\\))" +position = 'at' +root_capture = 'quit' +payload = 'st = nil' + + +## Prevents the game from crashing when hitting play with a corrupt/invalid save file +# G.FUNCS.can_continue(e) +[[patches]] +[patches.pattern] +target = 'functions/button_callbacks.lua' +pattern = "if G.SAVED_GAME ~= nil then G.SAVED_GAME = STR_UNPACK(G.SAVED_GAME) end" +position = 'after' +match_indent = true +payload = """ +if G.SAVED_GAME == nil then + e.config.colour = G.C.UI.BACKGROUND_INACTIVE + e.config.button = nil + return _can_continue +end +""" + +## Fix loading a blind with $0 reward +# Blind:load() +[[patches]] +[patches.regex] +target = 'blind.lua' +pattern = ''' +(?[\t ]*) G\.HUD_blind\.alignment\.offset\.y = 0 +[\t ]*end''' +position = 'at' +payload = ''' +end +if G.GAME.blind.name and G.GAME.blind.name ~= '' then + G.HUD_blind.alignment.offset.y = 0 +end''' +line_prepend = '$indent' + +## Remove incorrect check for Moveable alignment change +# Moveable:align_to_major() +[[patches]] +[patches.regex] +target = 'engine/moveable.lua' +pattern = ''' +(?[\t ]*)if +self\.alignment\.prev_offset\.x == self\.alignment\.offset\.x[\s\S]*?return end +''' +position = 'at' +payload = 'if not self.alignment.type_list then return end' +line_prepend = '$indent' + +## Prevent softlock if booster pack is empty +## Crashes the game when you skip too fast on this PR, along with being the culprit for allowing you to skip boosters early +# G.FUNCS.can_skip_booster() +# [[patches]] +# [patches.pattern] +# target = 'functions/button_callbacks.lua' +# pattern = 'if G.pack_cards and (G.pack_cards.cards[1]) and' +# position = 'at' +# payload = 'if G.pack_cards and' +# match_indent = true + +## Set `G.your_collection.config.collection` to true in all cases +# create_UIBox_your_collection_seals() +[[patches]] +[patches.regex] +target = 'functions/UI_definitions.lua' +pattern = '''\{card_limit = 4, type = 'title', highlight_limit = 0\}''' +position = 'at' +payload = '''{card_limit = 4, type = 'title', highlight_limit = 0, collection = true}''' + +## Save and load Card.unique_val +# Card:save() +[[patches]] +[patches.pattern] +target = 'card.lua' +pattern = "bypass_lock = self.bypass_lock," +position = "after" +payload = """ +unique_val = self.unique_val, +unique_val__saved_ID = self.ID, +ignore_base_shader = self.ignore_base_shader, +ignore_shadow = self.ignore_shadow,""" +match_indent = true + +# Card:load() +[[patches]] +[patches.pattern] +target = 'card.lua' +pattern = "self.bypass_lock = cardTable.bypass_lock" +position = "after" +payload = """ +self.unique_val = cardTable.unique_val or self.unique_val +if cardTable.unique_val__saved_ID and G.ID <= cardTable.unique_val__saved_ID then + G.ID = cardTable.unique_val__saved_ID + 1 +end + +self.ignore_base_shader = cardTable.ignore_base_shader or {} +self.ignore_shadow = cardTable.ignore_shadow or {}""" +match_indent = true + +## Vars in card descriptions should use `card.ability` instead of `_c.config` where possible +## Allow passing in custom vars +# generate_card_ui() +[[patches]] +[patches.pattern] +target = 'functions/common_events.lua' +pattern = 'function generate_card_ui(_c, full_UI_table, specific_vars, card_type, badges, hide_desc, main_start, main_end)' +position = 'at' +match_indent = true +payload = '''function generate_card_ui(_c, full_UI_table, specific_vars, card_type, badges, hide_desc, main_start, main_end, card) + if _c.specific_vars then specific_vars = _c.specific_vars end''' + +[[patches]] +[patches.pattern] +target = 'functions/common_events.lua' +pattern = "if _c.set == 'Other' then" +position = 'before' +match_indent = true +payload = "local cfg = (card and card.ability) or _c['config']" # string index to make sure the next patch doesn't eat it + +[[patches]] +[patches.pattern] +target = 'functions/common_events.lua' +pattern = "if _c.name ~= 'Stone Card' and ((specific_vars and specific_vars.bonus_chips) or _c.config.bonus) then" +position = 'at' +match_indent = true +payload = "if _c.name ~= 'Stone Card' and ((specific_vars and specific_vars.bonus_chips) or (cfg.bonus ~= 0 and cfg.bonus)) then" + +[[patches]] +[patches.regex] +target = 'functions/common_events.lua' +pattern = '_c.config' +position = 'at' +payload = 'cfg' + +## When overriding with set_ability and card is added to deck, call add / remove effects +# Card:set_ability() +[[patches]] +[patches.pattern] +target = 'card.lua' +pattern = "self.config.center = center" +position = 'at' +match_indent = true +payload = ''' +if delay_sprites == 'quantum' then self.from_quantum = true end +if self.added_to_deck and old_center and not self.debuff then + self:remove_from_deck() + self.added_to_deck = true +end +if type(center) == 'string' then + assert(G.P_CENTERS[center]) + center = G.P_CENTERS[center] +end +self.config.center = center +''' + +[[patches]] +[patches.pattern] +target = 'card.lua' +pattern = "if G.consumeables and self.area == G.consumeables then" +position = 'before' +match_indent = true +payload = ''' +if self.added_to_deck and old_center and not self.debuff then + self.added_to_deck = false + self:add_to_deck() +end +self.from_quantum = nil''' + + +## set_ability() transfers over old fields +# special cases: +# extra_value should be transferred +# name, effect, set, extra should always be overwritten +[[patches]] +[patches.regex] +target = 'card.lua' +pattern = ''' +(?[\t ]*)self\.ability = (\{[\s\S]*? +[\t ]*\}) +''' +position = 'at' +line_prepend = '$indent' +payload = ''' +local new_ability = $2 +self.ability = self.ability or {} +new_ability.extra_value = nil +self.ability.extra_value = self.ability.extra_value or 0 +for k, v in pairs(new_ability) do + self.ability[k] = v +end +-- reset keys do not persist an ability change +local reset_keys = {'name', 'effect', 'set', 'extra', 'played_this_ante', 'perma_debuff'} +for _, mod in ipairs(SMODS.mod_list) do + if mod.set_ability_reset_keys then + local keys = mod.set_ability_reset_keys() + for _, v in pairs(keys) do table.insert(reset_keys, v) end + end +end +for _, k in ipairs(reset_keys) do + self.ability[k] = new_ability[k] +end +''' + +## Fix crash if self.config.card == nil for non-vanilla set_ability() calls +# Card:set_ability() +[[patches]] +[patches.pattern] +target = 'card.lua' +pattern = "self.label = center.label or self.config.card.label or self.ability.set" +position = 'at' +match_indent = true +payload = "self.label = center.label or self.config.card and self.config.card.label or self.ability.set" + +### Fix Matador + +# These patches have been removed for altering vanilla behavior. Git blame this line to see what they were + +### Fix Crimson Heart + +## Blind:drawn_to_hand() +[[patches]] +[patches.regex] +target = 'blind.lua' +pattern = "if self.name == 'Crimson Heart' and self.prepped and G.jokers.cards\\[1\\] then" +position = 'after' +payload = """ + + local prev_chosen_set = {} + local fallback_jokers = {}""" +# Fix bad logic if not enough choices for debuff +[[patches]] +[patches.regex] +target = 'blind.lua' +pattern = ''' +(?[\t ]*)for i = 1, #G\.jokers\.cards do +[\t ]*if not G\.jokers\.cards\[i\]\.debuff or #G\.jokers\.cards < 2 then jokers\[#jokers\+1\] = ?G\.jokers\.cards\[i\] end +[\t ]*G\.jokers\.cards\[i\]:set_debuff\(false\) +[\t ]*end''' +position = 'at' +line_prepend = '$indent' +payload = """ +for i = 1, #G.jokers.cards do + if G.jokers.cards[i].ability.crimson_heart_chosen then + prev_chosen_set[G.jokers.cards[i]] = true + G.jokers.cards[i].ability.crimson_heart_chosen = nil + if G.jokers.cards[i].debuff then SMODS.recalc_debuff(G.jokers.cards[i]) end + end +end +for i = 1, #G.jokers.cards do + if not G.jokers.cards[i].debuff then + if not prev_chosen_set[G.jokers.cards[i]] then + jokers[#jokers+1] = G.jokers.cards[i] + end + table.insert(fallback_jokers, G.jokers.cards[i]) + end +end +if #jokers == 0 then jokers = fallback_jokers end""" +# Add variable for Crimson Heart's choice +[[patches]] +[patches.pattern] +target = 'blind.lua' +pattern = "_card:set_debuff(true)" +position = "at" +match_indent = true +payload = """ +_card.ability.crimson_heart_chosen = true +SMODS.recalc_debuff(_card)""" + +## Blind:debuff_card() +[[patches]] +[patches.regex] +target = 'blind.lua' +pattern = ''' +if self\.name == 'Crimson Heart' and not self\.disabled and card\.area == G\.jokers then\s+ +((?[\t ]*)return)''' +root_capture = '$1' +position = "at" +line_prepend = '$indent' +payload = """ +if card.ability.crimson_heart_chosen then + card:set_debuff(true); + if card.debuff then card.debuffed_by_blind = true end + return +end""" + +## Blind:press_play() +# Shouldn't work with Matador +# yes it should + +## Blind:disable() +[[patches]] +[patches.regex] +target = 'blind.lua' +pattern = "elseif self.name == 'The Water' then" +position = 'at' +payload = """ +elseif self.name == 'Crimson Heart' then + for _, v in ipairs(G.jokers.cards) do + v.ability.crimson_heart_chosen = nil + end + elseif self.name == 'The Water' then""" + +## Blind:defeat() +[[patches]] +[patches.regex] +target = 'blind.lua' +pattern = "elseif self.name == 'The Manacle' and not self.disabled then" +position = 'at' +payload = """ +elseif self.name == 'Crimson Heart' then + for _, v in ipairs(G.jokers.cards) do + v.ability.crimson_heart_chosen = nil + end + elseif self.name == 'The Manacle' and not self.disabled then""" + + +## Fix Manacle's unnecessary card draw after positive G.hand:change_size() +# Blind:disable() +[[patches]] +[patches.regex] +target = 'blind.lua' +pattern = 'G\.hand:change_size\(1\)(\s+G\.FUNCS\.draw_from_deck_to_hand\(1\))' +root_capture = '$1' +position = 'at' +payload = "" + +# +# Money scaling fix +# + +## create_UIBox_HUD +[[patches]] +[patches.regex] +target = "functions/UI_definitions.lua" +pattern = ''' +string = \{\{ref_table = G\.GAME\, ref_value = 'dollars'\, prefix = localize\('\$'\)\}\}\,''' +position = "after" +payload = ''' + + scale_function = function () + return scale_number(G.GAME.dollars, 2.2 * scale, 99999, 1000000) + end,''' + +## DynaText:update_text +[[patches]] +[patches.pattern] +target = "engine/text.lua" +pattern = 'self.config.H = 0' +position = "after" +payload = "self.scale = self.config.scale_function and self.config.scale_function() or self.scale" +match_indent = true + + +# +# Fix gold stake legendary infloop +# Do not try to roll for jokers that are not in_pool +# + +# generate_starting_seed() +[[patches]] +[patches.pattern] +target = "functions/misc_functions.lua" +pattern = '''if win_ante and (win_ante >= 8) then''' +match_indent = true +position = "at" +payload = '''if win_ante and (win_ante >= 8) or (v.in_pool and type(v.in_pool) == 'function' and not v:in_pool()) then''' + +# +# Fix G.GAME.blind:set_blind(nil, true, nil) +# being called when not in blind. +# + +# Card:add_to_deck +# Card:remove_from_deck +[[patches]] +[patches.regex] +target = "card.lua" +pattern = 'if G\.GAME\.blind then' +position = "at" +payload = "if G.GAME.blind and G.GAME.blind.in_blind and not self.from_quantum then" + +# end_round() +[[patches]] +[patches.pattern] +target = "functions/state_events.lua" +pattern = "local game_over = true" +position = "before" +payload = "G.GAME.blind.in_blind = false" +match_indent = true + + + +# Make sure new param is loaded +[[patches]] +[patches.pattern] +target = "blind.lua" +match_indent = true +pattern = "function Blind:load(blindTable)" +position = "after" +payload = ''' + self.in_blind = blindTable.in_blind''' + +# Make sure new param is saved +[[patches]] +[patches.pattern] +target = "blind.lua" +match_indent = true +pattern = "local blindTable = {" +position = "after" +payload = ''' + in_blind = self.in_blind,''' + +# Cartomancer and astronomer unlock when *actually all* Tarot/Planet cards are discovered +# check_for_unlock() +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +match_indent = true +pattern = "if card.unlock_condition.tarot_count <= args.tarot_count then" +position = "at" +payload = 'if #G.P_CENTER_POOLS.Tarot <= args.tarot_count then' + +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +match_indent = true +pattern = "if card.unlock_condition.planet_count <= args.planet_count then" +position = "at" +payload = 'if #G.P_CENTER_POOLS.Planet <= args.planet_count then' + +# wtf +[[patches]] +[patches.pattern] +target = "engine/animatedsprite.lua" +match_indent = true +pattern = "for _, v in pairs(G.ANIMATIONS) do" +position = "at" +payload = 'for k, v in pairs(G.ANIMATIONS) do' + +[[patches]] +[patches.pattern] +target = "engine/animatedsprite.lua" +match_indent = true +pattern = "for _, v in pairs(G.I.SPRITE) do" +position = "at" +payload = 'for k, v in pairs(G.I.SPRITE) do' + +## Make vanilla enhancement jokers work with extra enhancements + +# Steel Joker +[[patches]] +[patches.pattern] +target = "card.lua" +match_indent = true +pattern = "if v.config.center == G.P_CENTERS.m_steel then self.ability.steel_tally = self.ability.steel_tally+1 end" +position = "at" +payload = "if SMODS.has_enhancement(v, 'm_steel') then self.ability.steel_tally = self.ability.steel_tally+1 end" + +# Stone Joker +[[patches]] +[patches.pattern] +target = "card.lua" +match_indent = true +pattern = "if v.config.center == G.P_CENTERS.m_stone then self.ability.stone_tally = self.ability.stone_tally+1 end" +position = "at" +payload = "if SMODS.has_enhancement(v, 'm_stone') then self.ability.stone_tally = self.ability.stone_tally+1 end" + +# Golden Ticket +[[patches]] +[patches.pattern] +target = "card.lua" +match_indent = true +pattern = "context.other_card.ability.name == 'Gold Card' then" +position = "at" +payload = "SMODS.has_enhancement(context.other_card, 'm_gold') then" + +# Golden Ticket Unlock +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +match_indent = true +pattern = "if args.cards[j].ability.name == 'Gold Card' then" +position = "at" +payload = "if SMODS.has_enhancement(args.cards[j], 'm_gold') then" + +# Glass Joker +[[patches]] +[patches.pattern] +target = "card.lua" +match_indent = true +pattern = "if val.ability.name == 'Glass Card' then shattered_glass = shattered_glass + 1 end" +position = "at" +payload = "if SMODS.has_enhancement(val, 'm_glass') then shattered_glass = shattered_glass + 1 end" + +# Driver's License +[[patches]] +[patches.pattern] +target = "card.lua" +match_indent = true +pattern = "if v.config.center ~= G.P_CENTERS.c_base then self.ability.driver_tally = self.ability.driver_tally+1 end" +position = "at" +payload = "if next(SMODS.get_enhancements(v)) then self.ability.driver_tally = self.ability.driver_tally+1 end" +# Basegame fix for the reroll vouchers redeem function when only the center but no card object exists + +# Card:apply_to_run +[[patches]] +[patches.pattern] +target = 'card.lua' +pattern = """G.GAME.round_resets.reroll_cost = G.GAME.round_resets.reroll_cost - self.ability.extra""" +position = 'at' +match_indent = true +payload = """G.GAME.round_resets.reroll_cost = G.GAME.round_resets.reroll_cost - center_table.extra""" + +# Card:apply_to_run +[[patches]] +[patches.pattern] +target = 'card.lua' +pattern = """G.GAME.current_round.reroll_cost = math.max(0, G.GAME.current_round.reroll_cost - self.ability.extra)""" +position = 'at' +match_indent = true +payload = """G.GAME.current_round.reroll_cost = math.max(0, G.GAME.current_round.reroll_cost - center_table.extra)""" + + +# Fix booster skip issues maybe? +[[patches]] +[patches.pattern] +target = "functions/button_callbacks.lua" +pattern = "if G.pack_cards and (G.pack_cards.cards[1]) and" +position = "at" +payload = ''' +if G.pack_cards and (not (G.GAME.STOP_USE and G.GAME.STOP_USE > 0)) and +''' +match_indent = true + +# Due to STOP_USE being used we can remove this dumb check +# could probably remove the rest of it since it serves no purpose otherwise, but whatever +[[patches]] +[patches.regex] +target = "functions/button_callbacks.lua" +pattern = '''and \(G\.hand\.cards\[1\] or \(G\.hand\.config\.card_limit <= 0\)\)''' +position = "at" +payload = ''' ''' + +# Fix prng calls on collection advancing seeds +# Keep vanilla behaviour for to-do list +[[patches]] +[patches.pattern] +target = "functions/misc_functions.lua" +pattern = "if key == 'seed' then return math.random() end" +position = "after" +payload = """ +if G.SETTINGS.paused and key ~= 'to_do' then return math.random() end +""" +overwrite = true +match_indent = true + +# Fixes Steam API not loading on unix +[[patches]] +[patches.pattern] +target = 'main.lua' +match_indent = true +position = 'after' +pattern = '--To control when steam communication happens, make sure to send updates to steam as little as possible' +payload = '''local cwd = NFS.getWorkingDirectory() +NFS.setWorkingDirectory(love.filesystem.getSourceBaseDirectory()) +''' + +[[patches]] +[patches.pattern] +target = 'main.lua' +match_indent = true +position = 'before' +pattern = '--Set up the render window and the stage for the splash screen, then enter the gameloop with :update' +payload = '''NFS.setWorkingDirectory(cwd) +''' + +[[patches]] +[patches.pattern] +target = "main.lua" +pattern = '''if os == 'OS X' or os == 'Windows' then''' +position = "at" +payload = '''if os == 'OS X' or os == 'Windows' or os == 'Linux' then''' +overwrite = true +match_indent = true + +[[patches]] +[patches.pattern] +target = "main.lua" +pattern = '''if os == 'OS X' then''' +position = "at" +payload = '''if os == 'OS X' or os == 'Linux' then''' +overwrite = true +match_indent = true + +[[patches]] +[patches.pattern] +target = "main.lua" +pattern = "st = require 'luasteam'" +position = "at" +payload = """local success, _st = pcall(require, 'luasteam') +if success then st = _st else sendWarnMessage(_st, "LuaSteam"); st = {} end""" +overwrite = true +match_indent = true + +# copy_card edition config +[[patches]] +[patches.pattern] +target = 'functions/common_events.lua' +position = 'after' +match_indent = true +pattern = 'new_card:set_edition(other.edition or {}, nil, true)' +payload = '''for k,v in pairs(other.edition or {}) do + if type(v) == 'table' then + new_card.edition[k] = copy_table(v) + else + new_card.edition[k] = v + end +end''' + +# fix Smeared Joker compat issues with modded suits +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "if next(find_joker('Smeared Joker')) and (self.base.suit == 'Hearts' or self.base.suit == 'Diamonds') == (suit == 'Hearts' or suit == 'Diamonds') then" +position = "at" +payload = "if next(find_joker('Smeared Joker')) and SMODS.smeared_check(self, suit) then" +overwrite = true +match_indent = true + +# fix Seeing Double compat issues with modded suits +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = """local suits = { + ['Hearts'] = 0, + ['Diamonds'] = 0, + ['Spades'] = 0, + ['Clubs'] = 0 +} +for i = 1, #context.scoring_hand do + if not SMODS.has_any_suit(context.scoring_hand[i]) then + if context.scoring_hand[i]:is_suit('Hearts') then suits["Hearts"] = suits["Hearts"] + 1 end + if context.scoring_hand[i]:is_suit('Diamonds') then suits["Diamonds"] = suits["Diamonds"] + 1 end + if context.scoring_hand[i]:is_suit('Spades') then suits["Spades"] = suits["Spades"] + 1 end + if context.scoring_hand[i]:is_suit('Clubs') then suits["Clubs"] = suits["Clubs"] + 1 end + end +end +for i = 1, #context.scoring_hand do + if SMODS.has_any_suit(context.scoring_hand[i]) then + if context.scoring_hand[i]:is_suit('Clubs') and suits["Clubs"] == 0 then suits["Clubs"] = suits["Clubs"] + 1 + elseif context.scoring_hand[i]:is_suit('Diamonds') and suits["Diamonds"] == 0 then suits["Diamonds"] = suits["Diamonds"] + 1 + elseif context.scoring_hand[i]:is_suit('Spades') and suits["Spades"] == 0 then suits["Spades"] = suits["Spades"] + 1 + elseif context.scoring_hand[i]:is_suit('Hearts') and suits["Hearts"] == 0 then suits["Hearts"] = suits["Hearts"] + 1 end + end +end +if (suits["Hearts"] > 0 or +suits["Diamonds"] > 0 or +suits["Spades"] > 0) and +suits["Clubs"] > 0 then + return { + message = localize{type='variable',key='a_xmult',vars={self.ability.extra}}, + Xmult_mod = self.ability.extra + } +end""" +position = "at" +payload = """if SMODS.seeing_double_check(context.scoring_hand, 'Clubs') then + return { + message = localize{type='variable',key='a_xmult',vars={self.ability.extra}}, + Xmult_mod = self.ability.extra + } +end""" +overwrite = true +match_indent = true diff --git a/Steamodded/lovely/gradient.toml b/Steamodded/lovely/gradient.toml new file mode 100644 index 0000000..782aaf5 --- /dev/null +++ b/Steamodded/lovely/gradient.toml @@ -0,0 +1,16 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = -10 + +# Game:update +[[patches]] +[patches.pattern] +target = "game.lua" +pattern = "self.C.EDITION[2] = 0.7+0.2*(1+math.sin(self.TIMERS.REAL*1.5 + 6))" +position = "after" +payload = ''' +for _,v in pairs(SMODS.Gradients) do + v:update(dt) +end''' +match_indent = true \ No newline at end of file diff --git a/Steamodded/lovely/joker_retriggers.toml b/Steamodded/lovely/joker_retriggers.toml new file mode 100644 index 0000000..72dfbdc --- /dev/null +++ b/Steamodded/lovely/joker_retriggers.toml @@ -0,0 +1,364 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = -10 + + +# Luchador +[[patches]] +[patches.regex] +target = "card.lua" +pattern = '''[ \t]*G\.GAME\.blind:disable\(\) +(?[ \t]*)end''' +position = "at" +line_prepend = '$indent' +payload = ''' G.GAME.blind:disable() + return nil, true +end''' + +# Diet Cola +[[patches]] +[patches.regex] +target = "card.lua" +pattern = ''' +[ \t]*return true +[ \t]*end\) +[ \t]*\}\)\) +(?[ \t]*)end +''' +position = "at" +line_prepend = '$indent' +payload = ''' return true + end) + })) + return nil, true +end +''' + +# Invisible Joker +[[patches]] +[patches.regex] +target = "card.lua" +pattern = '''[ \t]*if card\.ability\.invis_rounds then card\.ability\.invis_rounds = 0 end +[ \t]*card:add_to_deck\(\) +(?[ \t]*)G\.jokers:emplace\(card\)''' +position = "after" +line_prepend = '$indent' +payload = "return nil, true" + +# Campfire +[[patches]] +[patches.regex] +target = "card.lua" +pattern = '''localize\('k_upgrade_ex'\)\}\); return true +[ \t]*end\}\)\) +[ \t]*end +(?[ \t]*)return''' +position = "at" +line_prepend = '$indent' +payload = '''localize('k_upgrade_ex')}); return true + end})) +end +if self.ability.name == 'Campfire' and not context.blueprint then return nil, true end''' + +# Flash Card +[[patches]] +[patches.regex] +target = "card.lua" +pattern = '''[ \t]*G\.C\.MULT\}\) +[ \t]*return true +[ \t]*end\)\}\)\) +(?[ \t]*)end''' +position = "at" +line_prepend = '$indent' +payload = '''G.C.MULT}) + return true + end)})) +end +if self.ability.name == 'Flash Card' and not context.blueprint then return nil, true end''' + +# Perkeo +[[patches]] +[patches.regex] +target = "card.lua" +pattern = '''[ \t]*card_eval_status_text\(context\.blueprint_card or self, 'extra', nil, nil, nil, \{message = localize\('k_duplicated_ex'\)\}\) +(?[ \t]*)end''' +position = "at" +line_prepend = '$indent' +payload = ''' card_eval_status_text(context.blueprint_card or self, 'extra', nil, nil, nil, {message = localize('k_duplicated_ex')}) + return nil, true +end''' + +# Throwback +[[patches]] +[patches.regex] +target = "card.lua" +pattern = ''' +[ \t]*end +[ \t]*return +(?[ \t]*)elseif context\.skipping_booster''' +position = "before" +line_prepend = '$indent' +payload = "return nil, true" + +# Red Card +[[patches]] +[patches.regex] +target = "card.lua" +pattern = ''' +[ \t]*end +[ \t]*return +(?[ \t]*)elseif context\.playing_card_added''' +position = "before" +line_prepend = '$indent' +payload = "return nil, true" + +# Hologram +[[patches]] +[patches.regex] +target = "card.lua" +pattern = ''' +[ \t]*end +(?[ \t]*)elseif context\.first_hand_drawn''' +position = "before" +line_prepend = '$indent' +payload = "return nil, true" + +# Certificate +[[patches]] +[patches.regex] +target = "card.lua" +pattern = ''' +[ \t]*end +(?[ \t]*)if self\.ability\.name == 'DNA' and not context\.blueprint''' +position = "before" +line_prepend = '$indent' +payload = "return nil, true" + +# Chicot +[[patches]] +[patches.regex] +target = "card.lua" +pattern = ''' +[ \t]*end +(?[ \t]*)if self\.ability\.name == 'Madness' ''' +position = "before" +line_prepend = '$indent' +payload = "return nil, true" + +# Madness +[[patches]] +[patches.regex] +target = "card.lua" +pattern = ''' +[ \t]*end +(?[ \t]*)if self\.ability\.name == 'Burglar' ''' +position = "before" +line_prepend = '$indent' +payload = "return nil, true" + +# Burglar +[[patches]] +[patches.regex] +target = "card.lua" +pattern = ''' +[ \t]*end +(?[ \t]*)if self\.ability\.name == 'Riff-raff' ''' +position = "before" +line_prepend = '$indent' +payload = "return nil, true" + +# Riff-raff +[[patches]] +[patches.regex] +target = "card.lua" +pattern = ''' +[ \t]*end +(?[ \t]*)if self\.ability\.name == 'Cartomancer' ''' +position = "before" +line_prepend = '$indent' +payload = "return nil, true" + +# Cartomancer +[[patches]] +[patches.regex] +target = "card.lua" +pattern = ''' +[ \t]*end +(?[ \t]*)if self\.ability\.name == 'Ceremonial Dagger' and not context.blueprint''' +position = "before" +line_prepend = '$indent' +payload = "return nil, true" + +# Ceremonial Dagger +[[patches]] +[patches.regex] +target = "card.lua" +pattern = ''' +[ \t]*end +[ \t]*end +(?[ \t]*)if self\.ability\.name == 'Marble Joker' ''' +position = "before" +line_prepend = '$indent' +payload = "return nil, true" + +# Marble Joker +[[patches]] +[patches.regex] +target = "card.lua" +pattern = ''' +[ \t]*end +[ \t]*return +(?[ \t]*)elseif context.destroying_card''' +position = "before" +line_prepend = '$indent' +payload = "return nil, true" + +# Caino +[[patches]] +[patches.regex] +target = "card.lua" +pattern = '''[ \t]*func = function\(\) card_eval_status_text\(self, 'extra', nil, nil, nil, \{message = localize\{type = 'variable', key = 'a_xmult', vars = \{self\.ability\.caino_xmult\}\}\}\); return true +(?[ \t]*)end\}\)\)''' +position = "after" +line_prepend = '$indent' +payload = "return nil, true" + +# Glass Joker +[[patches]] +[patches.regex] +target = "card.lua" +pattern = '''glass_cards\}\}\}\) +[ \t]*return true +[ \t]*end +(?[ \t]*)\}\)\)''' +position = "after" +line_prepend = '$indent' +payload = "return nil, true" + +[[patches]] +[patches.regex] +target = "card.lua" +pattern = ''' +[ \t]*end +[ \t]*return +[ \t]*end +(?[ \t]*)if self\.ability\.name == 'Fortune Teller' and not context\.blueprint''' +position = "before" +line_prepend = '$indent' +payload = "return nil, true" + +# Fortune Teller +[[patches]] +[patches.regex] +target = "card.lua" +pattern = ''' +[ \t]*end +(?[ \t]*)if self\.ability\.name == 'Constellation' and not context\.blueprint''' +position = "before" +line_prepend = '$indent' +payload = "return nil, true" + +# Constellation +[[patches]] +[patches.regex] +target = "card.lua" +pattern = ''' +[ \t]*end +[ \t]*return +(?[ \t]*)elseif context.debuffed_hand''' +position = "before" +line_prepend = '$indent' +payload = "nil, true" + +# Burnt Joker +[[patches]] +[patches.regex] +target = "card.lua" +pattern = ''' +[ \t]*end +(?[ \t]*)elseif context.discard''' +position = "before" +line_prepend = '$indent' +payload = "return nil, true" + +# Faceless Joker +[[patches]] +[patches.regex] +target = "card.lua" +pattern = ''' +[ \t]*end +[ \t]*end +[ \t]*return +(?[ \t]*)elseif context.end_of_round''' +position = "before" +line_prepend = '$indent' +payload = "nil, true" + +# Yorick +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "self.ability.yorick_discards = self.ability.yorick_discards - 1" +position = "after" +match_indent = true +payload = "return nil, true" + +# Hallucination +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "card_eval_status_text(self, 'extra', nil, nil, nil, {message = localize('k_plus_tarot'), colour = G.C.PURPLE})" +position = "after" +match_indent = true +payload = "return nil, true" + +## Change card returns +# Ramen +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = ''' +message = localize('k_eaten_ex'), +colour = G.C.FILTER''' +position = "before" +match_indent = true +payload = "card = self," +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = '''message = localize{type='variable',key='a_xmult_minus',vars={self.ability.extra}},''' +position = "before" +match_indent = true +payload = "card = self," + +# Yorick +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = ''' +delay = 0.2, +message = localize{type='variable',key='a_xmult',vars={self.ability.x_mult}},''' +position = "before" +match_indent = true +payload = "card = self," + +# To Do List +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = '''message = localize('$')..self.ability.extra.dollars, + dollars = self.ability.extra.dollars,''' +position = "at" +match_indent = true +payload = '''message = localize('$')..self.ability.extra.dollars,''' + +# Matador +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = '''message = localize('$')..self.ability.extra, + dollars = self.ability.extra,''' +position = "at" +match_indent = true +payload = '''message = localize('$')..self.ability.extra,''' diff --git a/Steamodded/lovely/joker_size.toml b/Steamodded/lovely/joker_size.toml new file mode 100644 index 0000000..aa591aa --- /dev/null +++ b/Steamodded/lovely/joker_size.toml @@ -0,0 +1,73 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = -5 + +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = ''' +if _center.name == 'Square Joker' and (_center.discovered or self.bypass_discovery_center) then + self.children.center.scale.y = self.children.center.scale.x +end +''' +position = "after" +payload = ''' +if _center.pixel_size and _center.pixel_size.h and (_center.discovered or self.bypass_discovery_center) then + self.children.center.scale.y = self.children.center.scale.y*(_center.pixel_size.h/95) +end +if _center.pixel_size and _center.pixel_size.w and (_center.discovered or self.bypass_discovery_center) then + self.children.center.scale.x = self.children.center.scale.x*(_center.pixel_size.w/71) +end +''' +match_indent = true +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = ''' +if center.name == "Wee Joker" and (center.discovered or self.bypass_discovery_center) then + H = H*0.7 + W = W*0.7 + self.T.h = H + self.T.w = W +end +''' +position = "after" +payload = ''' +if center.display_size and center.display_size.h and (center.discovered or self.bypass_discovery_center) then + H = H*(center.display_size.h/95) + self.T.h = H +elseif center.pixel_size and center.pixel_size.h and (center.discovered or self.bypass_discovery_center) then + H = H*(center.pixel_size.h/95) + self.T.h = H +end +if center.display_size and center.display_size.w and (center.discovered or self.bypass_discovery_center) then + W = W*(center.display_size.w/71) + self.T.w = W +elseif center.pixel_size and center.pixel_size.w and (center.discovered or self.bypass_discovery_center) then + W = W*(center.pixel_size.w/71) + self.T.w = W +end +''' +match_indent = true +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = ''' +self.VT.h = self.T.H +self.VT.w = self.T.w +''' +position = "before" +payload = ''' +if self.config.center.display_size and self.config.center.display_size.h then + self.T.h = H*(self.config.center.display_size.h/95) +elseif self.config.center.pixel_size and self.config.center.pixel_size.h then + self.T.h = H*(self.config.center.pixel_size.h/95) +end +if self.config.center.display_size and self.config.center.display_size.w then + self.T.w = W*(self.config.center.display_size.w/71) +elseif self.config.center.pixel_size and self.config.center.pixel_size.w then + self.T.w = W*(self.config.center.pixel_size.w/71) +end +''' +match_indent = true diff --git a/Steamodded/lovely/keybind.toml b/Steamodded/lovely/keybind.toml new file mode 100644 index 0000000..80272b8 --- /dev/null +++ b/Steamodded/lovely/keybind.toml @@ -0,0 +1,82 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = -5 + +# Check all registered keybinds +# inserted inside Controller:key_press_update + +[[patches]] +[patches.pattern] +target = 'engine/controller.lua' +pattern = "if not _RELEASE_MODE then" +position = "before" +payload = ''' +for _, keybind in pairs(SMODS.Keybinds) do + if keybind.action and keybind.key_pressed == key and keybind.event == 'pressed' then + local execute = true + for _, other_key in pairs(keybind.held_keys) do + if not self.held_keys[other_key] then + execute = false + break + end + end + if execute then + keybind:action() + end + end +end +''' +match_indent = true + +# Controller:key_release_update +[[patches]] +[patches.pattern] +target = 'engine/controller.lua' +pattern = "function Controller:key_release_update(key, dt)" +position = "after" +payload = ''' +for _, keybind in pairs(SMODS.Keybinds) do + if keybind.action and keybind.key_pressed == key and keybind.event == 'released' then + local execute = true + for _, other_key in pairs(keybind.held_keys) do + if not self.held_keys[other_key] then + execute = false + break + end + end + if execute then + keybind:action() + end + end +end +''' +match_indent = true + +[[patches]] +[patches.regex] +target = 'engine/controller.lua' +pattern = 'if key == "r"' +position = 'before' +line_prepend = '$indent' +payload = ''' +for _, keybind in pairs(SMODS.Keybinds) do + if keybind.key_pressed == key and keybind.event == 'held' and keybind.held_duration then + if self.held_key_times[key] > keybind.held_duration then + local execute = true + for _, other_key in pairs(keybind.held_keys) do + if not self.held_keys[other_key] then + execute = false + break + end + end + if execute then + keybind:action() + self.held_key_times[key] = nil + end + else + self.held_key_times[key] = self.held_key_times[key] + dt + end + end +end +''' diff --git a/Steamodded/lovely/language.toml b/Steamodded/lovely/language.toml new file mode 100644 index 0000000..b89ebff --- /dev/null +++ b/Steamodded/lovely/language.toml @@ -0,0 +1,59 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = -10 + +### Language API + +# Game:set_language() +[[patches]] +[patches.pattern] +target = 'game.lua' +pattern = "if not (love.filesystem.read('localization/'..G.SETTINGS.language..'.lua')) or G.F_ENGLISH_ONLY then" +position = 'at' +payload = 'if false then' +match_indent = true + +[[patches]] +[patches.pattern] +target = 'game.lua' +pattern = "local localization = love.filesystem.getInfo('localization/'..G.SETTINGS.language..'.lua')" +position = 'at' +payload = "local localization = love.filesystem.getInfo('localization/'..G.SETTINGS.language..'.lua') or love.filesystem.getInfo('localization/en-us.lua')" +match_indent = true + +[[patches]] +[patches.pattern] +target = 'game.lua' +pattern = "self.localization = assert(loadstring(love.filesystem.read('localization/'..G.SETTINGS.language..'.lua')))()" +position = 'at' +payload = """self.localization = assert(loadstring(love.filesystem.read('localization/'..G.SETTINGS.language..'.lua') or love.filesystem.read('localization/en-us.lua'), '=[localization "'..G.SETTINGS.language..'.lua"]'))()""" +match_indent = true + +[[patches]] +[patches.pattern] +target = 'game.lua' +pattern = "self.LANG = self.LANGUAGES[self.SETTINGS.language] or self.LANGUAGES['en-us']" +position = 'at' +payload = "self.LANG = self.LANGUAGES[self.SETTINGS.real_language or self.SETTINGS.language] or self.LANGUAGES['en-us']" +match_indent = true + +# G.FUNCS.change_lang + +[[patches]] +[patches.pattern] +target = 'functions/button_callbacks.lua' +pattern = "G.SETTINGS.language = lang.key" +position = 'at' +payload = """G.SETTINGS.language = lang.loc_key or lang.key +G.SETTINGS.real_language = lang.key""" +match_indent = true + +# G.FUNCS.warn_lang (wtf) +[[patches]] +[patches.pattern] +target = 'functions/button_callbacks.lua' +pattern = 'if (_infotip_object.config.set ~= e.config.ref_table.label) and (not G.F_NO_ACHIEVEMENTS) then' +position = 'at' +payload = 'if (_infotip_object.config.set ~= e.config.ref_table.label) then' +match_indent = true diff --git a/Steamodded/lovely/libs.toml b/Steamodded/lovely/libs.toml new file mode 100644 index 0000000..2d2e542 --- /dev/null +++ b/Steamodded/lovely/libs.toml @@ -0,0 +1,34 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = -5 + +[[patches]] +[patches.module] +source = "libs/json/json.lua" +before = "main.lua" +name = "json" + +[[patches]] +[patches.module] +source = "libs/nativefs/nativefs.lua" +before = "main.lua" +name = "nativefs" + +[[patches]] +[patches.module] +source = "libs/https/luajit-curl.lua" +before = "main.lua" +name = "luajit-curl" + +[[patches]] # Ensure the thread can also load this +[patches.module] +source = "libs/https/luajit-curl.lua" +before = '=[SMODS _ "smods-https-thread.lua"]' +name = "luajit-curl" + +[[patches]] +[patches.module] +source = "libs/https/smods-https.lua" +before = "main.lua" +name = "SMODS.https" diff --git a/Steamodded/lovely/loader.toml b/Steamodded/lovely/loader.toml new file mode 100644 index 0000000..dfe4bd9 --- /dev/null +++ b/Steamodded/lovely/loader.toml @@ -0,0 +1,27 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = -5 + +### Supporting code for loader.lua + +## Save discovered, unlocked states +# Game:init_item_prototypes() +[[patches]] +[patches.pattern] +target = 'game.lua' +pattern = "meta.alerted = meta.alerted or {}" +position = 'after' +payload = ''' +for _, t in ipairs{ + G.P_CENTERS, + G.P_BLINDS, + G.P_TAGS, + G.P_SEALS, +} do + for k, v in pairs(t) do + SMODS._save_d_u(v) + v._discovered_unlocked_overwritten = true + end +end''' +match_indent = true diff --git a/Steamodded/lovely/menu.toml b/Steamodded/lovely/menu.toml new file mode 100644 index 0000000..0e3e9fb --- /dev/null +++ b/Steamodded/lovely/menu.toml @@ -0,0 +1,60 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = -5 + +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +pattern = '''local main_menu = nil''' +position = "after" +payload = '''local mods = nil''' +match_indent = true + +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +pattern = '''main_menu = UIBox_button{ label = {localize('b_main_menu')}, button = "go_to_menu", minw = 5}''' +position = "after" +payload = '''mods = UIBox_button{ id = "mods_button", label = {localize('b_mods')}, button = "mods_button", minw = 5}''' +match_indent = true + +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = '''G.ARGS.set_alerts_alertables[11].should_alert = alert_booster''' +position = "after" +payload = '''table.insert(G.ARGS.set_alerts_alertables, {id = 'mods_button', alert_uibox_name = 'mods_button_alert', should_alert = SMODS.mod_button_alert})''' +match_indent = true + +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +pattern = '''main_menu,''' +position = "after" +payload = '''mods,''' +match_indent = true + + +[[patches]] +[patches.pattern] +target = 'game.lua' +pattern = '''self.ASSET_ATLAS[self.asset_atli[i].name].image = love.graphics.newImage(self.asset_atli[i].path, {mipmaps = true, dpiscale = self.SETTINGS.GRAPHICS.texture_scaling})''' +position = 'after' +payload = ''' +local mipmap_level = SMODS.config.graphics_mipmap_level_options[SMODS.config.graphics_mipmap_level] +if mipmap_level and mipmap_level > 0 then + self.ASSET_ATLAS[self.asset_atli[i].name].image:setMipmapFilter('linear', mipmap_level) +end''' +match_indent = true + + +[[patches]] +[patches.pattern] +target = 'functions/UI_definitions.lua' +pattern = '''create_option_cycle({w = 4,scale = 0.8, label = localize("b_set_CRT_bloom"),options = localize('ml_bloom_opt'), opt_callback = 'change_crt_bloom', current_option = G.SETTINGS.GRAPHICS.bloom}),''' +position = 'after' +payload = ''' +create_option_cycle({label = localize('b_graphics_mipmap_level'),scale = 0.8, options = SMODS.config.graphics_mipmap_level_options, opt_callback = 'SMODS_change_mipmap', current_option = SMODS.config.graphics_mipmap_level}),''' +match_indent = true + diff --git a/Steamodded/lovely/mod.toml b/Steamodded/lovely/mod.toml new file mode 100644 index 0000000..8feb0d8 --- /dev/null +++ b/Steamodded/lovely/mod.toml @@ -0,0 +1,72 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = -5 + +### Per-mod functions + +# end_round() +[[patches]] +[patches.regex] +target = 'functions/state_events.lua' +pattern = '''(?[\t ]*)reset_castle_card\(\)''' +line_prepend = '$indent' +position = 'after' +payload = ''' + +for _, mod in ipairs(SMODS.mod_list) do + if mod.reset_game_globals and type(mod.reset_game_globals) == 'function' then + mod.reset_game_globals(false) + end +end''' + +# Game:start_run() +[[patches]] +[patches.regex] +target = 'game.lua' +pattern = '''(?[\t ]*)reset_castle_card\(\)''' +line_prepend = '$indent' +position = 'after' +payload = ''' + +for _, mod in ipairs(SMODS.mod_list) do + if mod.reset_game_globals and type(mod.reset_game_globals) == 'function' then + mod.reset_game_globals(true) + end +end''' + +# Card:set_debuff() +[[patches]] +[patches.pattern] +target = 'card.lua' +pattern = "function Card:set_debuff(should_debuff)" +position = 'after' +match_indent = true +payload = ''' + for _, mod in ipairs(SMODS.mod_list) do + if mod.set_debuff and type(mod.set_debuff) == 'function' then + local res = mod.set_debuff(self) + if res == 'prevent_debuff' then + if self.debuff then + self.debuff = false + if self.area == G.jokers then self:add_to_deck(true) end + self.debuffed_by_blind = false + end + return + end + should_debuff = should_debuff or res + end + end + for k, v in pairs(self.ability.debuff_sources or {}) do + if v == 'prevent_debuff' then + if self.debuff then + self.debuff = false + if self.area == G.jokers then self:add_to_deck(true) end + end + self.debuffed_by_blind = false + return + end + should_debuff = should_debuff or v + end + +''' diff --git a/Steamodded/lovely/number_formatting.toml b/Steamodded/lovely/number_formatting.toml new file mode 100644 index 0000000..0107ffa --- /dev/null +++ b/Steamodded/lovely/number_formatting.toml @@ -0,0 +1,171 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = -10 + +# +# Use number_format for... +# + +# DynaText + +[[patches]] +[patches.regex] +target = "engine/text.lua" +pattern = 'tostring\((?v\.ref_table and v\.ref_table\[v\.ref_value\] or v\.string)\)' +position = "at" +payload = "format_ui_value($param)" + +# Cash Out + +[[patches]] +[patches.regex] +target = "functions/common_events.lua" +pattern = ''' +localize\('\$'\)\.\.config\.dollars''' +position = "at" +payload = "localize('$')..format_ui_value(config.dollars)" + +# End of round money + +[[patches]] +[patches.regex] +target = "functions/common_events.lua" +pattern = ''' +localize\('\$'\)\.\.num_dollars\}''' +position = "at" +payload = "localize('$')..format_ui_value(num_dollars)}" + +# Tooltip numbers + +[[patches]] +[patches.regex] +target = "functions/misc_functions.lua" +pattern = '(?args\.vars\[tonumber\(subpart\[1\]\)\])' +position = "at" +payload = 'format_ui_value($param)' + +# Poker Hand chips + +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +pattern = "{n=G.UIT.T, config={text = G.GAME.hands[handname].chips, scale = 0.45, colour = G.C.UI.TEXT_LIGHT}}," +position = "at" +payload = "{n=G.UIT.T, config={text = number_format(G.GAME.hands[handname].chips, 1000000), scale = 0.45, colour = G.C.UI.TEXT_LIGHT}}," +match_indent = true + +# Poker Hand mult + +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +pattern = "{n=G.UIT.T, config={text = G.GAME.hands[handname].mult, scale = 0.45, colour = G.C.UI.TEXT_LIGHT}}" +position = "at" +payload = "{n=G.UIT.T, config={text = number_format(G.GAME.hands[handname].mult, 1000000), scale = 0.45, colour = G.C.UI.TEXT_LIGHT}}" +match_indent = true + +# Continue Run - Money + +[[patches]] +[patches.regex] +target = "functions/UI_definitions.lua" +pattern = 'tostring\(saved_game\.GAME\.dollars\)' +position = "at" +payload = "format_ui_value(saved_game.GAME.dollars)" + +# Continue Run - Best Hand - bigger size + +[[patches]] +[patches.regex] +target = "functions/UI_definitions.lua" +pattern = 'scale_number\(saved_game\.GAME\.round_scores\.hand\.amt\, 0\.8\*scale\)' +position = "at" +payload = "scale_number(saved_game.GAME.round_scores.hand.amt, 0.8*scale, 100000000000)" + + +# +# Custom sci notation switch point +# + +## number_format +[[patches]] +[patches.pattern] +target = "functions/misc_functions.lua" +pattern = 'function number_format(num)' +position = "at" +payload = ''' +function number_format(num, e_switch_point) + if type(num) ~= 'number' then return num end + + local sign = (num >= 0 and "") or "-" + num = math.abs(num)''' +match_indent = true + +[[patches]] +[patches.regex] +target = "functions/misc_functions.lua" +pattern = 'num >= G\.E_SWITCH_POINT' +position = "at" +payload = "num >= (e_switch_point or G.E_SWITCH_POINT)" + +# 1. Fix floating point error (1.000e92 instead of 10.000e91) +# 2. Lower precision with higher numbers +[[patches]] +[patches.pattern] +target = "functions/misc_functions.lua" +pattern = ''' +return string.format("%.3f",x/(10^fac))..'e'..fac''' +position = "at" +payload = ''' +if num == math.huge then + return sign.."naneinf" +end + +local mantissa = round_number(x/(10^fac), 3) +if mantissa >= 10 then + mantissa = mantissa / 10 + fac = fac + 1 +end +return sign..(string.format(fac >= 100 and "%.1fe%i" or fac >= 10 and "%.2fe%i" or "%.3fe%i", mantissa, fac))''' +match_indent = true + +# Remove trailing zeroes +# E.g. X1.5 being displayed as X1.50 +[[patches]] +[patches.pattern] +target = "functions/misc_functions.lua" +pattern = ''' +return string.format(num ~= math.floor(num) and (num >= 100 and "%.0f" or num >= 10 and "%.1f" or "%.2f") or "%.0f", num):reverse():gsub("(%d%d%d)", "%1,"):gsub(",$", ""):reverse()''' +position = "at" +payload = ''' +local formatted +if num ~= math.floor(num) and num < 100 then + formatted = string.format(num >= 10 and "%.1f" or "%.2f", num) + if formatted:sub(-1) == "0" then + formatted = formatted:gsub("%.?0+$", "") + end + -- Return already to avoid comas being added + if num < 0.01 then return tostring(num) end +else + formatted = string.format("%.0f", num) +end +return sign..(formatted:reverse():gsub("(%d%d%d)", "%1,"):gsub(",$", ""):reverse())''' +match_indent = true + +## scale_number +[[patches]] +[patches.pattern] +target = "functions/button_callbacks.lua" +pattern = 'function scale_number(number, scale, max)' +position = "at" +payload = 'function scale_number(number, scale, max, e_switch_point)' +match_indent = true + +[[patches]] +[patches.regex] +target = "functions/button_callbacks.lua" +pattern = 'number >= G\.E_SWITCH_POINT' +position = "at" +payload = "math.abs(number) >= (e_switch_point or G.E_SWITCH_POINT)" + diff --git a/Steamodded/lovely/perma_bonus.toml b/Steamodded/lovely/perma_bonus.toml new file mode 100644 index 0000000..6bf2387 --- /dev/null +++ b/Steamodded/lovely/perma_bonus.toml @@ -0,0 +1,337 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = -5 + +### Permanent card values implementations +## Adapted from AMM (https://github.com/AutumnMood924/AutumnMoodMechanics) + +# generate_card_ui(): mult card special case +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = "if _c.effect == 'Mult Card' then loc_vars = {cfg.mult}" +position = "at" +payload = "if _c.effect == 'Mult Card' then loc_vars = {SMODS.signed(cfg.mult + (specific_vars and specific_vars.bonus_mult or 0))}" +match_indent = true + +# generate_card_ui(): gold card special case +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = "elseif _c.effect == 'Gold Card' then loc_vars = {cfg.h_dollars}" +position = "at" +payload = "elseif _c.effect == 'Gold Card' then loc_vars = {specific_vars and SMODS.signed_dollars(specific_vars.total_h_dollars) or cfg.h_dollars and SMODS.signed_dollars(cfg.h_dollars) or 0}" +match_indent = true + +# generate_card_ui(): stone card special case +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = "elseif _c.effect == 'Stone Card' then loc_vars = {((specific_vars and specific_vars.bonus_chips) or cfg.bonus)}" +position = "at" +payload = "elseif _c.effect == 'Stone Card' then loc_vars = {((specific_vars and SMODS.signed(specific_vars.bonus_chips)) or cfg.bonus and SMODS.signed(cfg.bonus) or 0)}" +match_indent = true + +# generate_card_ui(): show permanent bonuses on default playing cards +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = "elseif _c.set == 'Enhanced' then" +position = "before" +payload = ''' +if specific_vars and specific_vars.bonus_x_chips then + localize{type = 'other', key = 'card_x_chips', nodes = desc_nodes, vars = {specific_vars.bonus_x_chips}} +end +if specific_vars and specific_vars.bonus_mult then + localize{type = 'other', key = 'card_extra_mult', nodes = desc_nodes, vars = {SMODS.signed(specific_vars.bonus_mult)}} +end +if specific_vars and specific_vars.bonus_x_mult then + localize{type = 'other', key = 'card_x_mult', nodes = desc_nodes, vars = {specific_vars.bonus_x_mult}} +end +if specific_vars and specific_vars.bonus_h_chips then + localize{type = 'other', key = 'card_extra_h_chips', nodes = desc_nodes, vars = {SMODS.signed(specific_vars.bonus_h_chips)}} +end +if specific_vars and specific_vars.bonus_h_x_chips then + localize{type = 'other', key = 'card_h_x_chips', nodes = desc_nodes, vars = {specific_vars.bonus_h_x_chips}} +end +if specific_vars and specific_vars.bonus_h_mult then + localize{type = 'other', key = 'card_extra_h_mult', nodes = desc_nodes, vars = {SMODS.signed(specific_vars.bonus_h_mult)}} +end +if specific_vars and specific_vars.bonus_h_x_mult then + localize{type = 'other', key = 'card_h_x_mult', nodes = desc_nodes, vars = {specific_vars.bonus_h_x_mult}} +end +if specific_vars and specific_vars.bonus_p_dollars then + localize{type = 'other', key = 'card_extra_p_dollars', nodes = desc_nodes, vars = {SMODS.signed_dollars(specific_vars.bonus_p_dollars)}} +end +if specific_vars and specific_vars.bonus_h_dollars then + localize{type = 'other', key = 'card_extra_h_dollars', nodes = desc_nodes, vars = {SMODS.signed_dollars(specific_vars.bonus_h_dollars)}} +end''' +match_indent = true +overwrite = false + +# generate_card_ui(): signed(extra_chips) +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = "localize{type = 'other', key = 'card_extra_chips', nodes = desc_nodes, vars = {specific_vars.bonus_chips}}" +position = "at" +match_indent = true +payload = "localize{type = 'other', key = 'card_extra_chips', nodes = desc_nodes, vars = {SMODS.signed(specific_vars.bonus_chips)}}" + +# generate_card_ui(): signed(extra_chips) +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = "localize{type = 'other', key = 'card_extra_chips', nodes = desc_nodes, vars = {((specific_vars and specific_vars.bonus_chips) or cfg.bonus)}}" +position = "at" +match_indent = true +payload = "localize{type = 'other', key = 'card_extra_chips', nodes = desc_nodes, vars = {SMODS.signed((specific_vars and specific_vars.bonus_chips) or cfg.bonus)}}" + +# generate_card_ui(): show permanent bonuses on enhanced playing cards +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = "elseif _c.set == 'Booster' then" +position = "before" +payload = ''' +if specific_vars and specific_vars.bonus_x_chips then + localize{type = 'other', key = 'card_x_chips', nodes = desc_nodes, vars = {specific_vars.bonus_x_chips}} +end +if specific_vars and specific_vars.bonus_mult and _c.effect ~= 'Mult Card' then + localize{type = 'other', key = 'card_extra_mult', nodes = desc_nodes, vars = {SMODS.signed(specific_vars.bonus_mult)}} +end +if specific_vars and specific_vars.bonus_x_mult then + localize{type = 'other', key = 'card_x_mult', nodes = desc_nodes, vars = {specific_vars.bonus_x_mult}} +end +if specific_vars and specific_vars.bonus_h_chips then + localize{type = 'other', key = 'card_extra_h_chips', nodes = desc_nodes, vars = {SMODS.signed(specific_vars.bonus_h_chips)}} +end +if specific_vars and specific_vars.bonus_h_x_chips then + localize{type = 'other', key = 'card_h_x_chips', nodes = desc_nodes, vars = {specific_vars.bonus_h_x_chips}} +end +if specific_vars and specific_vars.bonus_h_mult then + localize{type = 'other', key = 'card_extra_h_mult', nodes = desc_nodes, vars = {SMODS.signed(specific_vars.bonus_h_mult)}} +end +if specific_vars and specific_vars.bonus_h_x_mult then + localize{type = 'other', key = 'card_h_x_mult', nodes = desc_nodes, vars = {specific_vars.bonus_h_x_mult}} +end +if specific_vars and specific_vars.bonus_p_dollars then + localize{type = 'other', key = 'card_extra_p_dollars', nodes = desc_nodes, vars = {SMODS.signed_dollars(specific_vars.bonus_p_dollars)}} +end +if specific_vars and specific_vars.bonus_h_dollars and _c.effect ~= 'Gold Card' then + localize{type = 'other', key = 'card_extra_h_dollars', nodes = desc_nodes, vars = {SMODS.signed_dollars(specific_vars.bonus_h_dollars)}} +end''' +match_indent = true +overwrite = false + +# generate_UIBox_ability_table(): prime locals for easier boolean magic +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "loc_vars = { playing_card = not not self.base.colour, value = self.base.value, suit = self.base.suit, colour = self.base.colour," +position = "before" +payload = '''local bonus_chips = self.ability.bonus + (self.ability.perma_bonus or 0) +local total_h_dollars = self:get_h_dollars()''' +match_indent = true +overwrite = false + +# generate_UIBox_ability_table(): prime specific_vars for playing cards +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "bonus_chips = (self.ability.bonus + (self.ability.perma_bonus or 0)) > 0 and (self.ability.bonus + (self.ability.perma_bonus or 0)) or nil," +position = "at" +payload = ''' +bonus_x_chips = self.ability.perma_x_chips ~= 0 and (self.ability.perma_x_chips + 1) or nil, +bonus_mult = self.ability.perma_mult ~= 0 and self.ability.perma_mult or nil, +bonus_x_mult = self.ability.perma_x_mult ~= 0 and (self.ability.perma_x_mult + 1) or nil, +bonus_h_chips = self.ability.perma_h_chips ~= 0 and self.ability.perma_h_chips or nil, +bonus_h_x_chips = self.ability.perma_h_x_chips ~= 0 and (self.ability.perma_h_x_chips + 1) or nil, +bonus_h_mult = self.ability.perma_h_mult ~= 0 and self.ability.perma_h_mult or nil, +bonus_h_x_mult = self.ability.perma_h_x_mult ~= 0 and (self.ability.perma_h_x_mult + 1) or nil, +bonus_p_dollars = self.ability.perma_p_dollars ~= 0 and self.ability.perma_p_dollars or nil, +bonus_h_dollars = self.ability.perma_h_dollars ~= 0 and self.ability.perma_h_dollars or nil, +total_h_dollars = total_h_dollars ~= 0 and total_h_dollars or nil, +bonus_chips = bonus_chips ~= 0 and bonus_chips or nil,''' +match_indent = true +overwrite = false + +# set_ability: set defaults for temporary bonuses +# Also add conformance with SMODS documentation. +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "x_mult = center.config.Xmult or 1," +position = "at" +payload = ''' +x_mult = center.config.Xmult or center.config.x_mult or 1, +h_chips = center.config.h_chips or 0, +x_chips = center.config.x_chips or 1, +h_x_chips = center.config.h_x_chips or 1, +''' +match_indent = true +overwrite = false + +# set_ability: set defaults for permanent bonuses +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "perma_bonus = self.ability and self.ability.perma_bonus or 0," +position = "after" +payload = ''' +perma_x_chips = self.ability and self.ability.perma_x_chips or 0, +perma_mult = self.ability and self.ability.perma_mult or 0, +perma_x_mult = self.ability and self.ability.perma_x_mult or 0, +perma_h_chips = self.ability and self.ability.perma_h_chips or 0, +perma_h_x_chips = self.ability and self.ability.perma_h_x_chips or 0, +perma_h_mult = self.ability and self.ability.perma_hmult or 0, +perma_h_x_mult = self.ability and self.ability.perma_h_x_mult or 0, +perma_p_dollars = self.ability and self.ability.perma_p_dollars or 0, +perma_h_dollars = self.ability and self.ability.perma_h_dollars or 0, +''' +match_indent = true +overwrite = false + +# Card:get_chip_mult +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = '''if self.ability.effect == "Lucky Card" then + if pseudorandom('lucky_mult') < G.GAME.probabilities.normal/5 then + self.lucky_trigger = true + return self.ability.mult + else + return 0 + end +else + return self.ability.mult +end''' +position = "at" +match_indent = true +payload = '''local ret = self.ability.perma_mult or 0 +if self.ability.effect == "Lucky Card" then + if pseudorandom('lucky_mult') < G.GAME.probabilities.normal/5 then + self.lucky_trigger = true + ret = ret + self.ability.mult + end +else + ret = ret + self.ability.mult +end +-- TARGET: get_chip_mult +return ret''' + +# Card:get_chip_x_mult +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = '''if self.ability.x_mult <= 1 then return 0 end +return self.ability.x_mult''' +position = "at" +match_indent = true +payload = '''local ret = SMODS.multiplicative_stacking(self.ability.x_mult or 1, self.ability.perma_x_mult or 0) +-- TARGET: get_chip_x_mult +return ret +''' + +# Card:get_chip_h_mult +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = 'return self.ability.h_mult' +position = "at" +match_indent = true +payload = '''local ret = (self.ability.h_mult or 0) + (self.ability.perma_h_mult or 0) +-- TARGET: get_chip_h_mult +return ret +''' + +# Card:get_chip_h_x_mult +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = 'return self.ability.h_x_mult' +position = "at" +match_indent = true +payload = '''local ret = SMODS.multiplicative_stacking(self.ability.h_x_mult or 1, self.ability.perma_h_x_mult or 0) +-- TARGET: get_chip_h_x_mult +return ret +''' + +# Card:get_chip_x_bonus +# Card:get_chip_h_bonus +# Card:get_chip_h_x_bonus +# Card:get_h_dollars +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = 'function Card:get_edition()' +position = "before" +match_indent = true +payload = ''' +function Card:get_chip_x_bonus() + if self.debuff then return 0 end + local ret = SMODS.multiplicative_stacking(self.ability.x_chips or 1, self.ability.perma_x_chips or 0) + -- TARGET: get_chip_x_bonus + return ret +end + +function Card:get_chip_h_bonus() + if self.debuff then return 0 end + local ret = (self.ability.h_chips or 0) + (self.ability.perma_h_chips or 0) + -- TARGET: get_chip_h_bonus + return ret +end + +function Card:get_chip_h_x_bonus() + if self.debuff then return 0 end + local ret = SMODS.multiplicative_stacking(self.ability.h_x_chips or 1, self.ability.perma_h_x_chips or 0) + -- TARGET: get_chip_h_x_bonus + return ret +end + +function Card:get_h_dollars() + if self.debuff then return 0 end + local ret = (self.ability.h_dollars or 0) + (self.ability.perma_h_dollars or 0) + -- TARGET: get_h_dollars + return ret +end +''' + +# Card:get_p_dollars +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = '''end +if ret > 0 then + G.GAME.dollar_buffer = (G.GAME.dollar_buffer or 0) + ret''' +position = "at" +match_indent = true +payload = '''elseif self.ability.p_dollars < 0 then + ret = ret + self.ability.p_dollars +end +ret = ret + (self.ability.perma_p_dollars) or 0 +-- TARGET: get_p_dollars +if ret ~= 0 then + G.GAME.dollar_buffer = (G.GAME.dollar_buffer or 0) + ret''' + +# Card:get_end_of_round_effect +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = ''' +if self.ability.h_dollars > 0 then + ret.h_dollars = self.ability.h_dollars + ret.card = self +end +''' +position = "at" +match_indent = true +payload = ''' +local h_dollars = self:get_h_dollars() +if h_dollars ~= 0 then + ret.h_dollars = h_dollars + ret.card = self +end +''' +times = 1 diff --git a/Steamodded/lovely/playing_card.toml b/Steamodded/lovely/playing_card.toml new file mode 100644 index 0000000..8889bb6 --- /dev/null +++ b/Steamodded/lovely/playing_card.toml @@ -0,0 +1,302 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = -10 + +### Playing Card API + +# Game:init_game_object() +[[patches]] +[patches.pattern] +target = 'game.lua' +pattern = 'function Game:init_game_object()' +position = 'after' +match_indent = true +payload = ''' + local cards_played = {} + for _,v in ipairs(SMODS.Rank.obj_buffer) do + cards_played[v] = { suits = {}, total = 0 } + end''' + +[[patches]] +[patches.regex] +target = "game.lua" +pattern = '(?[\t ]*)cards_played = \{\n(.*\n){13}[\t ]*\},' +position = 'at' +line_prepend = '$indent' +payload = ''' + cards_played = cards_played, + disabled_suits = {}, + disabled_ranks = {},''' + +# Game:start_run() +[[patches]] +[patches.pattern] +target = "game.lua" +pattern = 'local _ = nil' +position = 'before' +match_indent = true +payload = ''' +if type(SMODS.Ranks[v.value].in_pool) == 'function' and not SMODS.Ranks[v.value]:in_pool({initial_deck = true, suit = v.suit}) +or type(SMODS.Suits[v.suit].in_pool) == 'function' and not SMODS.Suits[v.suit]:in_pool({initial_deck = true, rank = v.value}) then + goto continue +end''' + +[[patches]] +[patches.pattern] +target = "game.lua" +pattern = "if self.GAME.starting_params.erratic_suits_and_ranks then _, k = pseudorandom_element(G.P_CARDS, pseudoseed('erratic')) end" +position = 'at' +match_indent = true +payload = '''if self.GAME.starting_params.erratic_suits_and_ranks then + v, k = pseudorandom_element(G.P_CARDS, pseudoseed('erratic'), {starting_deck = true}) +end''' + +[[patches]] +[patches.pattern] +target = "game.lua" +pattern = 'local _r, _s = string.sub(k, 3, 3), string.sub(k, 1, 1)' +position = 'at' +match_indent = true +payload = 'local _r, _s = SMODS.Ranks[v.value].card_key, SMODS.Suits[v.suit].card_key' + +[[patches]] +[patches.pattern] +target = "game.lua" +pattern = "if self.GAME.starting_params.no_faces and (_r == 'K' or _r == 'Q' or _r == 'J') then keep = false end" +position = 'at' +match_indent = true +payload = ''' +if self.GAME.starting_params.no_faces and SMODS.Ranks[v.value].face then keep = false end''' + +[[patches]] +[patches.pattern] +target = "game.lua" +pattern = "if keep then card_protos[#card_protos+1] = {s=_s,r=_r,e=_e,d=_d,g=_g} end" +position = "after" +payload = "::continue::" +match_indent = true + +# loc_colour() +[[patches]] +[patches.pattern] +target = 'functions/misc_functions.lua' +pattern = 'return G.ARGS.LOC_COLOURS[_c] or _default or G.C.UI.TEXT_DARK' +position = 'before' +match_indent = true +payload = ''' + for _, v in ipairs(SMODS.Rarity.obj_buffer) do + G.ARGS.LOC_COLOURS[v:lower()] = G.C.RARITY[v] + end + for _, v in ipairs(SMODS.Gradient.obj_buffer) do + G.ARGS.LOC_COLOURS[v:lower()] = SMODS.Gradients[v] + end + for _, v in ipairs(SMODS.ConsumableType.ctype_buffer) do + G.ARGS.LOC_COLOURS[v:lower()] = G.C.SECONDARY_SET[v] + end + for _, v in ipairs(SMODS.Suit.obj_buffer) do + G.ARGS.LOC_COLOURS[v:lower()] = G.C.SUITS[v] + end''' + +# get_flush() +[[patches]] +[patches.regex] +target = "functions/misc_functions.lua" +pattern = '(?[\t ]*)local suits = \{\n[\t ]*"Spades",\n[\t ]*"Hearts",\n[\t ]*"Clubs",\n[\t ]*"Diamonds"\n[\t ]*\}\n[\t ]*if #hand > 5 or (?#hand < \(5 - \(four_fingers and 1 or 0\)\) then return ret else)' +position = 'at' +line_prepend = '$indent' +payload = ''' +local suits = SMODS.Suit.obj_buffer +if $restcond''' + +# get_X_same() +[[patches]] +[patches.pattern] +target = 'functions/misc_functions.lua' +pattern = 'local vals = {{},{},{},{},{},{},{},{},{},{},{},{},{},{}}' +position = 'at' +match_indent = true +payload = ''' +local vals = {} +for i = 1, SMODS.Rank.max_id.value do + vals[i] = {} +end''' + +[[patches]] +[patches.pattern] +target = 'functions/misc_functions.lua' +pattern = 'function get_X_same(num, hand)' +position = 'at' +match_indent = true +payload = '''function get_X_same(num, hand, or_more)''' + +[[patches]] +[patches.pattern] +target = 'functions/misc_functions.lua' +pattern = 'if #curr == num then' +position = 'at' +match_indent = true +payload = '''if or_more and (#curr >= num) or (#curr == num) then''' + +# Card:get_nominal() +[[patches]] +[patches.regex] +target = "card.lua" +pattern = 'function Card:get_nominal\(mod\)\n([\t ]+.*\n)*end' +position = 'at' +payload = ''' +function Card:get_nominal(mod) + local mult = 1 + local rank_mult = 1 + if mod == 'suit' then mult = 10000 end + if self.ability.effect == 'Stone Card' or (self.config.center.no_suit and self.config.center.no_rank) then + mult = -10000 + elseif self.config.center.no_suit then + mult = 0 + elseif self.config.center.no_rank then + rank_mult = 0 + end + return 10*self.base.nominal*rank_mult + self.base.suit_nominal*mult + (self.base.suit_nominal_original or 0)*0.0001*mult + 10*self.base.face_nominal*rank_mult + 0.000001*self.unique_val +end''' + +# Card:set_base() +[[patches]] +[patches.regex] +target = 'card.lua' +pattern = "(?[\t ]*)if self.base.value == '2' then self.base.nominal = 2; self.base.id = 2(\n[\t ]+elseif .*)*" +position = 'at' +line_prepend = '$indent' +payload = ''' +local rank = SMODS.Ranks[self.base.value] or {} +self.base.nominal = rank.nominal or 0 +self.base.face_nominal = rank.face_nominal or 0 +self.base.id = rank.id''' + +[[patches]] +[patches.regex] +target = 'card.lua' +pattern = "(?[\t ]*)if self.base.suit == 'Diamonds' then self.base.suit_nominal = 0.01; self.base.suit_nominal_original = suit_base_nominal_original or 0.001 (\n[\t ]+elseif .*)*" +position = 'at' +line_prepend = '$indent' +payload = ''' +local suit = SMODS.Suits[self.base.suit] or {} +self.base.suit_nominal = suit.suit_nominal or 0 +self.base.suit_nominal_original = suit_base_nominal_original or suit.suit_nominal or 0''' + +# Card:change_suit() +[[patches]] +[patches.regex] +target = 'card.lua' +pattern = "(?[\t ]*)local new_code = [\\s\\S]*?local new_val = [\\s\\S]*?local new_card = G.P_CARDS\\[new_code..new_val\\]" +position = 'at' +line_prepend = '$indent' +payload = ''' +local new_code = SMODS.Suits[new_suit].card_key +local new_val = SMODS.Ranks[self.base.value].card_key +local new_card = G.P_CARDS[new_code..'_'..new_val]''' + +# Card:is_face() +[[patches]] +[patches.regex] +target = 'card.lua' +pattern = "(?[\t ]*)if id == 11 or id == 12 or id == 13 or next\\(find_joker\\(\"Pareidolia\"\\)\\) then" +position = 'at' +line_prepend = '$indent' +payload = ''' +local rank = SMODS.Ranks[self.base.value] +if not id then return end +if (id > 0 and rank and rank.face) or next(find_joker("Pareidolia")) then''' + + +# tally_sprite() +[[patches]] +[patches.regex] +target = 'functions/UI_definitions.lua' +pattern = '(?[\t ]*local t_s = Sprite\(0,0,0.5,0.5,)G.ASSET_ATLAS\[.*?\](?.*?\))' +position = 'at' +payload = '$start G.ASSET_ATLAS[suit and SMODS.Suits[suit][G.SETTINGS.colourblind_option and "hc_ui_atlas" or "lc_ui_atlas"]] or G.ASSET_ATLAS[("ui_"..(G.SETTINGS.colourblind_option and "2" or "1"))]$rest' + +[[patches]] +[patches.pattern] +target = 'functions/UI_definitions.lua' +pattern = 'function tally_sprite(pos, value, tooltip)' +position = 'at' +match_indent = true +payload = 'function tally_sprite(pos, value, tooltip, suit)' + +# G.UIDEF.challenge_description_tab() +[[patches]] +[patches.regex] +target = 'functions/UI_definitions.lua' +pattern = "(?[\t ]*)local SUITS = \\{(\n.*){5}\n[\t ]*local suit_map = \\{'S', 'H', 'C', 'D'\\}" +position = 'at' +line_prepend = '$indent' +payload = ''' +local SUITS = {} +local suit_map = {} +for i = #SMODS.Suit.obj_buffer, 1, -1 do + local suit = SMODS.Suits[SMODS.Suit.obj_buffer[i]] + SUITS[suit.card_key] = {} + suit_map[#suit_map+1] = suit.card_key +end''' + +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +pattern = 'local _r, _s = string.sub(k, 3, 3), string.sub(k, 1, 1)' +position = 'at' +match_indent = true +payload = 'local _r, _s = SMODS.Ranks[v.value].card_key, SMODS.Suits[v.suit].card_key' + +# TODO there may need to be a way to let in_pool know what challenge is being displayed +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +pattern = 'local keep, _e, _d, _g = true, nil, nil, nil' +position = 'after' +match_indent = true +payload = ''' +if type(SMODS.Ranks[v.value].in_pool) == 'function' and not SMODS.Ranks[v.value]:in_pool({initial_deck = true, suit = v.suit}) then + keep = false +end +if type(SMODS.Suits[v.suit].in_pool) == 'function' and not SMODS.Suits[v.suit]:in_pool({initial_deck = true, rank = v.value}) then + keep = false +end''' + +[[patches]] +[patches.regex] +target = 'functions/UI_definitions.lua' +pattern = '(?[\t ]*)for j = 1, 4 do\n[\t ]*(?if SUITS\[suit_map\[j\]\]\[1\] then\n[\t ]*table.sort.*(\n.*)*?)\n[\t ]*0\.42\*G.CARD_H,' +position = 'at' +line_prepend = '$indent' +payload = ''' +local num_suits = 0 +for j = 1, #suit_map do + if SUITS[suit_map[j]][1] then num_suits = num_suits + 1 end +end +for j = 1, #suit_map do + $mid + (0.42 - (num_suits <= 4 and 0 or num_suits >= 8 and 0.28 or 0.07 * (num_suits - 4))) * G.CARD_H,''' + +[[patches]] +[patches.pattern] +target = 'functions/common_events.lua' +pattern = '--Fill all remaining info if this is the main desc' +position = 'before' +match_indent = true +payload = '''if card_type == 'Default' or card_type == 'Enhanced' and not _c.replace_base_card and card and card.base then + if not _c.no_suit then + local suit = SMODS.Suits[card.base.suit] or {} + if suit.loc_vars and type(suit.loc_vars) == 'function' then + suit:loc_vars(info_queue, card) + end + end + if not _c.no_rank then + local rank = SMODS.Ranks[card.base.value] or {} + if rank.loc_vars and type(rank.loc_vars) == 'function' then + rank:loc_vars(info_queue, card) + end + end +end + +''' diff --git a/Steamodded/lovely/poker_hand.toml b/Steamodded/lovely/poker_hand.toml new file mode 100644 index 0000000..d6f0f05 --- /dev/null +++ b/Steamodded/lovely/poker_hand.toml @@ -0,0 +1,60 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = -5 + +### Poker Hand API + +# evaluate_poker_hand() +[[patches]] +[patches.pattern] +target = "functions/misc_functions.lua" +pattern = "local parts = {" +position = 'before' +payload = ''' +for _,v in ipairs(SMODS.PokerHand.obj_buffer) do + results[v] = {} +end''' +match_indent = true + +[[patches]] +[patches.pattern] +target = "functions/misc_functions.lua" +pattern = "if next(parts._5) and next(parts._flush) then" +position = 'before' +payload = ''' +for _,_hand in pairs(SMODS.PokerHands) do + if _hand.atomic_part and type(_hand.atomic_part) == 'function' then + parts[_hand.key] = _hand.atomic_part(hand) + end +end''' +match_indent = true + +[[patches]] +[patches.pattern] +target = "functions/misc_functions.lua" +pattern = "return results" +position = 'before' +payload = ''' +for _,_hand in pairs(SMODS.PokerHands) do + if _hand.composite and type(_hand.composite) == 'function' then + local other_hands + results[_hand.key], other_hands = _hand.composite(parts) + results[_hand.key] = results[_hand.key] or {} + if other_hands and type(other_hands) == 'table' then + for k, v in pairs(other_hands) do + results[k] = v + end + end + else + results[_hand.key] = parts[_hand.key] + end +end +results.top = nil +for _, v in ipairs(G.handlist) do + if not results.top and results[v] then + results.top = results[v] + break + end +end''' +match_indent = true diff --git a/Steamodded/lovely/pool.toml b/Steamodded/lovely/pool.toml new file mode 100644 index 0000000..2480665 --- /dev/null +++ b/Steamodded/lovely/pool.toml @@ -0,0 +1,185 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = -10 + +### Functions that affect random selection from pools + +# pseudorandom_element() +# TODO special cases for now +[[patches]] +[patches.pattern] +target = "functions/misc_functions.lua" +pattern = "function pseudorandom_element(_t, seed)" +position = "at" +payload = """function pseudorandom_element(_t, seed, args) + -- TODO special cases for now + -- Preserves reverse nominal order for Suits, nominal+face_nominal order for Ranks + -- for vanilla RNG + if _t == SMODS.Suits then + _t = SMODS.Suit:obj_list(true) + end + if _t == SMODS.Ranks then + _t = SMODS.Rank:obj_list() + end +""" +match_indent = true + +[[patches]] +[patches.pattern] +target = "functions/misc_functions.lua" +pattern = "keys[#keys+1] = {k = k,v = v}" +position = "at" +payload = """ +local keep = true +local in_pool_func = + args and args.in_pool + or type(v) == 'table' and type(v.in_pool) == 'function' and v.in_pool + or _t == G.P_CARDS and function(c) + --Handles special case for Erratic Deck + local initial_deck = args and args.starting_deck or false + + return not ( + type(SMODS.Ranks[c.value].in_pool) == 'function' and not SMODS.Ranks[c.value]:in_pool({initial_deck = initial_deck, suit = c.suit}) + or type(SMODS.Suits[c.suit].in_pool) == 'function' and not SMODS.Suits[c.suit]:in_pool({initial_deck = initial_deck, rank = c.value}) + ) + end +if in_pool_func then + keep = in_pool_func(v, args) +end +if keep then + keys[#keys+1] = {k = k,v = v} +end""" +match_indent = true + +# fixes pseudorandom_element on an empty list +# nil, nil is returned in that case +[[patches]] +[patches.pattern] +target = "functions/misc_functions.lua" +pattern = "local key = keys[math.random(#keys)].k" +position = "before" +payload = "if #keys == 0 then return nil, nil end" +match_indent = true + +## get_current_pool() + +# Centers + +[[patches]] +[patches.pattern] +target = 'functions/common_events.lua' +pattern = "else _starting_pool, _pool_key = G.P_CENTER_POOLS[_type], _type..(_append or '')" +match_indent = true +position = 'before' +payload = ''' +elseif SMODS.ObjectTypes[_type] and SMODS.ObjectTypes[_type].rarities then + local rarities = SMODS.ObjectTypes[_type].rarities + local rarity + if _legendary and rarities.legendary then + rarity = rarities.legendary.key + else + rarity = _rarity or SMODS.poll_rarity(_type, 'rarity_'.._type..G.GAME.round_resets.ante..(_append or '')) + end + _starting_pool, _pool_key = SMODS.ObjectTypes[_type].rarity_pools[rarity], _type..rarity..(_append or '')''' + +[[patches]] +[patches.pattern] +target = 'functions/common_events.lua' +pattern = "if _type == 'Tarot' or _type == 'Tarot_Planet' then _pool[#_pool + 1] = \"c_strength\"" +match_indent = true +position = 'at' +payload = ''' +if SMODS.ObjectTypes[_type] and SMODS.ObjectTypes[_type].default and G.P_CENTERS[SMODS.ObjectTypes[_type].default] then + _pool[#_pool+1] = SMODS.ObjectTypes[_type].default +elseif _type == 'Tarot' or _type == 'Tarot_Planet' then _pool[#_pool + 1] = "c_strength"''' + +[[patches]] +[patches.pattern] +target = 'functions/common_events.lua' +pattern = "if v.name == 'Black Hole' or v.name == 'The Soul' then" +match_indent = true +position = 'at' +payload = "if v.name == 'Black Hole' or v.name == 'The Soul' or v.hidden then" + +[[patches]] +[patches.pattern] +target = 'functions/common_events.lua' +pattern = "if _type == 'Enhanced' then" +match_indent = true +position = 'before' +payload = ''' +local in_pool, pool_opts +if v.in_pool and type(v.in_pool) == 'function' then + in_pool, pool_opts = v:in_pool({ source = _append }) +end +pool_opts = pool_opts or {} +''' + +[[patches]] +[patches.pattern] +target = 'functions/common_events.lua' +pattern = 'elseif not (G.GAME.used_jokers[v.key] and not next(find_joker("Showman"))) and' +match_indent = true +position = 'at' +payload = '''elseif not (G.GAME.used_jokers[v.key] and not pool_opts.allow_duplicates and not next(find_joker("Showman"))) and''' + +[[patches]] +[patches.pattern] +target = 'functions/common_events.lua' +pattern = "if add and not G.GAME.banned_keys[v.key] then" +match_indent = true +position = 'before' +payload = ''' +if v.in_pool and type(v.in_pool) == 'function' then + add = in_pool and (add or pool_opts.override_base_checks) +end +''' + +## G.GAME.used_jokers now checks keys, not names +# Card:set_ability() +# Remove the old center from `used_jokers` if set_ability overrides +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "self.config.center = center" +position = 'after' +payload = ''' +if old_center and not next(SMODS.find_card(old_center.key, true)) then + G.GAME.used_jokers[old_center.key] = nil +end''' +match_indent = true +[[patches]] +[patches.regex] +target = "card.lua" +pattern = ''' +(?[\t ]*)for k, v in pairs\(G\.P_CENTERS\) do +[\t ]*if v\.name == self\.ability\.name then +[\t ]*G\.GAME\.used_jokers\[k\] = true +[\t ]*end +[\t ]*end''' +position = "at" +payload = ''' +if self.config.center.key then + G.GAME.used_jokers[self.config.center.key] = true +end +''' +line_prepend = "$indent" +# Card:remove() +[[patches]] +[patches.regex] +target = "card.lua" +pattern = ''' +(?[\t ]*)for k, v in pairs\(G\.P_CENTERS\) do +[\t ]*if v\.name == self\.ability\.name then +[\t ]*if not next\(find_joker\(self\.ability\.name, true\)\) then +[\t ]*G\.GAME\.used_jokers\[k\] = nil +[\t ]*end +[\t ]*end +[\t ]*end''' +position = "at" +payload = ''' +if not next(SMODS.find_card(self.config.center.key, true)) then + G.GAME.used_jokers[self.config.center.key] = nil +end''' +line_prepend = "$indent" diff --git a/Steamodded/lovely/rarity.toml b/Steamodded/lovely/rarity.toml new file mode 100644 index 0000000..efaef67 --- /dev/null +++ b/Steamodded/lovely/rarity.toml @@ -0,0 +1,61 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = -10 + +### Rarity API + +# get_badge_colour +[[patches]] +[patches.pattern] +target = 'functions/UI_definitions.lua' +pattern = 'return G.BADGE_COL[key] or {1, 0, 0, 1}' +position = 'before' +match_indent = true +payload = ''' +for k, v in pairs(SMODS.Rarity.obj_buffer) do + G.BADGE_COL[k] = G.C.RARITY[v] +end''' + +# G.UIDEF.card_h_popup +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +pattern = "if AUT.card_type == 'Joker' or (AUT.badges and AUT.badges.force_rarity) then card_type = ({localize('k_common'), localize('k_uncommon'), localize('k_rare'), localize('k_legendary')})[card.config.center.rarity] end" +position = "at" +payload = "if AUT.card_type == 'Joker' or (AUT.badges and AUT.badges.force_rarity) then card_type = SMODS.Rarity:get_rarity_badge(card.config.center.rarity) end" +match_indent = true + +# Game:update +[[patches]] +[patches.pattern] +target = "game.lua" +pattern = "self.C.EDITION[2] = 0.7+0.2*(1+math.sin(self.TIMERS.REAL*1.5 + 6))" +position = "after" +payload = ''' +for k, v in pairs(SMODS.Rarities) do + if v.gradient and type(v.gradient) == "function" then v:gradient(dt) end +end''' +match_indent = true + +# get_current_pool +[[patches]] +[patches.regex] +target = "functions/common_events.lua" +pattern = '''(?[\t ]*)local rarity = _rarity or pseudorandom\('rarity'\.\.G\.GAME\.round_resets\.ante\.\.\(_append or ''\)\) \n[\s\S]{12}rarity = \(_legendary and 4\) or \(rarity > 0\.95 and 3\) or \(rarity > 0\.7 and 2\) or 1''' +position = "at" +payload = ''' +_rarity = (_legendary and 4) or (type(_rarity) == "number" and ((_rarity > 0.95 and 3) or (_rarity > 0.7 and 2) or 1)) or _rarity +_rarity = ({Common = 1, Uncommon = 2, Rare = 3, Legendary = 4})[_rarity] or _rarity +local rarity = _rarity or SMODS.poll_rarity("Joker", 'rarity'..G.GAME.round_resets.ante..(_append or '')) +''' + +## Ensure that other cards set to string rarity work the same as set for int rarity +# Card:calculate_joker +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "if self.ability.name == 'Baseball Card' and context.other_joker.config.center.rarity == 2 and self ~= context.other_joker then" +position = "at" +payload = '''if self.ability.name == 'Baseball Card' and (context.other_joker.config.center.rarity == 2 or context.other_joker.config.center.rarity == "Uncommon") and self ~= context.other_joker then''' +match_indent = true diff --git a/Steamodded/lovely/seal.toml b/Steamodded/lovely/seal.toml new file mode 100644 index 0000000..62054ea --- /dev/null +++ b/Steamodded/lovely/seal.toml @@ -0,0 +1,224 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = -10 + +### Seal API +# Card:open() +[[patches]] +[patches.regex] +target = 'card.lua' +pattern = ''' +(?[\t ]*)local seal_rate = 10 +[\n\t ]*local seal_poll = pseudorandom\(pseudoseed\('stdseal'..G.GAME.round_resets.ante\)\) +[\n\t ]*if seal_poll > 1 - 0.02\*seal_rate then +[\n\t ]*local seal_type = pseudorandom\(pseudoseed\('stdsealtype'..G.GAME.round_resets.ante\)\) +[\n\t ]*if seal_type > 0.75 then card:set_seal\('Red'\) +[\n\t ]*elseif seal_type > 0.5 then card:set_seal\('Blue'\) +[\n\t ]*elseif seal_type > 0.25 then card:set_seal\('Gold'\) +[\n\t ]*else card:set_seal\('Purple'\) +[\n\t ]*end +[\n\t ]*end''' +position = 'at' +line_prepend = '$indent' +payload = ''' +card:set_seal(SMODS.poll_seal({mod = 10}))''' + +# Card:calculate_joker() +[[patches]] +[patches.regex] +target = 'card.lua' +pattern = ''' +(?[\t ]*)local seal_type = pseudorandom\(pseudoseed\('certsl'\)\) +[\n\t ]*if seal_type > 0.75 then _card:set_seal\('Red', true\) +[\n\t ]*elseif seal_type > 0.5 then _card:set_seal\('Blue', true\) +[\n\t ]*elseif seal_type > 0.25 then _card:set_seal\('Gold', true\) +[\n\t ]*else _card:set_seal\('Purple', true\) +[\n\t ]*end''' +position = 'at' +line_prepend = '$indent' +payload = '''_card:set_seal(SMODS.poll_seal({guaranteed = true, type_key = 'certsl'}))''' + +# get_badge_colour() +[[patches]] +[patches.pattern] +target = 'functions/UI_definitions.lua' +pattern = 'return G.BADGE_COL[key] or {1, 0, 0, 1}' +position = 'before' +match_indent = true +payload = ''' +for k, v in pairs(SMODS.Seals) do + G.BADGE_COL[k:lower()..'_seal'] = v.badge_colour +end''' + +# Card:calculate_seal() +[[patches]] +[patches.regex] +target = "card.lua" +pattern = 'function Card:calculate_seal\(context\)\n(?[\t ]*)if self.debuff then return nil end' +position = 'after' +line_prepend = '$indent' +payload = ''' + + +local obj = G.P_SEALS[self.seal] or {} +if obj.calculate and type(obj.calculate) == 'function' then + local o = obj:calculate(self, context) + if o then + if not o.card then o.card = self end + return o + end +end''' + +# Card:update() +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = 'if G.STAGE == G.STAGES.RUN then' +position = 'before' +match_indent = true +payload = ''' +local obj = G.P_SEALS[self.seal] or {} +if obj.update and type(obj.update) == 'function' then + obj:update(self, dt) +end''' + +# Card:get_p_dollars() +[[patches]] +[patches.regex] +target = "card.lua" +pattern = '''(?[\t ]*)if (?self\.seal == 'Gold' then\n)''' +position = 'at' +line_prepend = '$indent' +payload = ''' +local obj = G.P_SEALS[self.seal] or {} +if obj.get_p_dollars and type(obj.get_p_dollars) == 'function' then + ret = ret + obj:get_p_dollars(self) +elseif $cond''' + +# generate_card_ui() +[[patches]] +[patches.pattern] +target = 'functions/common_events.lua' +pattern = "if v == 'gold_seal'*" +match_indent = true +position = 'before' +payload = ''' +local seal = G.P_SEALS[v] or G.P_SEALS[SMODS.Seal.badge_to_key[v] or ''] +if seal then + info_queue[#info_queue+1] = seal +else''' +[[patches]] +[patches.pattern] +target = 'functions/common_events.lua' +pattern = "if v == 'purple_seal'*" +match_indent = true +position = 'after' +payload = 'end' + +[[patches]] +[patches.regex] +target = 'functions/common_events.lua' +position = 'at' +pattern = '''\{key = (?'.*?_seal'), set = 'Other'\}''' +payload = '''G.P_SEALS[$badge] or G.P_SEALS[SMODS.Seal.badge_to_key[$badge] or '']''' + +# Card:update_alert() +[[patches]] +[patches.pattern] +target = 'card.lua' +pattern = "function Card:update_alert()" +match_indent = true +position = 'after' +payload = ''' + if self.ability.set == 'Default' and self.config.center and self.config.center.key == 'c_base' and self.seal then + if G.P_SEALS[self.seal].alerted and self.children.alert then + self.children.alert:remove() + self.children.alert = nil + elseif not G.P_SEALS[self.seal].alerted and not self.children.alert and G.P_SEALS[self.seal].discovered then + self.children.alert = UIBox{ + definition = create_UIBox_card_alert(), + config = {align="tli", + offset = {x = 0.1, y = 0.1}, + parent = self} + } + end + end''' + +# Card:hover() +[[patches]] +[patches.pattern] +target = 'card.lua' +pattern = "G:save_progress()" +match_indent = false +position = "after" +payload = ''' + elseif self.children.alert and self.seal and not G.P_SEALS[self.seal].alerted then + G.P_SEALS[self.seal].alerted = true + G:save_progress()''' + +# Game:init_item_prototypes() +[[patches]] +[patches.regex] +target = 'game.lua' +pattern = '''(?[\t ]*)Gold =[ {A-z=1-4,"}\n]*},[\n\t ]*}''' +position = 'at' +line_prepend = '$indent' +payload = ''' +Red = {order = 1, discovered = false, set = "Seal"}, +Blue = {order = 2, discovered = false, set = "Seal"}, +Gold = {order = 3, discovered = false, set = "Seal"}, +Purple = {order = 4, discovered = false, set = "Seal"}, +} +''' + +# Card:set_seal() +[[patches]] +[patches.pattern] +target = 'card.lua' +pattern = '''G.CONTROLLER.locks.seal = true''' +position = 'after' +match_indent = true +payload = '''local sound = G.P_SEALS[_seal].sound or {sound = 'gold_seal', per = 1.2, vol = 0.4}''' +[[patches]] +[patches.pattern] +target = 'card.lua' +pattern = '''play_sound('gold_seal', 1.2, 0.4)''' +position = 'at' +match_indent = true +payload = '''play_sound(sound.sound, sound.per, sound.vol)''' +## Populate Seal Ability Table +[[patches]] +[patches.pattern] +target = 'card.lua' +pattern = '''self.seal = _seal''' +position = 'after' +match_indent = true +payload = ''' +self.ability.seal = {} +for k, v in pairs(G.P_SEALS[_seal].config or {}) do + if type(v) == 'table' then + self.ability.seal[k] = copy_table(v) + else + self.ability.seal[k] = v + end +end +''' + +[[patches]] +[patches.pattern] +target = 'functions/common_events.lua' +pattern = '''new_card:set_seal(other.seal, true)''' +position = 'after' +match_indent = true +payload = ''' +if other.seal then + for k, v in pairs(other.ability.seal or {}) do + if type(v) == 'table' then + new_card.ability.seal[k] = copy_table(v) + else + new_card.ability.seal[k] = v + end + end +end +''' \ No newline at end of file diff --git a/Steamodded/lovely/shop.toml b/Steamodded/lovely/shop.toml new file mode 100644 index 0000000..fa8c4f2 --- /dev/null +++ b/Steamodded/lovely/shop.toml @@ -0,0 +1,237 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = -10 + +# Set defaults +[[patches]] +[patches.pattern] +target = 'functions/misc_functions.lua' +match_indent = true +position = 'after' +pattern = ''' +erratic_suits_and_ranks = false, +''' +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] +target = 'back.lua' +match_indent = true +position = 'before' +pattern = ''' +if self.effect.config.no_interest then +''' +payload = ''' +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] +target = 'functions/state_events.lua' +match_indent = true +position = 'at' +pattern = ''' +G.GAME.current_round.voucher = get_next_voucher_key() +''' +payload = ''' +G.GAME.current_round.voucher = SMODS.get_next_vouchers() +''' +[[patches]] +[patches.pattern] +target = 'game.lua' +match_indent = true +position = 'at' +pattern = ''' +self.GAME.current_round.voucher = G.SETTINGS.tutorial_progress and G.SETTINGS.tutorial_progress.forced_voucher or get_next_voucher_key() +''' +payload = ''' +local forced_voucher = (G.SETTINGS.tutorial_progress or {}).forced_voucher +self.GAME.current_round.voucher = forced_voucher and {forced_voucher, spawn = {[forced_voucher] = true }} or SMODS.get_next_vouchers() +''' +# Stop redeeming vouchers deleting the table of vouchers +[[patches]] +[patches.pattern] +target = 'card.lua' +match_indent = true +position = 'at' +pattern = ''' +if self.shop_voucher then G.GAME.current_round.voucher = nil end +''' +payload = ''' +if self.shop_voucher then G.GAME.current_round.voucher.spawn[self.config.center_key] = false end +if self.from_tag then G.GAME.current_round.voucher.spawn[G.GAME.current_round.voucher[1]] = false end +''' +[[patches]] +[patches.pattern] +target = 'card.lua' +match_indent = true +position = 'at' +pattern = ''' +G.GAME.current_round.voucher = nil +''' +payload = ''' +--G.GAME.current_round.voucher = nil +''' +# Add voucher restock message +[[patches]] +[patches.pattern] +target = 'functions/button_callbacks.lua' +match_indent = true +position = 'at' +pattern = ''' + if (G.shop_vouchers and G.shop_vouchers.cards and (G.shop_vouchers.cards[1] or G.GAME.current_round.voucher)) then +''' +payload = ''' + if (G.shop_vouchers and G.shop_vouchers.cards and G.shop_vouchers.cards[1]) then +''' +# Maintain voucher tag jank interaction +[[patches]] +[patches.pattern] +target = 'tag.lua' +match_indent = true +position = 'before' +pattern = ''' +create_shop_card_ui(card, 'Voucher', G.shop_vouchers) +''' +payload = ''' +card.from_tag = true +''' + + + +# Free Rerolls +[[patches]] +[patches.pattern] +target = 'functions/state_events.lua' +match_indent = true +position = 'at' +pattern = ''' +local chaos = find_joker('Chaos the Clown') +G.GAME.current_round.free_rerolls = #chaos +''' +payload = ''' +G.GAME.current_round.free_rerolls = G.GAME.round_resets.free_rerolls +''' +# G.GAME.round_resets.free_rerolls +[[patches]] +[patches.pattern] +target = 'game.lua' +match_indent = true +position = 'after' +pattern = ''' +reroll_cost = 1, +''' +payload = ''' +free_rerolls = 0, +''' +# Adjust Chaos the Clown +[[patches]] +[patches.pattern] +target = 'card.lua' +match_indent = true +position = 'at' +pattern = ''' +G.GAME.current_round.free_rerolls = G.GAME.current_round.free_rerolls + 1 +''' +payload = ''' +SMODS.change_free_rerolls(1) +''' +[[patches]] +[patches.pattern] +target = 'card.lua' +match_indent = true +position = 'at' +pattern = ''' +G.GAME.current_round.free_rerolls = G.GAME.current_round.free_rerolls - 1 +''' +payload = ''' +SMODS.change_free_rerolls(-1) +''' + +## Shop Card Area Width +[[patches]] +[patches.pattern] +target = 'functions/UI_definitions.lua' +pattern = '''G.GAME.shop.joker_max*1.02*G.CARD_W,''' +position = 'at' +match_indent = true +payload = '''math.min(G.GAME.shop.joker_max*1.02*G.CARD_W,4.08*G.CARD_W),''' +[[patches]] +[patches.pattern] +target = 'functions/common_events.lua' +pattern = '''G.shop_jokers.T.w = G.GAME.shop.joker_max*1.01*G.CARD_W''' +position = 'at' +match_indent = true +payload = '''G.shop_jokers.T.w = math.min(G.GAME.shop.joker_max*1.02*G.CARD_W,4.08*G.CARD_W)''' + +# for some reason shop_voucher is not saved/loaded so... that's what's gonna happen +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = '''ability = self.ability,''' +position = "before" +payload = ''' +shop_voucher = self.shop_voucher, +''' +match_indent = true + +# water is wet +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = '''self.ability = cardTable.ability''' +position = "before" +payload = ''' +self.shop_voucher = cardTable.shop_voucher +''' +match_indent = true diff --git a/Steamodded/lovely/sound.toml b/Steamodded/lovely/sound.toml new file mode 100644 index 0000000..481300e --- /dev/null +++ b/Steamodded/lovely/sound.toml @@ -0,0 +1,167 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = -10 + +#modulate_sound() +[[patches]] +[patches.pattern] +target = 'functions/misc_functions.lua' +pattern = 'G.SOUND_MANAGER.channel:push(G.ARGS.push)' +match_indent = true +position = 'after' +payload = ''' +SMODS.previous_track = SMODS.previous_track or '' +local in_sync = (SMODS.Sounds[desired_track] or {}).sync +local out_sync = (SMODS.Sounds[SMODS.previous_track] or {}).sync +local should_sync = true +if (type(in_sync) == 'table' and not in_sync[SMODS.previous_track]) or in_sync == false then should_sync = false end +if (type(out_sync) == 'table' and not out_sync[desired_track]) or out_sync == false then should_sync = false end +if + SMODS.previous_track and SMODS.previous_track ~= desired_track and + not should_sync +then + G.ARGS.push.type = 'restart_music' + G.SOUND_MANAGER.channel:push(G.ARGS.push) +end +SMODS.previous_track = desired_track''' + +[[patches]] +[patches.pattern] +target = 'functions/misc_functions.lua' +pattern = 'G.ARGS.push.ambient_control = G.SETTINGS.ambient_control' +match_indent = true +position = 'after' +payload = ''' +if SMODS.remove_replace_sound and SMODS.remove_replace_sound ~= desired_track then + SMODS.Sound.replace_sounds[SMODS.remove_replace_sound] = nil + SMODS.remove_replace_sound = nil +end +local replace_sound = SMODS.Sound.replace_sounds[desired_track] +if replace_sound then + local replaced_track = desired_track + desired_track = replace_sound.key + G.ARGS.push.desired_track = desired_track + if SMODS.previous_track ~= desired_track then + if replace_sound.times > 0 then replace_sound.times = replace_sound.times - 1 end + if replace_sound.times == 0 then SMODS.remove_replace_sound = replaced_track end + end +end +local stop_sound = SMODS.Sound.stop_sounds[desired_track] +if SMODS.Sound.stop_sounds[desired_track] then + if SMODS.previous_track ~= '' and stop_sound > 0 then stop_sound = stop_sound - 1 end + SMODS.Sound.stop_sounds[desired_track] = stop_sound ~= 0 and stop_sound or nil + SMODS.previous_track = '' + return +end +''' + +[[patches]] +[patches.pattern] +target = 'functions/misc_functions.lua' +pattern = "(G.STATE == G.STATES.SPLASH and '') or" +match_indent = true +position = 'after' +payload = 'SMODS.Sound:get_current_music() or' + +# PLAY_SOUND +[[patches]] +[patches.pattern] +target = 'engine/sound_manager.lua' +pattern = '''local s = {sound = love.audio.newSource("resources/sounds/"..args.sound_code..'.ogg', should_stream and "stream" or 'static')}''' +match_indent = true +position = 'at' +payload = ''' +local c = SMODS_Sounds[args.sound_code] +local s = c and +{sound = love.audio.newSource(love.sound.newDecoder(c.data), c.should_stream and 'stream' or 'static'), per = c.per, vol = c.vol } or +{sound = love.audio.newSource("resources/sounds/"..args.sound_code..'.ogg', should_stream and "stream" or 'static')}''' + +# pass in custom sounds +[[patches]] +[patches.pattern] +target = 'engine/sound_manager.lua' +pattern = "DISABLE_SFX = false" +match_indent = true +position = 'after' +payload = ''' +SMODS_Sounds = {} +''' +[[patches]] +[patches.pattern] +target = 'engine/sound_manager.lua' +pattern = "elseif request.type == 'stop' then" +match_indent = true +position = 'before' +payload = ''' +elseif request.type == 'sound_source' then + SMODS_Sounds[request.sound_code] = { + sound_code = request.sound_code, + data = request.data, + sound = sound, + per = request.per, + vol = request.vol, + } + SOURCES[request.sound_code] = {} +''' + +[[patches]] +[patches.pattern] +target = 'engine/sound_manager.lua' +pattern = "s.original_pitch = args.per or 1" +match_indent = true +position = 'at' +payload = 's.original_pitch = ((args.type ~= "sound") and s.per) or args.per or 1' + +[[patches]] +[patches.pattern] +target = 'engine/sound_manager.lua' +pattern = "s.original_volume = args.vol or 1" +match_indent = true +position = 'at' +payload = 's.original_volume = ((args.type ~= "sound") and s.vol) or args.vol or 1' + +# don't crash RESTART_MUSIC + +[[patches]] +[patches.pattern] +target = 'engine/sound_manager.lua' +pattern = "RESTART_MUSIC()" +match_indent = true +position = 'at' +payload = 'RESTART_MUSIC(request)' + +# fix looping for music of different length + +[[patches]] +[patches.regex] +target = 'engine/sound_manager.lua' +pattern = """(?[\t ]*)function MODULATE\\(args\\)(\n.*){9}""" +line_prepend = '$indent' +position = 'at' +payload = """function MODULATE(args) + if args.desired_track ~= '' then + local sound = ((SOURCES[current_track or {}] or {})[1] or {}).sound + if not sound or not sound:isPlaying() then + RESTART_MUSIC(args) + end + end +""" +[[patches]] +[patches.pattern] +target = 'engine/sound_manager.lua' +pattern = "for _, s in pairs(v) do" +match_indent = true +position = 'at' +payload = """current_track = args.desired_track +for _, s in pairs(v) do""" + +# [[patches]] +# [patches.pattern] +# target = 'engine/sound_manager.lua' +# pattern = 'if s.sound and not s.sound:isPlaying() then' +# match_indent = true +# position = 'at' +# payload = '''if s.sound and s.sound:isPlaying() then +# s.sound:stop() +# elseif s.sound and not s.sound:isPlaying() then''' diff --git a/Steamodded/lovely/stake.toml b/Steamodded/lovely/stake.toml new file mode 100644 index 0000000..839175f --- /dev/null +++ b/Steamodded/lovely/stake.toml @@ -0,0 +1,190 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = -10 + +# Fix areas where highest stake is hardcoded as Gold Stake +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +pattern = "if G.PROFILES[G.SETTINGS.profile].all_unlocked then max_stake = 8 end" +position = "at" +payload = "if G.PROFILES[G.SETTINGS.profile].all_unlocked then max_stake = #G.P_CENTER_POOLS['Stake'] end" +match_indent = true + +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +pattern = "for i = 1, math.min(max_stake+1, 8) do" +position = "at" +payload = "for i = 1, math.min(max_stake+1, #G.P_CENTER_POOLS['Stake']) do" +match_indent = true + +[[patches]] +[patches.pattern] +target = "functions/misc_functions.lua" +pattern = "if G.GAME.stake >= 8 then" +position = "at" +payload = "if G.GAME.stake >= #G.P_CENTER_POOLS['Stake'] then" +match_indent = true + +# Stake modifier API +[[patches]] +[patches.pattern] +target = "game.lua" +pattern = "if self.GAME.stake >= 2 then" +position = "before" +payload = "if false then" +match_indent = true + +[[patches]] +[patches.pattern] +target = "game.lua" +pattern = "if self.GAME.stake >= 8 then self.GAME.modifiers.enable_rentals_in_shop = true end" +position = "after" +payload = "end SMODS.setup_stake(self.GAME.stake)" +match_indent = true + +# Stake shininess API +[[patches]] +[patches.pattern] +target = "functions/misc_functions.lua" +pattern = "if _stake == 8 then" +position = "at" +payload = "if G.P_CENTER_POOLS['Stake'][_stake].shiny then" +match_indent = true + +# Override stake listing to make room for our recursive version +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +pattern = "for i = G.GAME.stake-1, 2, -1 do" +position = "before" +payload = "if false then" +match_indent = true + +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +pattern = 'other_col = {n=G.UIT.R, config={align = "cm", padding = 0.05, r = 0.1, colour = G.C.L_BLACK}, nodes=stake_desc_rows}' +position = "before" +payload = "end SMODS.applied_stakes_UI(G.GAME.stake, stake_desc_rows)" +match_indent = true + +# Set win stake to that specified in unlocked stake +[[patches]] +[patches.pattern] +target = "functions/misc_functions.lua" +pattern = 'for i = 1, G.GAME.stake do' +position = "at" +payload = '''for i = 1, +(G.P_CENTER_POOLS["Stake"][G.GAME.stake].unlocked_stake) and +(G.P_STAKES[G.P_CENTER_POOLS["Stake"][G.GAME.stake].unlocked_stake].stake_level-1) or (G.GAME.stake-1) +do''' +match_indent = true + +# Stake Sprites +[[patches]] +[patches.pattern] +target = "functions/misc_functions.lua" +pattern = 'local stake_sprite = Sprite(0,0,_scale*1,_scale*1,G.ASSET_ATLAS["chips"], G.P_CENTER_POOLS.Stake[_stake].pos)' +position = "at" +payload = 'local stake_sprite = Sprite(0,0,_scale*1,_scale*1,G.ASSET_ATLAS[G.P_CENTER_POOLS.Stake[_stake].atlas], G.P_CENTER_POOLS.Stake[_stake].pos)' +match_indent = true + +# Achievements and unlocks +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = 'if highest_win >= 2 then' +position = "at" +payload = 'if highest_win >= G.P_STAKES["stake_red"].stake_level then' +match_indent = true + +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = 'if highest_win >= 4 then' +position = "at" +payload = 'if highest_win >= G.P_STAKES["stake_black"].stake_level then' +match_indent = true + +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = 'if highest_win >= 8 then' +position = "at" +payload = 'if highest_win >= G.P_STAKES["stake_gold"].stake_level then' +match_indent = true + +# get_blind_amount +[[patches]] +[patches.pattern] +target = "functions/misc_functions.lua" +pattern = 'function get_blind_amount(ante)' +position = "after" +payload = '''if G.GAME.modifiers.scaling and G.GAME.modifiers.scaling > 3 then return SMODS.get_blind_amount(ante) end''' +match_indent = true + +# set_joker_usage +[[patches]] +[patches.pattern] +target = "functions/misc_functions.lua" +pattern = 'G.PROFILES[G.SETTINGS.profile].joker_usage[v.config.center_key] = {count = 1, order = v.config.center.order, wins = {}, losses = {}}' +position = "at" +payload = 'G.PROFILES[G.SETTINGS.profile].joker_usage[v.config.center_key] = {count = 1, order = v.config.center.order, wins = {}, losses = {}, wins_by_key = {}, losses_by_key = {}}' +match_indent = true + +# set_joker_win +[[patches]] +[patches.pattern] +target = "functions/misc_functions.lua" +pattern = 'G.PROFILES[G.SETTINGS.profile].joker_usage[v.config.center_key] = G.PROFILES[G.SETTINGS.profile].joker_usage[v.config.center_key] or {count = 1, order = v.config.center.order, wins = {}, losses = {}}' +position = "at" +payload = 'G.PROFILES[G.SETTINGS.profile].joker_usage[v.config.center_key] = G.PROFILES[G.SETTINGS.profile].joker_usage[v.config.center_key] or {count = 1, order = v.config.center.order, wins = {}, losses = {}, wins_by_key = {}, losses_by_key = {}}' +match_indent = true + +#set_joker_win +[[patches]] +[patches.pattern] +target = "functions/misc_functions.lua" +pattern = 'G.PROFILES[G.SETTINGS.profile].joker_usage[v.config.center_key].wins[G.GAME.stake] = (G.PROFILES[G.SETTINGS.profile].joker_usage[v.config.center_key].wins[G.GAME.stake] or 0) + 1' +position = "after" +payload = 'G.PROFILES[G.SETTINGS.profile].joker_usage[v.config.center_key].wins_by_key[SMODS.stake_from_index(G.GAME.stake)] = (G.PROFILES[G.SETTINGS.profile].joker_usage[v.config.center_key].wins_by_key[SMODS.stake_from_index(G.GAME.stake)] or 0) + 1' +match_indent = true + +#set_joker_loss +[[patches]] +[patches.pattern] +target = "functions/misc_functions.lua" +pattern = 'G.PROFILES[G.SETTINGS.profile].joker_usage[v.config.center_key].losses[G.GAME.stake] = (G.PROFILES[G.SETTINGS.profile].joker_usage[v.config.center_key].losses[G.GAME.stake] or 0) + 1' +position = "after" +payload = 'G.PROFILES[G.SETTINGS.profile].joker_usage[v.config.center_key].losses_by_key[SMODS.stake_from_index(G.GAME.stake)] = (G.PROFILES[G.SETTINGS.profile].joker_usage[v.config.center_key].losses_by_key[SMODS.stake_from_index(G.GAME.stake)] or 0) + 1' +match_indent = true + +# set_deck_usage +[[patches]] +[patches.pattern] +target = "functions/misc_functions.lua" +pattern = 'G.PROFILES[G.SETTINGS.profile].deck_usage[deck_key] = {count = 1, order = G.GAME.selected_back.effect.center.order, wins = {}, losses = {}}' +position = "at" +payload = 'G.PROFILES[G.SETTINGS.profile].deck_usage[deck_key] = {count = 1, order = G.GAME.selected_back.effect.center.order, wins = {}, losses = {}, wins_by_key = {}, losses_by_key = {}}' +match_indent = true + +# set_deck_loss +[[patches]] +[patches.pattern] +target = "functions/misc_functions.lua" +pattern = 'if not G.PROFILES[G.SETTINGS.profile].deck_usage[deck_key] then G.PROFILES[G.SETTINGS.profile].deck_usage[deck_key] = {count = 1, order = G.GAME.selected_back.effect.center.order, wins = {}, losses = {}} end' +position = "at" +payload = 'if not G.PROFILES[G.SETTINGS.profile].deck_usage[deck_key] then G.PROFILES[G.SETTINGS.profile].deck_usage[deck_key] = {count = 1, order = G.GAME.selected_back.effect.center.order, wins = {}, losses = {}, wins_by_key = {}, losses_by_key = {}} end' +match_indent = true + +# G.UIDEF.viewed_stake_option +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +pattern = 'G.viewed_stake = math.min(max_stake+1, G.viewed_stake)' +position = "after" +payload = '''if G.viewed_stake > #G.P_CENTER_POOLS.Stake then G.viewed_stake = #G.P_CENTER_POOLS.Stake end''' +match_indent = true diff --git a/Steamodded/lovely/sticker.toml b/Steamodded/lovely/sticker.toml new file mode 100644 index 0000000..f251f2c --- /dev/null +++ b/Steamodded/lovely/sticker.toml @@ -0,0 +1,111 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = -10 + +### Sticker API + +# generate_UIBox_ability_table() +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "if self.sticker or ((self.sticker_run and self.sticker_run~='NONE') and G.SETTINGS.run_stake_stickers) then loc_vars = loc_vars or {}; loc_vars.sticker=(self.sticker or self.sticker_run) end" +position = "before" +match_indent = true +payload = ''' +for k, v in ipairs(SMODS.Sticker.obj_buffer) do + if self.ability[v] and not SMODS.Stickers[v].hide_badge then + badges[#badges+1] = v + end +end''' + +# generate_card_ui() +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = "if v == 'eternal' then*" +match_indent = true +position = "before" +payload = ''' +local sticker = SMODS.Stickers[v] +if sticker then + local t = { key = v, set = 'Other' } + local res = {} + if sticker.loc_vars and type(sticker.loc_vars) == 'function' then + res = sticker:loc_vars(info_queue, card) or {} + t.vars = res.vars or {} + t.key = res.key or t.key + t.set = res.set or t.set + end + info_queue[#info_queue+1] = t +else''' + +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = "if v == 'rental' then*" +match_indent = true +position = "after" +payload = '''end''' + +# create_card() +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = "if card.ability.consumeable and not skip_materialize then card:start_materialize() end" +position = "after" +match_indent = true +payload = ''' +for k, v in ipairs(SMODS.Sticker.obj_buffer) do + local sticker = SMODS.Stickers[v] + if sticker.should_apply and type(sticker.should_apply) == 'function' and sticker:should_apply(card, center, area) then + sticker:apply(card, true) + end +end''' + +## Remove base game sticker rolls if one is added +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = "if G.GAME.modifiers.enable_eternals_in_shop and eternal_perishable_poll > 0.7 then" +position = "at" +match_indent = true +payload = '''if G.GAME.modifiers.enable_eternals_in_shop and eternal_perishable_poll > 0.7 and not SMODS.Stickers["eternal"].should_apply then''' + +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = "elseif G.GAME.modifiers.enable_perishables_in_shop and ((eternal_perishable_poll > 0.4) and (eternal_perishable_poll <= 0.7)) then" +position = "at" +match_indent = true +payload = '''elseif G.GAME.modifiers.enable_perishables_in_shop and ((eternal_perishable_poll > 0.4) and (eternal_perishable_poll <= 0.7)) and not SMODS.Stickers["perishable"].should_apply then''' + +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = "if G.GAME.modifiers.enable_rentals_in_shop and pseudorandom((area == G.pack_cards and 'packssjr' or 'ssjr')..G.GAME.round_resets.ante) > 0.7 then" +position = "at" +match_indent = true +payload = '''if G.GAME.modifiers.enable_rentals_in_shop and pseudorandom((area == G.pack_cards and 'packssjr' or 'ssjr')..G.GAME.round_resets.ante) > 0.7 and not SMODS.Stickers["rental"].should_apply then''' + +# get_badge_colour() +[[patches]] +[patches.pattern] +target = 'functions/UI_definitions.lua' +pattern = 'return G.BADGE_COL[key] or {1, 0, 0, 1}' +position = 'before' +match_indent = true +payload = ''' +for k, v in pairs(SMODS.Stickers) do + G.BADGE_COL[k] = v.badge_colour +end''' + +## Remove Pinned effect when in Sticker collections +# CardArea:aling_cards +[[patches]] +[patches.pattern] +target = 'cardarea.lua' +pattern = '''table.sort(self.cards, function (a, b) return a.T.x + a.T.w/2 - 100*(a.pinned and a.sort_id or 0) < b.T.x + b.T.w/2 - 100*(b.pinned and b.sort_id or 0) end)''' +position = 'at' +match_indent = true +payload = '''table.sort(self.cards, function (a, b) return a.T.x + a.T.w/2 - 100*((a.pinned and not a.ignore_pinned) and a.sort_id or 0) < b.T.x + b.T.w/2 - 100*((b.pinned and not b.ignore_pinned) and b.sort_id or 0) end)''' diff --git a/Steamodded/lovely/tag.toml b/Steamodded/lovely/tag.toml new file mode 100644 index 0000000..7a885e3 --- /dev/null +++ b/Steamodded/lovely/tag.toml @@ -0,0 +1,139 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = -10 + +### Tag API +# Tag:apply_to_run() +[[patches]] +[patches.pattern] +target = "tag.lua" +pattern = "function Tag:apply_to_run(_context)" +position = 'after' +match_indent = true +payload = ''' + if self.triggered then return end + local obj = SMODS.Tags[self.key] + local res + if obj and obj.apply and type(obj.apply) == 'function' then + res = obj:apply(self, _context) + end + if res then return res end +''' + +# Tag:set_ability() +[[patches]] +[patches.pattern] +target = "tag.lua" +pattern = "function Tag:set_ability()" +position = 'after' +match_indent = true +payload = ''' + local obj = SMODS.Tags[self.key] + local res + if obj and obj.set_ability and type(obj.set_ability) == 'function' then + obj:set_ability(self) + end +''' + +# create_UIBox_your_collection_tags() +[[patches]] +[patches.regex] +target = "functions/UI_definitions.lua" +pattern = "(?[\t ]*)local tag_matrix = \\{(\n.*){6}" +position = 'at' +line_prepend = '$indent' +payload = ''' +local tag_matrix = {} +local counter = 0 +local tag_tab = {} +local tag_pool = {} +if G.ACTIVE_MOD_UI then + for k, v in pairs(G.P_TAGS) do + if v.mod and G.ACTIVE_MOD_UI.id == v.mod.id then tag_pool[k] = v end + end +else + tag_pool = G.P_TAGS +end +for k, v in pairs(tag_pool) do + counter = counter + 1 + tag_tab[#tag_tab+1] = v +end +for i = 1, math.ceil(counter / 6) do + table.insert(tag_matrix, {}) +end''' + +[[patches]] +[patches.regex] +target = "functions/UI_definitions.lua" +pattern = '''(?[\t ]*)v\.children\.alert\.states\.collide\.can = false\n[\s\S]{8}end\n[\s\S]{8}return true\n[\s\S]{4}end\)\n[\s\S]{2}\}\)\)\n{3}''' +position = 'after' +line_prepend = '$indent' +payload = ''' +local table_nodes = {} +for i = 1, math.ceil(counter / 6) do + table.insert(table_nodes, {n=G.UIT.R, config={align = "cm"}, nodes=tag_matrix[i]}) +end''' + +[[patches]] +[patches.regex] +target = "functions/UI_definitions.lua" +pattern = '''(?[\t ]*)\{\n[\s\S]{10}\{n=G\.UIT\.R, config=\{align = "cm"\}, nodes=tag_matrix\[1\]},[\s\S]*tag_matrix\[4\]\},\n[\s\S]{8}\}''' +position = 'at' +line_prepend = '$indent' +payload = '''table_nodes''' + +# Tag:generate_UI() +[[patches]] +[patches.regex] +target = "tag.lua" +pattern = 'G.ASSET_ATLAS\["tags"\]' +position = 'at' +payload = 'G.ASSET_ATLAS[(not self.hide_ability) and G.P_TAGS[self.key].atlas or "tags"]' + +# Tag:get_uibox_table() +[[patches]] +[patches.pattern] +target = "tag.lua" +pattern = '''function Tag:get_uibox_table(tag_sprite)''' +position = 'at' +match_indent = true +payload = '''function Tag:get_uibox_table(tag_sprite, vars_only)''' +[[patches]] +[patches.pattern] +target = "tag.lua" +pattern = '''tag_sprite.ability_UIBox_table = generate_card_ui(G.P_TAGS[self.key], nil, loc_vars, (self.hide_ability) and 'Undiscovered' or 'Tag', nil, (self.hide_ability))''' +position = 'at' +match_indent = true +payload = '''if vars_only then return loc_vars end +tag_sprite.ability_UIBox_table = generate_card_ui(G.P_TAGS[self.key], nil, loc_vars, (self.hide_ability) and 'Undiscovered' or 'Tag', nil, (self.hide_ability), nil, nil, self)''' + +# generate_card_ui() + +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = "elseif _c.set == 'Tag' then" +position = "after" +match_indent = true +payload = '''specific_vars = specific_vars or Tag.get_uibox_table({ name = _c.name, config = _c.config, ability = { orbital_hand = '['..localize('k_poker_hand')..']' }}, nil, true) +''' + +# Prevent Boss Tag from crashing when triggered at a bad time +# by quietly rerolling it if blind select UI is not there +[[patches]] +[patches.pattern] +target = "functions/button_callbacks.lua" +pattern = "G.FUNCS.reroll_boss = function(e)" +position = "after" +match_indent = true +payload = '''if not G.blind_select_opts then + G.GAME.round_resets.boss_rerolled = true + if not G.from_boss_tag then ease_dollars(-10) end + G.from_boss_tag = nil + G.GAME.round_resets.blind_choices.Boss = get_new_boss() + for i = 1, #G.GAME.tags do + if G.GAME.tags[i]:apply_to_run({type = 'new_blind_choice'}) then break end + end + return true +end''' \ No newline at end of file diff --git a/Steamodded/lovely/threads.toml b/Steamodded/lovely/threads.toml new file mode 100644 index 0000000..85c2580 --- /dev/null +++ b/Steamodded/lovely/threads.toml @@ -0,0 +1,30 @@ +# Necessary to kill threads which lets us restart the game. + +[manifest] +version = "1.0.0" +dump_lua = true +priority = -5 + +[[patches]] +[patches.pattern] +target = "engine/save_manager.lua" +pattern = "if request then" +position = "after" +payload = "if request.type == 'kill' then return end" +match_indent = true + +[[patches]] +[patches.pattern] +target = "engine/http_manager.lua" +pattern = "if request then" +position = "after" +payload = "if request.type == 'kill' then return end" +match_indent = true + +[[patches]] +[patches.pattern] +target = "engine/sound_manager.lua" +pattern = "if request then" +position = "after" +payload = "if request.type == 'kill' then return end" +match_indent = true diff --git a/Steamodded/lovely/ui.toml b/Steamodded/lovely/ui.toml new file mode 100644 index 0000000..fa6714a --- /dev/null +++ b/Steamodded/lovely/ui.toml @@ -0,0 +1,251 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = -10 + +### Addition Tab + +## Decks tab +# create_UIBox_your_collection_decks() +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +pattern = '''G.GAME.viewed_back = Back(G.P_CENTERS.b_red)''' +position = "at" +payload = ''' +local deck_pool = SMODS.collection_pool(G.P_CENTER_POOLS.Back) +G.GAME.viewed_back = Back(G.ACTIVE_MOD_UI and deck_pool[1] or G.P_CENTERS.b_red)''' +match_indent = true + +# create_UIBox_your_collection_decks() +[[patches]] +[patches.regex] +target = 'functions/UI_definitions.lua' +pattern = '''(?[\t ]*)for k, v in ipairs\(G\.P_CENTER_POOLS\.Back\) do\n[\s\S]{4}ordered_names\[#ordered_names\+1\] = v\.name\n[\s\S]{2}end''' +position = 'at' +payload = ''' +for k, v in ipairs(deck_pool) do + ordered_names[#ordered_names+1] = v.key +end''' +line_prepend = '$indent' + +# create_UIBox_your_collection_decks() +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +pattern = '''local t = create_UIBox_generic_options({ back_func = 'your_collection', contents = {''' +position = "at" +payload = '''local t = create_UIBox_generic_options({ back_func = G.ACTIVE_MOD_UI and "openModUI_"..G.ACTIVE_MOD_UI.id or 'your_collection', contents = {''' +match_indent = true + +# G.FUNCS.your_collection_deck_page +[[patches]] +[patches.pattern] +target = "functions/button_callbacks.lua" +pattern = '''G.GAME.viewed_back:change_to(G.P_CENTER_POOLS.Back[args.to_key])''' +position = "at" +payload = ''' +local deck_pool = SMODS.collection_pool(G.P_CENTER_POOLS.Back) +G.GAME.viewed_back:change_to(deck_pool[args.to_key])''' +match_indent = true + +# create_UIBox_your_collection() +[[patches]] +[patches.regex] +target = 'functions/UI_definitions.lua' +pattern = '''(?[\t ]*)UIBox_button\(\{button = 'your_collection_blinds', label = \{localize\('b_blinds'\)\}, count = G\.DISCOVER_TALLIES\.blinds, minw = 5, minh = 2.0, id = 'your_collection_blinds', focus_args = \{snap_to = true\}\}\),''' +position = 'after' +payload = '''UIBox_button({button = 'your_collection_other_gameobjects', label = {localize('k_other')}, minw = 5, id = 'your_collection_other_gameobjects', focus_args = {snap_to = true}}),''' + +# Fix UIElement.config.chosen being overriden if choice=true is set +# UIElement:click() +[[patches]] +[patches.pattern] +target = "engine/ui.lua" +match_indent = true +position = "after" +pattern = "if self.config.choice then" +payload = " local chosen_temp = self.config.chosen" + +[[patches]] +[patches.pattern] +target = "engine/ui.lua" +match_indent = true +position = "at" +pattern = "self.config.chosen = true" +payload = "self.config.chosen = chosen_temp or true" + +# Escape from mod menu saves config +# Needs to be before all checks +[[patches]] +[patches.pattern] +target = 'engine/controller.lua' +pattern = "function Controller:key_press_update(key, dt)" +position = "after" +payload = ''' + if key == "escape" and G.ACTIVE_MOD_UI then + G.FUNCS.exit_mods() + end +''' +match_indent = true + +[[patches]] +[patches.regex] +target = 'functions/UI_definitions.lua' +position = 'before' +line_prepend = '$indent' +pattern = ''' +(?[\t ]*)return \{n=G\.UIT\.ROOT, config = \{align = 'cm', colour = G\.C\.CLEAR\}, nodes=\{ +[\t ]*\{n=G\.UIT\.C,''' +payload = ''' +local cols +if #info_boxes <= 3 then + cols = 1 +elseif #info_boxes <= 10 then + cols = 2 +elseif #info_boxes <= 24 then + cols = 3 +else + cols = 4 +end +local nodes_per_col = math.ceil(#info_boxes/cols) +local info_cols = {} +for i = 0, cols-1 do + local col = {} + for j = 1, nodes_per_col do + local info_box = info_boxes[i*nodes_per_col+j] + if info_box then + table.insert(col, info_box) + else break end + end + table.insert(info_cols, {n=G.UIT.C, config = {align="cm"}, nodes = col}) +end +info_boxes = {{n=G.UIT.R, config = {align="cm", padding = 0.05, card_pos = card.T.x }, nodes = info_cols}} +''' + +[[patches]] +[patches.pattern] +target = 'functions/button_callbacks.lua' +match_indent = true +position = 'at' +pattern = "config = {offset = {x=-0.03,y=0}, align = 'cl', parent = e}" +payload = """config = (not e.config.ref_table or not e.config.ref_table[1].config.card_pos or e.config.ref_table[1].config.card_pos > G.ROOM.T.w*0.4) and + {offset = {x=-0.03,y=0}, align = 'cl', parent = e} or + {offset = {x=0.03,y=0}, align = 'cr', parent = e}""" + +[[patches]] +[patches.pattern] +target = 'tag.lua' +match_indent = true +position = 'at' +pattern = "_self.config.h_popup_config ={align = 'cl', offset = {x=-0.1,y=0},parent = _self}" +payload = """_self.config.h_popup_config = (_self.T.x > G.ROOM.T.w*0.4) and + {align = 'cl', offset = {x=-0.1,y=0},parent = _self} or + {align = 'cr', offset = {x=0.1,y=0},parent = _self}""" + +# desc_from_rows +[[patches]] +[patches.regex] +target = 'functions/UI_definitions.lua' +position = 'at' +pattern = 'colour = empty and G\.C\.CLEAR or G\.C\.UI\.BACKGROUND_WHITE' +payload = 'colour = desc_nodes.background_colour or empty and G.C.CLEAR or G.C.UI.BACKGROUND_WHITE' + +# info_tip_from_rows +[[patches]] +[patches.regex] +target = 'functions/UI_definitions.lua' +position = 'at' +pattern = 'padding = 0\.05, colour = G\.C\.WHITE\}' +payload = 'padding = 0.05, colour = desc_nodes.background_colour or G.C.WHITE}' + +# localize +[[patches]] +[patches.regex] +target = 'functions/misc_functions.lua' +position = 'after' +pattern = '\(part\.control\.C and loc_colour\(part\.control\.C\)\)' +payload = ' or args.text_colour' + +[[patches]] +[patches.regex] +target = 'functions/misc_functions.lua' +position = 'at' +pattern = 'loc_colour\(part\.control\.C or nil, args\.default_col\)' +payload = 'not part.control.C and args.text_colour or loc_colour(part.control.C or nil, args.default_col)' + +[[patches]] +[patches.regex] +target = 'functions/misc_functions.lua' +position = 'after' +pattern = 'part\.control\.s and tonumber\(part\.control\.s\)' +payload = ' or args.scale ' + +# set_discover_tallies() +# exclude no_collection objects +[[patches]] +[patches.pattern] +target = 'functions/misc_functions.lua' +match_indent = true +position = 'at' +pattern = "if not v.omit then" +payload = "if not v.omit and not v.no_collection then" + +[[patches]] +[patches.regex] +target = 'functions/misc_functions.lua' +line_prepend = '$indent' +position = 'at' +pattern = '(?[\t ]*)(?for _, v in pairs\(G\.P_[BT].*)(?(\n.*){7})' +payload = '''$start + if not v.no_collection then + $rest +end +''' + +#set_alerts() +[[patches]] +[patches.pattern] +target = 'functions/common_events.lua' +match_indent = true +position = 'at' +pattern = "if v.discovered and not v.alerted then" +payload = "if v.discovered and not v.alerted and not v.no_collection then" + +## Description controls +# localize + +[[patches]] +[patches.pattern] +target = 'functions/misc_functions.lua' +match_indent = true +position = 'at' +pattern = 'final_line[#final_line+1] = {n=G.UIT.O, config={' +payload = ''' +final_line[#final_line+1] = {n=G.UIT.C, config={align = "m", colour = part.control.B and args.vars.colours[tonumber(part.control.B)] or part.control.X and loc_colour(part.control.X) or nil, r = 0.05, padding = 0.03, res = 0.15}, nodes={}} +final_line[#final_line].nodes[1] = {n=G.UIT.O, config={ +''' + + +[[patches]] +[patches.pattern] +target = 'functions/misc_functions.lua' +match_indent = true +position = 'at' +pattern = 'elseif part.control.X then' +payload = 'elseif part.control.X or part.control.B then' + +[[patches]] +[patches.regex] +target = 'functions/misc_functions.lua' +position = 'at' +pattern = 'colour = loc_colour\(part.control.X\)' +payload = 'colour = part.control.B and args.vars.colours[tonumber(part.control.B)] or loc_colour(part.control.X)' + +[[patches]] +[patches.pattern] +target = 'functions/misc_functions.lua' +match_indent = true +position = 'at' +pattern = 'colour = loc_colour(part.control.C or nil),' +payload = 'colour = part.control.V and args.vars.colours[tonumber(part.control.V)] or loc_colour(part.control.C or nil),' \ No newline at end of file diff --git a/Steamodded/lovely/ui_elements.toml b/Steamodded/lovely/ui_elements.toml new file mode 100644 index 0000000..875959b --- /dev/null +++ b/Steamodded/lovely/ui_elements.toml @@ -0,0 +1,130 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = -10 + +## colour argument fix +# create_tabs() +[[patches]] +[patches.pattern] +target = 'functions/UI_definitions.lua' +pattern = '''tab_buttons[#tab_buttons+1] = UIBox_button({id = 'tab_but_'..(v.label or ''), ref_table = v, button = 'change_tab', label = {v.label}, minh = 0.8*args.scale, minw = 2.5*args.scale, col = true, choice = true, scale = args.text_scale, chosen = v.chosen, func = v.func, focus_args = {type = 'none'}})''' +position = 'at' +payload = '''tab_buttons[#tab_buttons+1] = UIBox_button({id = 'tab_but_'..(v.label or ''), ref_table = v, button = 'change_tab', label = {v.label}, minh = 0.8*args.scale, minw = 2.5*args.scale, col = true, choice = true, scale = args.text_scale, chosen = v.chosen, func = v.func, colour = args.colour, focus_args = {type = 'none'}})''' +match_indent = true + +# UIElement:draw_self() +[[patches]] +[patches.pattern] +target = 'engine/ui.lua' +pattern = '''love.graphics.polygon("fill", get_chosen_triangle_from_rect(self.layered_parallax.x, self.layered_parallax.y, self.VT.w*G.TILESIZE, self.VT.h*G.TILESIZE, self.config.chosen == 'vert'))''' +position = 'before' +payload = '''love.graphics.setColor(self.config.colour)''' +match_indent = true + + +## multiple text input fix +# create_text_input() +[[patches]] +[patches.pattern] +target = 'functions/UI_definitions.lua' +pattern = '''args.current_prompt_text = ''''' +position = 'after' +payload = '''args.id = args.id or "text_input"''' +match_indent = true +[[patches]] +[patches.pattern] +target = 'functions/UI_definitions.lua' +pattern = '''ui_letters[#ui_letters+1] = {n=G.UIT.T, config={ref_table = args, ref_value = 'current_prompt_text', scale = args.text_scale, colour = lighten(copy_table(args.colour), 0.4), id = 'prompt'}}''' +position = 'at' +payload = '''ui_letters[#ui_letters+1] = {n=G.UIT.T, config={ref_table = args, ref_value = 'current_prompt_text', scale = args.text_scale, colour = lighten(copy_table(args.colour), 0.4), id = args.id..'_prompt'}}''' +match_indent = true +[[patches]] +[patches.pattern] +target = 'functions/UI_definitions.lua' +pattern = '''ui_letters[i] = {n=G.UIT.T, config={ref_table = text.letters, ref_value = i, scale = args.text_scale, colour = G.C.UI.TEXT_LIGHT, id = 'letter_'..i}}''' +position = 'at' +payload = '''ui_letters[i] = {n=G.UIT.T, config={ref_table = text.letters, ref_value = i, scale = args.text_scale, colour = G.C.UI.TEXT_LIGHT, id = args.id..'_letter_'..i}}''' +match_indent = true +[[patches]] +[patches.pattern] +target = 'functions/UI_definitions.lua' +pattern = '''ui_letters[#ui_letters+1] = {n=G.UIT.B, config={r = 0.03,w=0.1, h=0.4, colour = position_text_colour, id = 'position', func = 'flash'}}''' +position = 'at' +payload = '''ui_letters[#ui_letters+1] = {n=G.UIT.B, config={r = 0.03,w=0.1, h=0.4, colour = position_text_colour, id = args.id..'_position', func = 'flash'}}''' +match_indent = true +[[patches]] +[patches.pattern] +target = 'functions/UI_definitions.lua' +pattern = '''{n=G.UIT.C, config={align = "cm", draw_layer = 1, colour = G.C.CLEAR}, nodes = {''' +position = 'at' +payload = '''{n=G.UIT.C, config={align = "cm", colour = G.C.CLEAR}, nodes = {''' +match_indent = true +[[patches]] +[patches.pattern] +target = 'functions/UI_definitions.lua' +pattern = '''{n=G.UIT.C, config={id = 'text_input', align = "cm", padding = 0.05, r = 0.1, draw_layer = 2, hover = true, colour = args.colour,minw = args.w, min_h = args.h, button = 'select_text_input', shadow = true}, nodes={''' +position = 'at' +payload = '''{n=G.UIT.C, config={id = args.id, align = "cm", padding = 0.05, r = 0.1, hover = true, colour = args.colour,minw = args.w, min_h = args.h, button = 'select_text_input', shadow = true}, nodes={''' +match_indent = true + +# G.FUNCS.select_text_input +[[patches]] +[patches.pattern] +target = 'functions/button_callbacks.lua' +pattern = '''G.CONTROLLER.text_input_hook = e.children[1].children[1]''' +position = 'after' +payload = '''G.CONTROLLER.text_input_id = e.config.id''' +match_indent = true + +# G.FUNCS.paste_seed +[[patches]] +[patches.pattern] +target = 'functions/button_callbacks.lua' +pattern = '''G.CONTROLLER.text_input_hook = e.UIBox:get_UIE_by_ID('text_input').children[1].children[1]''' +position = 'after' +payload = """G.CONTROLLER.text_input_id = 'text_input'""" +match_indent = true + +# G.FUNCS.flash +[[patches]] +[patches.pattern] +target = 'functions/button_callbacks.lua' +pattern = '''if G.CONTROLLER.text_input_hook then''' +position = 'at' +payload = '''if G.CONTROLLER.text_input_hook and G.CONTROLLER.text_input_id == e.config.id:sub(1,string.len(G.CONTROLLER.text_input_id)) then''' +match_indent = true + +# TRANSPOSE_TEXT_INPUT() +[[patches]] +[patches.pattern] +target = 'functions/button_callbacks.lua' +pattern = '''if hook.children[i].config.id == 'position' then''' +position = 'at' +payload = '''if hook.children[i].config.id == G.CONTROLLER.text_input_id..'_position' then''' +match_indent = true +[[patches]] +[patches.pattern] +target = 'functions/button_callbacks.lua' +pattern = '''local real_letter = hook.children[position_child+dir].config.id:sub(1, 7) == 'letter_' and hook.children[position_child+dir].config.text ~= ''''' +position = 'at' +payload = '''local real_letter = hook.children[position_child+dir].config.id:sub(1, 8+string.len(G.CONTROLLER.text_input_id)) == G.CONTROLLER.text_input_id..'_letter_' and hook.children[position_child+dir].config.text ~= ''''' +match_indent = true + +# GET_TEXT_FROM_INPUT() +[[patches]] +[patches.pattern] +target = 'functions/button_callbacks.lua' +pattern = '''if hook.children[i].config and hook.children[i].config.id:sub(1, 7) == 'letter_' and hook.children[i].config.text ~= '' then''' +position = 'at' +payload = '''if hook.children[i].config and hook.children[i].config.id:sub(1, 8+string.len(G.CONTROLLER.text_input_id)) == G.CONTROLLER.text_input_id..'_letter_' and hook.children[i].config.text ~= '' then''' +match_indent = true + +# remove hardcoded shop selection limit +[[patches]] +[patches.pattern] +target = "cardarea.lua" +pattern = "if self.highlighted[1] then" +position = "at" +payload = "if #self.highlighted >= self.config.highlighted_limit then" +match_indent = true diff --git a/UnStable-main/lovely/Card.toml b/UnStable-main/lovely/Card.toml new file mode 100644 index 0000000..84f8575 --- /dev/null +++ b/UnStable-main/lovely/Card.toml @@ -0,0 +1,90 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = 0 + +# Fix the nominal sorting (Suit for high ranks) +[[patches]] +[patches.regex] +target = 'card.lua' +pattern = '''if mod == 'suit' (.*)''' +position = 'at' +payload = ''' +if mod == 'suit' then mult = 30000 end''' + +# Fix the nominal sorting (For low ranks) +[[patches]] +[patches.regex] +target = 'card.lua' +pattern = '''return 10\*self.base.nominal\*rank_mult(.*)''' +position = 'at' +payload = ''' +--Temporary fix so the card with the lowest nominal can still be sorted properly + local nominal = self.base.nominal + + if self.base.value == 'unstb_???' then + nominal = 0.3 + elseif nominal < 0.4 then + nominal = 0.31 + nominal*0.1 + end + + --Hardcode this so it's sorted properly + if self.base.value == 'unstb_161' then + nominal = 30 + end + + return 10*(nominal)*rank_mult + self.base.suit_nominal*mult + (self.base.suit_nominal_original or 0)*0.0001*mult + 10*self.base.face_nominal*rank_mult + 0.000001*self.unique_val''' + + +# Adds ability text for decimal ranks +# function generate_card_ui() +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = "if main_end then" +position = "before" +match_indent = true +payload = """ +local isCollection = (card and card.area and card.area.config.collection) or false +if not isCollection and (_c.set == 'Default' or _c.set == 'Enhanced') and card and card.base and card.base.value and SMODS.Ranks[card.base.value].is_decimal and not card.config.center.no_rank and not card.debuff then + local rank_act = SMODS.Ranks[card.base.value].rank_act or {'0', '0', '0'} + if rank_act[3] then + localize{type = 'other', key = 'decimal_rank_ability', nodes = desc_nodes, vars = {rank_act[1], rank_act[2], rank_act[3]}} + else + localize{type = 'other', key = 'decimal_rank_ability_2', nodes = desc_nodes, vars = {rank_act[1], rank_act[2]}} + end +end""" + +# Adds 'No Chips' text for certain ranks +# function generate_card_ui() +[[patches]] +[patches.regex] +target = "functions/common_events.lua" +pattern = "specific_vars.nominal_chips then \n(.*)" +position = "at" +payload = """ +specific_vars.nominal_chips or (specific_vars.value == 'unstb_0' or specific_vars.value == 'unstb_???') then +if (specific_vars.value == 'unstb_0' or specific_vars.value == 'unstb_???') and not specific_vars.nominal_chips then + localize{type = 'other', key = 'no_chip', nodes = desc_nodes, vars = {}} +else + localize{type = 'other', key = 'card_chips', nodes = desc_nodes, vars = {specific_vars.nominal_chips}} +end +""" + +# Ranks unlocks from Booster Pack +# function generate_card_ui() +[[patches]] +[patches.pattern] +target = "functions/button_callbacks.lua" +pattern = "elseif card.ability.set == 'Enhanced' or card.ability.set == 'Default' then " +position = "after" +match_indent = true +payload = """ +if G.STATE == G.STATES.STANDARD_PACK or G.STATE == G.STATES.SMODS_BOOSTER_OPENED then + local rank = card.base.value + --Check if it's UnStable rank, if so then flips the flag + if rank:find('unstb_') then + setPoolRankFlagEnable(rank, true); + end +end +""" \ No newline at end of file diff --git a/UnStable-main/lovely/Consumable.toml b/UnStable-main/lovely/Consumable.toml new file mode 100644 index 0000000..c43d83d --- /dev/null +++ b/UnStable-main/lovely/Consumable.toml @@ -0,0 +1,21 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = 0 + +# Auxiliary Cards undiscovered sprite, based on Polyminoes undiscovered sprite from Bunco +[[patches]] +[patches.pattern] +target = 'card.lua' +pattern = '''local shared_sprite = (self.ability.set == 'Edition' or self.ability.set == 'Joker') and G.shared_undiscovered_joker or G.shared_undiscovered_tarot''' +position = 'after' +match_indent = true +payload = ''' + +if not G.shared_undiscovered_auxiliary then G.shared_undiscovered_auxiliary = Sprite(0, 0, G.CARD_W, G.CARD_H, G.ASSET_ATLAS['unstb_auxiliary_undiscovered'], {x = 1, y = 0}) end + +if self.ability.set == 'Auxiliary' then + shared_sprite = G.shared_undiscovered_auxiliary +end + +''' \ No newline at end of file diff --git a/UnStable-main/lovely/Deck.toml b/UnStable-main/lovely/Deck.toml new file mode 100644 index 0000000..9a97805 --- /dev/null +++ b/UnStable-main/lovely/Deck.toml @@ -0,0 +1,16 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = 0 + +# Adds rank blacklist functionality for deck +# function generate_card_ui() +[[patches]] +[patches.pattern] +target = "game.lua" +pattern = "if self.GAME.starting_params.no_faces and SMODS.Ranks[v.value].face then keep = false end" +position = "before" +match_indent = true +payload = """ +if self.GAME.starting_params.blacklisted_ranks and self.GAME.starting_params.blacklisted_ranks[v.value] then keep = false end +""" \ No newline at end of file diff --git a/UnStable-main/lovely/Enhancement.toml b/UnStable-main/lovely/Enhancement.toml new file mode 100644 index 0000000..8942c22 --- /dev/null +++ b/UnStable-main/lovely/Enhancement.toml @@ -0,0 +1,39 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = 0 + +# Adds triggers for destroyable enhancement after-play +[[patches]] +[patches.pattern] +target = 'functions/state_events.lua' +pattern = '''-- context.remove_playing_cards calculations''' +position = 'before' +match_indent = true +payload = ''' +for i=1, #scoring_hand do + if scoring_hand[i].config.center.after_play and not scoring_hand[i].debuff and not unstb_global.table_has_value(cards_destroyed, scoring_hand[i]) then + local effect = scoring_hand[i].config.center:after_play(scoring_hand[i], {scoring_hand = scoring_hand}) + if effect and effect.to_destroy then + cards_destroyed[#cards_destroyed+1] = scoring_hand[i] + end + end +end +''' + +# Enhancement Discard Overrides +[[patches]] +[patches.pattern] +target = 'functions/state_events.lua' +pattern = "draw_card(G.hand, G.discard, i*100/highlighted_count, 'down', false, G.hand.highlighted[i])" +position = 'at' +match_indent = true +payload = ''' + +if G.hand.highlighted[i].config.center.discard_override and not G.hand.highlighted[i].debuff then + G.hand.highlighted[i].config.center:discard_override(G.hand.highlighted[i], {delay = i*100/highlighted_count}) +else + draw_card(G.hand, G.discard, i*100/highlighted_count, 'down', false, G.hand.highlighted[i]) +end + +''' \ No newline at end of file diff --git a/UnStable-main/lovely/Joker.toml b/UnStable-main/lovely/Joker.toml new file mode 100644 index 0000000..3d37730 --- /dev/null +++ b/UnStable-main/lovely/Joker.toml @@ -0,0 +1,82 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = 0 + +# Blueprint Compat Jokers Part 1 +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "elseif self.ability.name == 'Blueprint' then" +position = "before" +payload = ''' +elseif self.config.center.key == 'j_unstb_plagiarism' then + self.ability.blueprint_compat_ui_l = self.ability.blueprint_compat_ui_l or ''; + self.ability.blueprint_compat_check_l = nil + + self.ability.blueprint_compat_ui_r = self.ability.blueprint_compat_ui_r or ''; + self.ability.blueprint_compat_check_r = nil + + main_end = (self.area and self.area == G.jokers) and { + {n=G.UIT.C, config={align = "bm", minh = 0.4, padding = 0.06}, nodes={ + {n=G.UIT.R, config={ref_table = self, align = "m", colour = G.C.JOKER_GREY, r = 0.05, padding = 0.06, func = 'blueprint_compat_dside_l'}, nodes={ + {n=G.UIT.T, config={ref_table = self.ability, ref_value = 'blueprint_compat_ui_l',colour = G.C.UI.TEXT_LIGHT, scale = 0.32*0.8}}, + }}, + + {n=G.UIT.R, config={ref_table = self, align = "m", colour = G.C.JOKER_GREY, r = 0.05, padding = 0.06, func = 'blueprint_compat_dside_r'}, nodes={ + {n=G.UIT.T, config={ref_table = self.ability, ref_value = 'blueprint_compat_ui_r',colour = G.C.UI.TEXT_LIGHT, scale = 0.32*0.8}}, + }} + }} + } or nil +''' +match_indent = true + +# Blueprint Compat Jokers Part 2 +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = "if self.ability.name == 'Blueprint' or self.ability.name == 'Brainstorm' then" +position = "before" +payload = ''' +if self.config.center.key == 'j_unstb_plagiarism' then + local other_joker_l = nil + local other_joker_r = nil + + for i = 1, #G.jokers.cards do + if G.jokers.cards[i] == self then + other_joker_l = G.jokers.cards[i-1] + other_joker_r = G.jokers.cards[i+1] + end + end + + if other_joker_l and other_joker_l ~= self and other_joker_l.config.center.blueprint_compat then + self.ability.blueprint_compat_l = 'compatible' + else + self.ability.blueprint_compat_l = 'incompatible' + end + + if other_joker_r and other_joker_r ~= self and other_joker_r.config.center.blueprint_compat then + self.ability.blueprint_compat_r = 'compatible' + else + self.ability.blueprint_compat_r = 'incompatible' + end +end +''' +match_indent = true + +# Adds support for Virtual Money (used for IC Card) +[[patches]] +[patches.regex] +target = 'functions/button_callbacks.lua' +pattern = '''G.GAME.dollars[ ]*-[ ]*G.GAME.bankrupt_at''' +position = 'at' +payload = '''G.GAME.dollars + (G.GAME.virtual_dollars or 0) - G.GAME.bankrupt_at''' + +# Adds support for Virtual Money (used for IC Card) +# (Talisman Variant) +[[patches]] +[patches.regex] +target = 'functions/button_callbacks.lua' +pattern = '''to_big\(G.GAME.dollars\)[ ]*-[ ]*to_big\(G.GAME.bankrupt_at\)''' +position = 'at' +payload = '''to_big(G.GAME.dollars) + to_big(G.GAME.virtual_dollars or 0) - to_big(G.GAME.bankrupt_at)''' \ No newline at end of file diff --git a/UnStable-main/lovely/Seal.toml b/UnStable-main/lovely/Seal.toml new file mode 100644 index 0000000..e166e11 --- /dev/null +++ b/UnStable-main/lovely/Seal.toml @@ -0,0 +1,15 @@ +[manifest] +version = "1.0.0" +dump_lua = true +priority = 0 + +# Shiny Seal +[[patches]] +[patches.pattern] +target = 'card.lua' +pattern = "if self.seal == 'Gold' then G.shared_seals[self.seal]:draw_shader('voucher', nil, self.ARGS.send_to_shader, nil, self.children.center) end" +position = "before" +match_indent = true +payload = ''' +if SMODS.Seals[self.seal] and SMODS.Seals[self.seal].shiny then G.shared_seals[self.seal]:draw_shader('voucher', nil, self.ARGS.send_to_shader, nil, self.children.center) end +''' diff --git a/lovely/hello b/lovely/hello new file mode 100644 index 0000000..e69de29