[manifest]
version = "1.0.0"
dump_lua = true
priority = -10

### Center API

# Card:set_ability()
[[patches]]
[patches.regex]
target = "card.lua"
pattern = "(?<indent>[\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>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
    local specific_vars = specific_vars or {}
    _c:generate_ui(info_queue, card, desc_nodes, specific_vars, full_UI_table)
    if desc_nodes ~= full_UI_table.main then
        -- TODO should be moved into generate_ui;
        -- also the multiple generate_ui cases should be refactored
        -- to work off a base implementation
        desc_nodes.name_styled = {}
        local set = name_override and "Other" or _c.set
        local key = name_override or _c.key
        if set == "Seal" then
            if G.localization.descriptions["Other"][_c.key.."_seal"] then set = "Other"; key = key.."_seal" end
        else
            if not G.localization.descriptions[set] or not G.localization.descriptions[set][_c.key] then set = "Other" end
        end

        localize{type = 'name', key = key, set = set, nodes = desc_nodes.name_styled, fixed_scale = 0.63, no_pop_in = true, no_shadow = true, y_offset = 0, no_spacing = true, no_bump = true, vars = (_c.create_fake_card and _c.loc_vars and (_c:loc_vars({}, _c:create_fake_card()) or {}).vars) or {colours = {}}} 
        desc_nodes.name_styled = SMODS.info_queue_desc_from_rows(desc_nodes.name_styled, true)
        desc_nodes.name_styled.config.align = "cm"
    end
    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 = "(?<indent>[\t ]+)if (?<rest>_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 = "(?<indent>[\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 = "(?<indent>[\t ]*)if(?<a> )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 = "(?<indent>[\t ]*)if(?<a> )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 = "(?<indent>[\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 = "(?<indent>[\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 = "(?<indent>[\t ]*)(?<if>if AUT.badges.card_type or AUT.badges.force_rarity then)\n[\t ]*(?<rest>.*)\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'''

# mod badges
[[patches]]
[patches.pattern]
target = 'functions/UI_definitions.lua'
match_indent = true
position = 'before'
pattern = '''
if AUT.info then
'''
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 = "(?<indent>[\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 = "(?<indent>[\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 = "(?<indent>[\t ]*)local t = create_UIBox_generic_options\\(\\{ back_func = G.STAGE"
line_prepend = '$indent'
position = 'before'
payload = '''
local consumable_nodes = {}
if #SMODS.ConsumableType.visible_buffer <= 3 then
    for _, key in ipairs(SMODS.ConsumableType.visible_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.visible_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 = "(?<indent>[\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 = "(?<indent>[\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 = '(?<indent>[\t ]*)for _, v in ipairs\((?<li>\{\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 SMODS.showman(v.key) and not v.can_repeat_soul) and SMODS.add_to_pool(v) 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 = "local card = Card(area.T.x + area.T.w/2, area.T.y, G.CARD_W, G.CARD_H, front, center,"
match_indent = true
position = 'at'
payload = '''
local card = Card(area.T.x + area.T.w/2, area.T.y, G.CARD_W, G.CARD_H, SMODS.set_create_card_front or front, center,'''

[[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, '''

[[patches]]
[patches.pattern]
target = 'functions/common_events.lua'
pattern = '''not (G.GAME.used_jokers['c_soul'] and not next(find_joker("Showman")))  then'''
match_indent = true
position = 'at'
payload = '''
not (G.GAME.used_jokers['c_soul'] and not SMODS.showman('c_soul')) then'''

[[patches]]
[patches.pattern]
target = 'functions/common_events.lua'
pattern = '''not (G.GAME.used_jokers['c_black_hole'] and not next(find_joker("Showman")))  then'''
match_indent = true
position = 'at'
payload = '''
not (G.GAME.used_jokers['c_black_hole'] and not SMODS.showman('c_black_hole')) then'''

# Fix vanilla copy_card back bug
# copy_card()
[[patches]]
[patches.pattern]
target = "functions/common_events.lua"
pattern = '''
local new_card = new_card or Card(other.T.x, other.T.y, G.CARD_W*(card_scale or 1), G.CARD_H*(card_scale or 1), G.P_CARDS.empty, G.P_CENTERS.c_base, {playing_card = playing_card})
'''
position = "at"
payload = '''
local new_card = new_card or Card(other.T.x, other.T.y, G.CARD_W*(card_scale or 1), G.CARD_H*(card_scale or 1), G.P_CARDS.empty, G.P_CENTERS.c_base, {playing_card = playing_card, bypass_back = G.GAME.selected_back.pos})
'''
match_indent = true

# Card:add_to_deck()
[[patches]]
[patches.regex]
target = 'card.lua'
pattern = '(?<indent>[\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 = '(?<indent>[\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'
match_indent = true
position = 'at'
pattern = '''
if G.booster_pack and not G.booster_pack.alignment.offset.py and (card.ability.consumeable or not (G.GAME.pack_choices and G.GAME.pack_choices > 1)) then
'''
payload = '''
local nc
local select_to = card.area == G.pack_cards and G.pack_cards and booster_obj and SMODS.card_select_area(card, booster_obj) 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 G.booster_pack and not G.booster_pack.alignment.offset.py and ((not select_to and card.ability.consumeable) or not (G.GAME.pack_choices and G.GAME.pack_choices > 1)) then

'''


# 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 = '''
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 other_joker.debuff 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
        -- temporary stopgap. fake cards should be implemented better
        ability.x_mult = _c['config'].Xmult or _c['config'].x_mult
        if ability.name == 'To Do List' then
            ability.to_do_poker_hand = "High Card" -- fallback
        end
        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
    '''
