balatro-mods/smods-main/lovely/fixes.toml

644 lines
19 KiB
TOML

[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 = "(?<indent>[\t ]*)if not \\(st.init and st:init\\(\\)\\) then\n[\t ]*(?<quit>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 = '''
(?<indent>[\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 = '''
(?<indent>[\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 = 'before'
match_indent = true
payload = '''
if self.added_to_deck and old_center and not self.debuff then
self:remove_from_deck()
self.added_to_deck = true
end'''
[[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'''
## 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 = '''
(?<indent>[\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'}
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.pattern]
target = 'blind.lua'
pattern = "if self.name == 'Crimson Heart' and self.prepped and G.jokers.cards[1] then"
position = 'after'
match_indent = true
payload = """
local prev_chosen_set = {}
local fallback_jokers = {}"""
# Fix bad logic if not enough choices for debuff
[[patches]]
[patches.regex]
target = 'blind.lua'
pattern = '''
(?<indent>[\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+
((?<indent>[\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.pattern]
target = 'blind.lua'
pattern = "if self.name == 'The Water' then"
position = 'before'
payload = """
if self.name == 'Crimson Heart' then
for _, v in ipairs(G.jokers.cards) do
v.ability.crimson_heart_chosen = nil
end
end"""
match_indent = true
## Blind:defeat()
[[patches]]
[patches.pattern]
target = 'blind.lua'
pattern = "if self.name == 'The Manacle' and not self.disabled then"
position = 'before'
payload = """
if self.name == 'Crimson Heart' then
for _, v in ipairs(G.jokers.cards) do
v.ability.crimson_heart_chosen = nil
end
end"""
match_indent = true
## 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 then"
# Blind:set_blind
[[patches]]
[patches.pattern]
target = "blind.lua"
match_indent = true
pattern = "if not reset then"
position = "after"
payload = '''
if blind then
self.in_blind = true
end'''
# 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'
##
## Card:draw() - improved mod compatibility
##
# Add option for sprites to not be drawn
[[patches]]
[patches.pattern]
target = "card.lua"
match_indent = true
pattern = '''
if k ~= 'focused_ui' and k ~= "front" and k ~= "back" and k ~= "soul_parts" and k ~= "center" and k ~= 'floating_sprite' and k~= "shadow" and k~= "use_button" and k ~= 'buy_button' and k ~= 'buy_and_use_button' and k~= "debuff" and k ~= 'price' and k~= 'particles' and k ~= 'h_popup' then v:draw() end'''
position = "at"
payload = '''
if not v.custom_draw and k ~= 'focused_ui' and k ~= "front" and k ~= "back" and k ~= "soul_parts" and k ~= "center" and k ~= 'floating_sprite' and k~= "shadow" and k~= "use_button" and k ~= 'buy_button' and k ~= 'buy_and_use_button' and k~= "debuff" and k ~= 'price' and k~= 'particles' and k ~= 'h_popup' then v:draw() end'''
# This check is not necessary?
[[patches]]
[patches.pattern]
target = "card.lua"
match_indent = true
pattern = '''
if self.edition or self.seal or self.ability.eternal or self.ability.rental or self.ability.perishable or self.sticker or ((self.sticker_run and self.sticker_run ~= 'NONE') and G.SETTINGS.run_stake_stickers) or (self.ability.set == 'Spectral') or self.debuff or self.greyed or (self.ability.name == 'The Soul') or (self.ability.set == 'Voucher') or (self.ability.set == 'Booster') or self.config.center.soul_pos or self.config.center.demo then'''
position = "at"
payload = '''
if true then'''
## 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 = ''' '''
# 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); st = {} end"""
overwrite = true
match_indent = true