[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)"""


# Add h_chips as a viable hand effect
[[patches]]
[patches.pattern]
target = 'functions/state_events.lua'
pattern = '''card_eval_status_text(G.hand.cards[i], 'h_mult', effects[ii].h_mult, percent)
                        end'''
position = 'after'
match_indent = true
payload = '''
if effects[ii].h_chips then 
    if effects[ii].card then juice_card(effects[ii].card) end
    hand_chips = mod_chips(hand_chips + effects[ii].h_chips)
    update_hand_text({delay = 0}, {chips = hand_chips})
    card_eval_status_text(effects[ii].card, 'chips', effects[ii].h_chips, percent)
end
'''

# 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 = ''' '''
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); st = {} end"""
overwrite = true
match_indent = true
