LOVELY_INTEGRITY = 'fff73090942942422c5293599c9a5f94fd18419e9275888a510770e6688dd01c'

--Class
Game = Object:extend()

--Class Methods
function Game:init()
    G = self

    self:set_globals()
end

function Game:start_up()
    --Load the settings file
    local settings = get_compressed('settings.jkr')
    local settings_ver = nil
    if settings then 
        local settings_file = STR_UNPACK(settings)
        if G.VERSION >= '1.0.0' and (love.system.getOS() == 'NOPE') and ((not settings_file.version) or (settings_file.version < '1.0.0')) then 
            for i = 1, 3 do
                love.filesystem.remove(i..'/'..'profile.jkr')
                love.filesystem.remove(i..'/'..'save.jkr')
                love.filesystem.remove(i..'/'..'meta.jkr')
                love.filesystem.remove(i..'/'..'unlock_notify.jkr')
                love.filesystem.remove(i..'')
            end
            for k, v in pairs(settings_file) do
                self.SETTINGS[k] = v
            end
            self.SETTINGS.profile = 1
            self.SETTINGS.tutorial_progress = nil
        else 
            if G.VERSION < '1.0.0' then 
                settings_ver = settings_file.version
            end
            for k, v in pairs(settings_file) do
                self.SETTINGS[k] = v
            end
        end
    end
    self.SETTINGS.version = settings_ver or G.VERSION
    self.SETTINGS.paused = nil

    local new_colour_proto = self.C["SO_"..(self.SETTINGS.colourblind_option and 2 or 1)]
    self.C.SUITS.Hearts = new_colour_proto.Hearts
    self.C.SUITS.Diamonds = new_colour_proto.Diamonds
    self.C.SUITS.Spades = new_colour_proto.Spades
    self.C.SUITS.Clubs = new_colour_proto.Clubs

    boot_timer('start', 'settings', 0.1)

    if self.SETTINGS.GRAPHICS.texture_scaling then
        self.SETTINGS.GRAPHICS.texture_scaling = self.SETTINGS.GRAPHICS.texture_scaling > 1 and 2 or 1
    end

    if self.SETTINGS.DEMO and not self.F_CTA then
        self.SETTINGS.DEMO = {
            total_uptime = 0,
            timed_CTA_shown = true,
            win_CTA_shown = true,
            quit_CTA_shown = true
        }
    end

    --create all sounds from resources and play one each to load into mem
    SOURCES = {}
    local sound_files = love.filesystem.getDirectoryItems("resources/sounds")

    for _, filename in ipairs(sound_files) do
        local extension = string.sub(filename, -4)
        if extension == '.ogg' then
            local sound_code = string.sub(filename, 1, -5)
            SOURCES[sound_code] = {}
        end
    end

    self.SETTINGS.language = self.SETTINGS.language or 'en-us'
    boot_timer('settings', 'window init', 0.2)
    self:init_window()

    if G.F_SOUND_THREAD then
        boot_timer('window init', 'soundmanager2')
        --call the sound manager to prepare the thread to play sounds
        self.SOUND_MANAGER = {
            thread = love.thread.newThread('engine/sound_manager.lua'),
            channel = love.thread.getChannel('sound_request'),
            load_channel = love.thread.getChannel('load_channel')
        }
        self.SOUND_MANAGER.thread:start(1)

        local sound_loaded, prev_file = false, 'none'
        while not sound_loaded and false do
            --Monitor the channel for any new requests
            local request = self.SOUND_MANAGER.load_channel:pop() -- Value from channel
            if request then
                --If the request is for an update to the music track, handle it here
                if request == 'finished' then sound_loaded = true
                else
                    boot_timer(request, prev_file)
                    prev_file = request
                end
            end
            love.timer.sleep(0.001)
        end
    
        boot_timer('soundmanager2', 'savemanager',0.22)
    end

    boot_timer('window init', 'savemanager')
    --call the save manager to wait for any save requests
    G.SAVE_MANAGER = {
        thread = love.thread.newThread('engine/save_manager.lua'),
        channel = love.thread.getChannel('save_request')
    }
    G.SAVE_MANAGER.thread:start(2)
    boot_timer('savemanager', 'shaders',0.4)

    --call the http manager
    G.HTTP_MANAGER = {
        thread = love.thread.newThread('engine/http_manager.lua'),
        out_channel = love.thread.getChannel('http_request'),
        in_channel = love.thread.getChannel('http_response')
    }
    if G.F_HTTP_SCORES then
        G.HTTP_MANAGER.thread:start()
    end

    --Load all shaders from resources
    self.SHADERS = {}
    local shader_files = love.filesystem.getDirectoryItems("resources/shaders")
    for k, filename in ipairs(shader_files) do
        local extension = string.sub(filename, -3)
        if extension == '.fs' then
            local shader_name = string.sub(filename, 1, -4)
            self.SHADERS[shader_name] = love.graphics.newShader("resources/shaders/"..filename)
        end
    end

    boot_timer('shaders', 'controllers',0.7)

    --Input handler/controller for game objects
    self.CONTROLLER = Controller()
    love.joystick.loadGamepadMappings("resources/gamecontrollerdb.txt")
    if self.F_RUMBLE then 
        local joysticks = love.joystick.getJoysticks()
        if joysticks then 
            if joysticks[1] then 
                self.CONTROLLER:set_gamepad(joysticks[2] or joysticks[1])
            end
        end
    end
    boot_timer('controllers', 'localization',0.8)

    if self.SETTINGS.GRAPHICS.texture_scaling then
        self.SETTINGS.GRAPHICS.texture_scaling = self.SETTINGS.GRAPHICS.texture_scaling > 1 and 2 or 1
    end

    self:load_profile(G.SETTINGS.profile or 1)

    self.SETTINGS.QUEUED_CHANGE = {}
    self.SETTINGS.music_control = {desired_track = '', current_track = '', lerp = 1} 

    self:set_render_settings()

    self:set_language()

    self:init_item_prototypes()
    boot_timer('protos', 'shared sprites',0.9)

    --For globally shared sprites
    self.shared_debuff = Sprite(0, 0, self.CARD_W, self.CARD_H, self.ASSET_ATLAS["centers"], {x=4, y = 0})

    self.shared_soul = Sprite(0, 0, self.CARD_W, self.CARD_H, self.ASSET_ATLAS["centers"], self.P_CENTERS.soul.pos)
    self.shared_undiscovered_joker = Sprite(0, 0, self.CARD_W, self.CARD_H, self.ASSET_ATLAS["centers"], self.P_CENTERS.undiscovered_joker.pos)
    self.shared_undiscovered_tarot = Sprite(0, 0, self.CARD_W, self.CARD_H, self.ASSET_ATLAS["centers"], self.P_CENTERS.undiscovered_tarot.pos)

    self.shared_sticker_eternal = Sprite(0, 0, self.CARD_W, self.CARD_H, self.ASSET_ATLAS["stickers"], {x = 0,y = 0})
    self.shared_sticker_perishable = Sprite(0, 0, self.CARD_W, self.CARD_H, self.ASSET_ATLAS["stickers"], {x = 0,y = 2})
    self.shared_sticker_rental = Sprite(0, 0, self.CARD_W, self.CARD_H, self.ASSET_ATLAS["stickers"], {x = 1,y = 2})
    
    self.shared_stickers = {
        White = Sprite(0, 0, self.CARD_W, self.CARD_H, self.ASSET_ATLAS["stickers"], {x = 1,y = 0}),
        Red = Sprite(0, 0, self.CARD_W, self.CARD_H, self.ASSET_ATLAS["stickers"], {x = 2,y = 0}),
        Green = Sprite(0, 0, self.CARD_W, self.CARD_H, self.ASSET_ATLAS["stickers"], {x = 3,y = 0}),
        Black = Sprite(0, 0, self.CARD_W, self.CARD_H, self.ASSET_ATLAS["stickers"], {x = 0,y = 1}),
        Blue = Sprite(0, 0, self.CARD_W, self.CARD_H, self.ASSET_ATLAS["stickers"], {x = 4,y = 0}),
        Purple = Sprite(0, 0, self.CARD_W, self.CARD_H, self.ASSET_ATLAS["stickers"], {x = 1,y = 1}),
        Orange = Sprite(0, 0, self.CARD_W, self.CARD_H, self.ASSET_ATLAS["stickers"], {x = 2,y = 1}),
        Gold = Sprite(0, 0, self.CARD_W, self.CARD_H, self.ASSET_ATLAS["stickers"], {x = 3,y = 1})
    }
    self.shared_seals = {
        Gold = Sprite(0, 0, self.CARD_W, self.CARD_H, self.ASSET_ATLAS["centers"], {x = 2,y = 0}),
        Purple = Sprite(0, 0, self.CARD_W, self.CARD_H, self.ASSET_ATLAS["centers"], {x = 4,y = 4}),
        Red = Sprite(0, 0, self.CARD_W, self.CARD_H, self.ASSET_ATLAS["centers"], {x = 5,y = 4}),
        Blue = Sprite(0, 0, self.CARD_W, self.CARD_H, self.ASSET_ATLAS["centers"], {x = 6,y = 4}),
    }
    self.sticker_map = {
        'White','Red','Green','Black','Blue','Purple','Orange','Gold'
    }
    boot_timer('shared sprites', 'prep stage',0.95)

    --For the visible cursor
    G.STAGE_OBJECT_INTERRUPT =true
    self.CURSOR = Sprite(0,0,0.3, 0.3, self.ASSET_ATLAS['gamepad_ui'], {x = 18, y = 0})
    self.CURSOR.states.collide.can = false
    G.STAGE_OBJECT_INTERRUPT = false

    --Create the event manager for the game
    self.E_MANAGER = EventManager()
    self.SPEEDFACTOR = 1
    initSteamodded()

    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
    set_profile_progress()
    boot_timer('prep stage', 'splash prep',1)
    self:splash_screen()
    boot_timer('splash prep', 'end',1)
end

function Game:init_item_prototypes()
    --Initialize all prototypes for units/items
    self.P_SEALS = {
        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"},
        }

    self.P_TAGS = {
        tag_uncommon =      {name = 'Uncommon Tag',     set = 'Tag', discovered = false, min_ante = nil, order = 1, config = {type = 'store_joker_create'}, pos = {x = 0,y = 0}},
        tag_rare =          {name = 'Rare Tag',         set = 'Tag', discovered = false, min_ante = nil, order = 2, config = {type = 'store_joker_create', odds = 3}, requires = 'j_blueprint', pos = {x = 1,y = 0}},
        tag_negative =      {name = 'Negative Tag',     set = 'Tag', discovered = false, min_ante = 2,   order = 3, config = {type = 'store_joker_modify', edition = 'negative', odds = 5}, requires = 'e_negative', pos = {x = 2, y = 0}},
        tag_foil =          {name = 'Foil Tag',         set = 'Tag', discovered = false, min_ante = nil, order = 4, config = {type = 'store_joker_modify', edition = 'foil', odds = 2}, requires = 'e_foil', pos = {x = 3,y = 0}},
        tag_holo =          {name = 'Holographic Tag',  set = 'Tag', discovered = false, min_ante = nil, order = 5, config = {type = 'store_joker_modify', edition = 'holo', odds = 3}, requires = 'e_holo', pos = {x = 0,y = 1}},
        tag_polychrome =    {name = 'Polychrome Tag',   set = 'Tag', discovered = false, min_ante = nil, order = 6, config = {type = 'store_joker_modify', edition = 'polychrome', odds = 4}, requires = 'e_polychrome', pos = {x = 1,y = 1}},
        tag_investment =    {name = 'Investment Tag',   set = 'Tag', discovered = false, min_ante = nil, order = 7, config = {type = 'eval', dollars = 25}, pos = {x = 2,y = 1}},
        tag_voucher =       {name = 'Voucher Tag',      set = 'Tag', discovered = false, min_ante = nil, order = 8, config = {type = 'voucher_add'}, pos = {x = 3,y = 1}},
        tag_boss =          {name = 'Boss Tag',         set = 'Tag', discovered = false, min_ante = nil, order = 9, config = {type = 'new_blind_choice', }, pos = {x = 0,y = 2}},
        tag_standard =      {name = 'Standard Tag',     set = 'Tag', discovered = false, min_ante = 2,   order = 10, config = {type = 'new_blind_choice', }, pos = {x = 1,y = 2}},
        tag_charm =         {name = 'Charm Tag',        set = 'Tag', discovered = false, min_ante = nil, order = 11, config = {type = 'new_blind_choice', }, pos = {x = 2,y = 2}},
        tag_meteor =        {name = 'Meteor Tag',       set = 'Tag', discovered = false, min_ante = 2,   order = 12, config = {type = 'new_blind_choice', }, pos = {x = 3,y = 2}},
        tag_buffoon =       {name = 'Buffoon Tag',      set = 'Tag', discovered = false, min_ante = 2,   order = 13, config = {type = 'new_blind_choice', }, pos = {x = 4,y = 2}},
        tag_handy =         {name = 'Handy Tag',        set = 'Tag', discovered = false, min_ante = 2,   order = 14, config = {type = 'immediate', dollars_per_hand = 1}, pos = {x = 1,y = 3}},
        tag_garbage =       {name = 'Garbage Tag',      set = 'Tag', discovered = false, min_ante = 2,   order = 15, config = {type = 'immediate', dollars_per_discard = 1}, pos = {x = 2,y = 3}},
        tag_ethereal =      {name = 'Ethereal Tag',     set = 'Tag', discovered = false, min_ante = 2,   order = 16, config = {type = 'new_blind_choice'}, pos = {x = 3,y = 3}},
        tag_coupon =        {name = 'Coupon Tag',       set = 'Tag', discovered = false, min_ante = nil, order = 17, config = {type = 'shop_final_pass', }, pos = {x = 4,y = 0}},
        tag_double =        {name = 'Double Tag',       set = 'Tag', discovered = false, min_ante = nil, order = 18, config = {type = 'tag_add', }, pos = {x = 5,y = 0}},
        tag_juggle =        {name = 'Juggle Tag',       set = 'Tag', discovered = false, min_ante = nil, order = 19, config = {type = 'round_start_bonus', h_size = 3}, pos = {x = 5,y = 1}},
        tag_d_six =         {name = 'D6 Tag',           set = 'Tag', discovered = false, min_ante = nil, order = 20, config = {type = 'shop_start', }, pos = {x = 5,y = 3}},
        tag_top_up =        {name = 'Top-up Tag',       set = 'Tag', discovered = false, min_ante = 2,   order = 21, config = {type = 'immediate', spawn_jokers = 2}, pos = {x = 4,y = 1}},
        tag_skip =          {name = 'Skip Tag',         set = 'Tag', discovered = false, min_ante = nil, order = 22, config = {type = 'immediate', skip_bonus = 5}, pos = {x = 0,y = 3}},
        tag_orbital =       {name = 'Orbital Tag',      set = 'Tag', discovered = false, min_ante = 2,   order = 23, config = {type = 'immediate', levels = 3}, pos = {x = 5,y = 2}},
        tag_economy =       {name = 'Economy Tag',      set = 'Tag', discovered = false, min_ante = nil, order = 24, config = {type = 'immediate', max = 40}, pos = {x = 4,y = 3}},
    }
    self.tag_undiscovered = {name = 'Not Discovered', order = 1, config = {type = ''}, pos = {x=3,y=4}}

    self.P_STAKES = {
        stake_white =   {name = 'White Chip',   unlocked = true,  order = 1, pos = {x = 0,y = 0}, stake_level = 1, set = 'Stake'},
        stake_red =     {name = 'Red Chip',     unlocked = false, order = 2, pos = {x = 1,y = 0}, stake_level = 2, set = 'Stake'},
        stake_green =   {name = 'Green Chip',   unlocked = false, order = 3, pos = {x = 2,y = 0}, stake_level = 3, set = 'Stake'},  
        stake_black =   {name = 'Black Chip',   unlocked = false, order = 4, pos = {x = 4,y = 0}, stake_level = 4, set = 'Stake'},
        stake_blue =    {name = 'Blue Chip',    unlocked = false, order = 5, pos = {x = 3,y = 0}, stake_level = 5, set = 'Stake'},
        stake_purple =  {name = 'Purple Chip',  unlocked = false, order = 6, pos = {x = 0,y = 1}, stake_level = 6, set = 'Stake'},
        stake_orange =  {name = 'Orange Chip',  unlocked = false, order = 7, pos = {x = 1,y = 1}, stake_level = 7, set = 'Stake'},
        stake_gold =    {name = 'Gold Chip',    unlocked = false, order = 8, pos = {x = 2,y = 1}, stake_level = 8, set = 'Stake'},
    }

    self.P_BLINDS = {
        bl_small =           {name = 'Small Blind',  defeated = false, order = 1, dollars = 3, mult = 1,  vars = {}, debuff_text = '', debuff = {}, pos = {x=0, y=0}},
        bl_big =             {name = 'Big Blind',    defeated = false, order = 2, dollars = 4, mult = 1.5,vars = {}, debuff_text = '', debuff = {}, pos = {x=0, y=1}},
        bl_ox =              {name = 'The Ox',       defeated = false, order = 4, dollars = 5, mult = 2,  vars = {localize('ph_most_played')}, debuff = {}, pos = {x=0, y=2}, boss = {min = 6, max = 10}, boss_colour = HEX('b95b08')},
        bl_hook =            {name = 'The Hook',     defeated = false, order = 3, dollars = 5, mult = 2,  vars = {}, debuff = {}, pos = {x=0, y=7}, boss = {min = 1, max = 10}, boss_colour = HEX('a84024')},
        bl_mouth =           {name = 'The Mouth',    defeated = false, order = 17, dollars = 5, mult = 2, vars = {}, debuff = {}, pos = {x=0, y=18}, boss = {min = 2, max = 10}, boss_colour = HEX('ae718e')},
        bl_fish =            {name = 'The Fish',     defeated = false, order = 10, dollars = 5, mult = 2, vars = {}, debuff = {}, pos = {x=0, y=5}, boss = {min = 2, max = 10}, boss_colour = HEX('3e85bd')},
        bl_club =            {name = 'The Club',     defeated = false, order = 9, dollars = 5, mult = 2,  vars = {}, debuff = {suit = 'Clubs'}, pos = {x=0, y=4}, boss = {min = 1, max = 10}, boss_colour = HEX('b9cb92')},
        bl_manacle =         {name = 'The Manacle',  defeated = false, order = 15, dollars = 5, mult = 2, vars = {}, debuff = {}, pos = {x=0, y=8}, boss = {min = 1, max = 10}, boss_colour = HEX('575757')},
        bl_tooth =           {name = 'The Tooth',    defeated = false, order = 23, dollars = 5, mult = 2, vars = {}, debuff = {}, pos = {x=0, y=22}, boss = {min = 3, max = 10}, boss_colour = HEX('b52d2d')},
        bl_wall =            {name = 'The Wall',     defeated = false, order = 6, dollars = 5, mult = 4,  vars = {}, debuff = {}, pos = {x=0, y=9}, boss = {min = 2, max = 10}, boss_colour = HEX('8a59a5')},
        bl_house =           {name = 'The House',    defeated = false, order = 5, dollars = 5, mult = 2,  vars = {}, debuff = {}, pos = {x=0, y=3}, boss ={min = 2, max = 10}, boss_colour = HEX('5186a8')},
        bl_mark =            {name = 'The Mark',     defeated = false, order = 25, dollars = 5, mult = 2, vars = {}, debuff = {}, pos = {x=0, y=23}, boss = {min = 2, max = 10}, boss_colour = HEX('6a3847')},

        bl_final_bell =      {name = 'Cerulean Bell',defeated = false, order = 30, dollars = 8, mult = 2, vars = {}, debuff = {}, pos = {x=0, y=26}, boss = {showdown = true, min = 10, max = 10}, boss_colour = HEX('009cfd')},
        bl_wheel =           {name = 'The Wheel',    defeated = false, order = 7, dollars = 5, mult = 2,  vars = {}, debuff = {}, pos = {x=0, y=10}, boss = {min = 2, max = 10}, boss_colour = HEX('50bf7c')},
        bl_arm =             {name = 'The Arm',      defeated = false, order = 8, dollars = 5, mult = 2,  vars = {}, debuff = {}, pos = {x=0, y=11}, boss = {min = 2, max = 10}, boss_colour = HEX('6865f3')},
        bl_psychic =         {name = 'The Psychic',  defeated = false, order = 11, dollars = 5, mult = 2, vars = {}, debuff = {h_size_ge = 5}, pos = {x=0, y=12}, boss = {min = 1, max = 10}, boss_colour = HEX('efc03c')},
        bl_goad =            {name = 'The Goad',     defeated = false, order = 12, dollars = 5, mult = 2, vars = {}, debuff = {suit = 'Spades'}, pos = {x=0, y=13}, boss = {min = 1, max = 10}, boss_colour = HEX('b95c96')},
        bl_water =           {name = 'The Water',    defeated = false, order = 13, dollars = 5, mult = 2, vars = {}, debuff = {}, pos = {x=0, y=14}, boss = {min = 2, max = 10}, boss_colour = HEX('c6e0eb')},
        bl_eye =             {name = 'The Eye',      defeated = false, order = 16, dollars = 5, mult = 2, vars = {}, debuff = {}, pos = {x=0, y=17}, boss = {min = 3, max = 10}, boss_colour = HEX('4b71e4')},
        bl_plant =           {name = 'The Plant',    defeated = false, order = 18, dollars = 5, mult = 2, vars = {}, debuff = {is_face = 'face'}, pos = {x=0, y=19}, boss = {min = 4, max = 10}, boss_colour = HEX('709284')},
        bl_needle =          {name = 'The Needle',   defeated = false, order = 21, dollars = 5, mult = 1, vars = {}, debuff = {}, pos = {x=0, y=20}, boss = {min = 2, max = 10}, boss_colour = HEX('5c6e31')},
        bl_head =            {name = 'The Head',     defeated = false, order = 22, dollars = 5, mult = 2, vars = {}, debuff = {suit = 'Hearts'}, pos = {x=0, y=21}, boss = {min = 1, max = 10}, boss_colour = HEX('ac9db4')},
        bl_final_leaf =      {name = 'Verdant Leaf', defeated = false, order = 27, dollars = 8, mult = 2, vars = {}, debuff = {}, pos = {x=0, y=28}, boss = {showdown = true, min = 10, max = 10}, boss_colour = HEX('56a786')},
        bl_final_vessel =    {name = 'Violet Vessel',defeated = false, order = 28, dollars = 8, mult = 6, vars = {}, debuff = {}, pos = {x=0, y=29}, boss = {showdown = true, min = 10, max = 10}, boss_colour = HEX('8a71e1')},
        bl_window =          {name = 'The Window',   defeated = false, order = 14, dollars = 5, mult = 2, vars = {}, debuff = {suit = 'Diamonds'}, pos = {x=0, y=6}, boss = {min = 1, max = 10}, boss_colour = HEX('a9a295')},
        bl_serpent =         {name = 'The Serpent',  defeated = false, order = 19, dollars = 5, mult = 2, vars = {}, debuff = {}, pos = {x=0, y=15}, boss = {min = 5, max = 10}, boss_colour = HEX('439a4f')},
        bl_pillar =          {name = 'The Pillar',   defeated = false, order = 20, dollars = 5, mult = 2, vars = {}, debuff = {}, pos = {x=0, y=16}, boss = {min = 1, max = 10}, boss_colour = HEX('7e6752')},
        bl_flint =           {name = 'The Flint',    defeated = false, order = 24, dollars = 5, mult = 2, vars = {}, debuff = {}, pos = {x=0, y=24}, boss = {min = 2, max = 10}, boss_colour = HEX('e56a2f')},
        bl_final_acorn =     {name = 'Amber Acorn',  defeated = false, order = 26, dollars = 8, mult = 2, vars = {}, debuff = {}, pos = {x=0, y=27}, boss = {showdown = true, min = 10, max = 10}, boss_colour = HEX('fda200')},
        bl_final_heart =     {name = 'Crimson Heart',defeated = false, order = 29, dollars = 8, mult = 2, vars = {}, debuff = {}, pos = {x=0, y=25}, boss = {showdown = true, min = 10, max = 10}, boss_colour = HEX('ac3232')},
        
    }
    self.b_undiscovered = {name = 'Undiscovered', debuff_text = 'Defeat this blind to discover', pos = {x=0,y=30}}

    self.P_CARDS = {
        H_2={name = "2 of Hearts",value = '2', suit = 'Hearts', pos = {x=0,y=0}},
        H_3={name = "3 of Hearts",value = '3', suit = 'Hearts', pos = {x=1,y=0}},
        H_4={name = "4 of Hearts",value = '4', suit = 'Hearts', pos = {x=2,y=0}},
        H_5={name = "5 of Hearts",value = '5', suit = 'Hearts', pos = {x=3,y=0}},
        H_6={name = "6 of Hearts",value = '6', suit = 'Hearts', pos = {x=4,y=0}},
        H_7={name = "7 of Hearts",value = '7', suit = 'Hearts', pos = {x=5,y=0}},
        H_8={name = "8 of Hearts",value = '8', suit = 'Hearts', pos = {x=6,y=0}},
        H_9={name = "9 of Hearts",value = '9', suit = 'Hearts', pos = {x=7,y=0}},
        H_T={name = "10 of Hearts",value = '10', suit = 'Hearts', pos = {x=8,y=0}},
        H_J={name = "Jack of Hearts",value = 'Jack', suit = 'Hearts', pos = {x=9,y=0}},
        H_Q={name = "Queen of Hearts",value = 'Queen', suit = 'Hearts', pos = {x=10,y=0}},
        H_K={name = "King of Hearts",value = 'King', suit = 'Hearts', pos = {x=11,y=0}},
        H_A={name = "Ace of Hearts",value = 'Ace', suit = 'Hearts', pos = {x=12,y=0}},
        C_2={name = "2 of Clubs",value = '2', suit = 'Clubs', pos = {x=0,y=1}},
        C_3={name = "3 of Clubs",value = '3', suit = 'Clubs', pos = {x=1,y=1}},
        C_4={name = "4 of Clubs",value = '4', suit = 'Clubs', pos = {x=2,y=1}},
        C_5={name = "5 of Clubs",value = '5', suit = 'Clubs', pos = {x=3,y=1}},
        C_6={name = "6 of Clubs",value = '6', suit = 'Clubs', pos = {x=4,y=1}},
        C_7={name = "7 of Clubs",value = '7', suit = 'Clubs', pos = {x=5,y=1}},
        C_8={name = "8 of Clubs",value = '8', suit = 'Clubs', pos = {x=6,y=1}},
        C_9={name = "9 of Clubs",value = '9', suit = 'Clubs', pos = {x=7,y=1}},
        C_T={name = "10 of Clubs",value = '10', suit = 'Clubs', pos = {x=8,y=1}},
        C_J={name = "Jack of Clubs",value = 'Jack', suit = 'Clubs', pos = {x=9,y=1}},
        C_Q={name = "Queen of Clubs",value = 'Queen', suit = 'Clubs', pos = {x=10,y=1}},
        C_K={name = "King of Clubs",value = 'King', suit = 'Clubs', pos = {x=11,y=1}},
        C_A={name = "Ace of Clubs",value = 'Ace', suit = 'Clubs', pos = {x=12,y=1}},
        D_2={name = "2 of Diamonds",value = '2', suit = 'Diamonds', pos = {x=0,y=2}},
        D_3={name = "3 of Diamonds",value = '3', suit = 'Diamonds', pos = {x=1,y=2}},
        D_4={name = "4 of Diamonds",value = '4', suit = 'Diamonds', pos = {x=2,y=2}},
        D_5={name = "5 of Diamonds",value = '5', suit = 'Diamonds', pos = {x=3,y=2}},
        D_6={name = "6 of Diamonds",value = '6', suit = 'Diamonds', pos = {x=4,y=2}},
        D_7={name = "7 of Diamonds",value = '7', suit = 'Diamonds', pos = {x=5,y=2}},
        D_8={name = "8 of Diamonds",value = '8', suit = 'Diamonds', pos = {x=6,y=2}},
        D_9={name = "9 of Diamonds",value = '9', suit = 'Diamonds', pos = {x=7,y=2}},
        D_T={name = "10 of Diamonds",value = '10', suit = 'Diamonds', pos = {x=8,y=2}},
        D_J={name = "Jack of Diamonds",value = 'Jack', suit = 'Diamonds', pos = {x=9,y=2}},
        D_Q={name = "Queen of Diamonds",value = 'Queen', suit = 'Diamonds', pos = {x=10,y=2}},
        D_K={name = "King of Diamonds",value = 'King', suit = 'Diamonds', pos = {x=11,y=2}},
        D_A={name = "Ace of Diamonds",value = 'Ace', suit = 'Diamonds', pos = {x=12,y=2}},
        S_2={name = "2 of Spades",value = '2', suit = 'Spades', pos = {x=0,y=3}},
        S_3={name = "3 of Spades",value = '3', suit = 'Spades', pos = {x=1,y=3}},
        S_4={name = "4 of Spades",value = '4', suit = 'Spades', pos = {x=2,y=3}},
        S_5={name = "5 of Spades",value = '5', suit = 'Spades', pos = {x=3,y=3}},
        S_6={name = "6 of Spades",value = '6', suit = 'Spades', pos = {x=4,y=3}},
        S_7={name = "7 of Spades",value = '7', suit = 'Spades', pos = {x=5,y=3}},
        S_8={name = "8 of Spades",value = '8', suit = 'Spades', pos = {x=6,y=3}},
        S_9={name = "9 of Spades",value = '9', suit = 'Spades', pos = {x=7,y=3}},
        S_T={name = "10 of Spades",value = '10', suit = 'Spades', pos = {x=8,y=3}},
        S_J={name = "Jack of Spades",value = 'Jack', suit = 'Spades', pos = {x=9,y=3}},
        S_Q={name = "Queen of Spades",value = 'Queen', suit = 'Spades', pos = {x=10,y=3}},
        S_K={name = "King of Spades",value = 'King', suit = 'Spades', pos = {x=11,y=3}},
        S_A={name = "Ace of Spades",value = 'Ace', suit = 'Spades', pos = {x=12,y=3}},
    }

    self.j_locked = {unlocked = false, max = 1, name = "Locked", pos = {x=8,y=9}, set = "Joker", cost_mult = 1.0,config = {}}
    self.v_locked = {unlocked = false, max = 1, name = "Locked", pos = {x=8,y=3}, set = "Voucher", cost_mult = 1.0,config = {}}
    self.c_locked = {unlocked = false, max = 1, name = "Locked", pos = {x=4,y=2}, set = "Tarot", cost_mult = 1.0,config = {}}
    self.j_undiscovered = {unlocked = false, max = 1, name = "Locked", pos = {x=9,y=9}, set = "Joker", cost_mult = 1.0,config = {}}
    self.t_undiscovered = {unlocked = false, max = 1, name = "Locked", pos = {x=6,y=2}, set = "Tarot", cost_mult = 1.0,config = {}}
    self.p_undiscovered = {unlocked = false, max = 1, name = "Locked", pos = {x=7,y=2}, set = "Planet", cost_mult = 1.0,config = {}}
    self.s_undiscovered = {unlocked = false, max = 1, name = "Locked", pos = {x=5,y=2}, set = "Spectral", cost_mult = 1.0,config = {}}
    self.v_undiscovered = {unlocked = false, max = 1, name = "Locked", pos = {x=8,y=2}, set = "Voucher", cost_mult = 1.0,config = {}}
    self.booster_undiscovered = {unlocked = false, max = 1, name = "Locked", pos = {x=0,y=5}, set = "Booster", cost_mult = 1.0,config = {}}

    self.P_CENTERS = {
        c_base={max = 500, freq = 1, line = 'base', name = "Default Base", pos = {x=1,y=0}, set = "Default", label = 'Base Card', effect = "Base", cost_mult = 1.0, config = {}},

        --Jokers
        j_joker=            {order = 1,  unlocked = true,   start_alerted = true, discovered = true,  blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 1, cost = 2, name = "Joker", pos = {x=0,y=0}, set = "Joker", effect = "Mult", cost_mult = 1.0, config = {mult = 4}},
        j_greedy_joker=     {order = 2,  unlocked = true,   discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 1, cost = 5, name = "Greedy Joker", pos = {x=6,y=1}, set = "Joker", effect = "Suit Mult", cost_mult = 1.0, config = {extra = {s_mult = 3, suit = 'Diamonds'}}},
        j_lusty_joker=      {order = 3,  unlocked = true,   discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 1, cost = 5, name = "Lusty Joker", pos = {x=7,y=1}, set = "Joker", effect = "Suit Mult", cost_mult = 1.0, config = {extra = {s_mult = 3, suit = 'Hearts'}}},
        j_wrathful_joker=   {order = 4,  unlocked = true,   discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 1, cost = 5, name = "Wrathful Joker", pos = {x=8,y=1}, set = "Joker", effect = "Suit Mult", cost_mult = 1.0, config = {extra = {s_mult = 3, suit = 'Spades'}}},
        j_gluttenous_joker= {order = 5,  unlocked = true,   discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 1, cost = 5, name = "Gluttonous Joker", pos = {x=9,y=1}, set = "Joker", effect = "Suit Mult", cost_mult = 1.0, config = {extra = {s_mult = 3, suit = 'Clubs'}}},
        j_jolly=            {order = 6,  unlocked = true,   discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 1, cost = 3, name = "Jolly Joker", pos = {x=2,y=0}, set = "Joker", effect = "Type Mult", cost_mult = 1.0, config = {t_mult = 8, type = 'Pair'}},
        j_zany=             {order = 7,  unlocked = true,   discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 1, cost = 4, name = "Zany Joker", pos = {x=3,y=0}, set = "Joker", effect = "Type Mult", cost_mult = 1.0, config = {t_mult = 12, type = 'Three of a Kind'}},
        j_mad=              {order = 8,  unlocked = true,   discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 1, cost = 4, name = "Mad Joker", pos = {x=4,y=0}, set = "Joker", effect = "Type Mult", cost_mult = 1.0, config = {t_mult = 10, type = 'Two Pair'}},
        j_crazy=            {order = 9,  unlocked = true,   discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 1, cost = 4, name = "Crazy Joker", pos = {x=5,y=0}, set = "Joker", effect = "Type Mult", cost_mult = 1.0, config = {t_mult = 12, type = 'Straight'}},
        j_droll=            {order = 10,  unlocked = true,  discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 1, cost = 4, name = "Droll Joker", pos = {x=6,y=0}, set = "Joker", effect = "Type Mult", cost_mult = 1.0, config = {t_mult = 10, type = 'Flush'}},
        j_sly=              {order = 11,  unlocked = true,  discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 1, cost = 3, name = "Sly Joker",set = "Joker", config = {t_chips = 50, type = 'Pair'}, pos = {x=0,y=14}},
        j_wily=             {order = 12,  unlocked = true,  discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 1, cost = 4, name = "Wily Joker",set = "Joker", config = {t_chips = 100, type = 'Three of a Kind'}, pos = {x=1,y=14}},
        j_clever=           {order = 13,  unlocked = true,  discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 1, cost = 4, name = "Clever Joker",set = "Joker", config = {t_chips = 80, type = 'Two Pair'}, pos = {x=2,y=14}},
        j_devious=          {order = 14,  unlocked = true,  discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 1, cost = 4, name = "Devious Joker",set = "Joker", config = {t_chips = 100, type = 'Straight'}, pos = {x=3,y=14}},
        j_crafty=           {order = 15,  unlocked = true,  discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 1, cost = 4, name = "Crafty Joker",set = "Joker", config = {t_chips = 80, type = 'Flush'}, pos = {x=4,y=14}},

        j_half=             {order = 16,  unlocked = true,   discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 1, cost = 5, name = "Half Joker", pos = {x=7,y=0}, set = "Joker", effect = "Hand Size Mult", cost_mult = 1.0, config = {extra = {mult = 20, size = 3}}},
        j_stencil=          {order = 17,  unlocked = true,  discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 2, cost = 8, name = "Joker Stencil", pos = {x=2,y=5}, set = "Joker", effect = "Hand Size Mult", cost_mult = 1.0, config = {}},
        j_four_fingers=     {order = 18,  unlocked = true,  discovered = false, blueprint_compat = false, perishable_compat = true, eternal_compat = true, rarity = 2, cost = 7, name = "Four Fingers", pos = {x=6,y=6}, set = "Joker", effect = "", config = {}},
        j_mime=             {order = 19,  unlocked = true,  discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 2, cost = 5, name = "Mime", pos = {x=4,y=1}, set = "Joker", effect = "Hand card double", cost_mult = 1.0, config = {extra = 1}},
        j_credit_card=      {order = 20,  unlocked = true,  discovered = false, blueprint_compat = false, perishable_compat = true, eternal_compat = true, rarity = 1, cost = 1, name = "Credit Card", pos = {x=5,y=1}, set = "Joker", effect = "Credit", cost_mult = 1.0, config = {extra = 20}},
        j_ceremonial=       {order = 21,  unlocked = true,  discovered = false, blueprint_compat = true, perishable_compat = false, eternal_compat = true, rarity = 2, cost = 6, name = "Ceremonial Dagger", pos = {x=5,y=5}, set = "Joker", effect = "", config = {mult = 0}},
        j_banner=           {order = 22,  unlocked = true,  discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 1, cost = 5, name = "Banner", pos = {x=1,y=2}, set = "Joker", effect = "Discard Chips", cost_mult = 1.0, config = {extra = 30}},
        j_mystic_summit=    {order = 23,  unlocked = true,  discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 1, cost = 5, name = "Mystic Summit", pos = {x=2,y=2}, set = "Joker", effect = "No Discard Mult", cost_mult = 1.0, config = {extra = {mult = 15, d_remaining = 0}}},
        j_marble=           {order = 24,  unlocked = true,  discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 2, cost = 6, name = "Marble Joker", pos = {x=3,y=2}, set = "Joker", effect = "Stone card hands", cost_mult = 1.0, config = {extra = 1}},
        j_loyalty_card=     {order = 25,  unlocked = true,  discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 2, cost = 5, name = "Loyalty Card", pos = {x=4,y=2}, set = "Joker", effect = "1 in 10 mult", cost_mult = 1.0, config = {extra = {Xmult = 4, every = 5, remaining = "5 remaining"}}},
        j_8_ball=           {order = 26,  unlocked = true,  discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 1, cost = 5, name = "8 Ball", pos = {x=0,y=5}, set = "Joker", effect = "Spawn Tarot", cost_mult = 1.0, config = {extra=4}},
        j_misprint=         {order = 27,  unlocked = true,  discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 1, cost = 4, name = "Misprint", pos = {x=6,y=2}, set = "Joker", effect = "Random Mult", cost_mult = 1.0, config = {extra = {max = 23, min = 0}}},
        j_dusk=             {order = 28,  unlocked = true,  discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 2, cost = 5, name = "Dusk", pos = {x=4,y=7}, set = "Joker", effect = "", config = {extra = 1}, unlock_condition = {type = '', extra = '', hidden = true}},
        j_raised_fist=      {order = 29,  unlocked = true,  discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 1, cost = 5, name = "Raised Fist", pos = {x=8,y=2}, set = "Joker", effect = "Socialized Mult", cost_mult = 1.0, config = {}},
        j_chaos=            {order = 30,  unlocked = true,  discovered = false, blueprint_compat = false, perishable_compat = true, eternal_compat = true, rarity = 1, cost = 4, name = "Chaos the Clown", pos = {x=1,y=0}, set = "Joker", effect = "Bonus Rerolls", cost_mult = 1.0, config = {extra = 1}},
        
        j_fibonacci=        {order = 31,  unlocked = true,  discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 2, cost = 8, name = "Fibonacci", pos = {x=1,y=5}, set = "Joker", effect = "Card Mult", cost_mult = 1.0, config = {extra = 8}},
        j_steel_joker=      {order = 32,  unlocked = true,  discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 2, cost = 7, name = "Steel Joker", pos = {x=7,y=2}, set = "Joker", effect = "Steel Card Buff", cost_mult = 1.0, config = {extra = 0.2}, enhancement_gate = 'm_steel'},
        j_scary_face=       {order = 33,  unlocked = true,  discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 1, cost = 4, name = "Scary Face", pos = {x=2,y=3}, set = "Joker", effect = "Scary Face Cards", cost_mult = 1.0, config = {extra = 30}},
        j_abstract=         {order = 34,  unlocked = true,  discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 1, cost = 4, name = "Abstract Joker", pos = {x=3,y=3}, set = "Joker", effect = "Joker Mult", cost_mult = 1.0, config = {extra = 3}},
        j_delayed_grat=     {order = 35,  unlocked = true,  discovered = false, blueprint_compat = false, perishable_compat = true, eternal_compat = true, rarity = 1, cost = 4, name = "Delayed Gratification", pos = {x=4,y=3}, set = "Joker", effect = "Discard dollars", cost_mult = 1.0, config = {extra = 2}},
        j_hack=             {order = 36,  unlocked = true,  discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 2, cost = 6, name = "Hack", pos = {x=5,y=2}, set = "Joker", effect = "Low Card double", cost_mult = 1.0, config = {extra = 1}},
        j_pareidolia=       {order = 37,  unlocked = true,  discovered = false, blueprint_compat = false, perishable_compat = true, eternal_compat = true, rarity = 2, cost = 5, name = "Pareidolia", pos = {x=6,y=3}, set = "Joker", effect = "All face cards", cost_mult = 1.0, config = {}},
        j_gros_michel=      {order = 38,  unlocked = true,  discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = false, rarity = 1, cost = 5, name = "Gros Michel", pos = {x=7,y=6}, set = "Joker", effect = "", config = {extra = {odds = 6, mult = 15}}, no_pool_flag = 'gros_michel_extinct'},
        j_even_steven=      {order = 39,  unlocked = true,  discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 1, cost = 4, name = "Even Steven", pos = {x=8,y=3}, set = "Joker", effect = "Even Card Buff", cost_mult = 1.0, config = {extra = 4}},
        j_odd_todd=         {order = 40,  unlocked = true,  discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 1, cost = 4, name = "Odd Todd", pos = {x=9,y=3}, set = "Joker", effect = "Odd Card Buff", cost_mult = 1.0, config = {extra = 31}},
        j_scholar=          {order = 41,  unlocked = true,  discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 1, cost = 4, name = "Scholar", pos = {x=0,y=4}, set = "Joker", effect = "Ace Buff", cost_mult = 1.0, config = {extra = {mult = 4, chips = 20}}},
        j_business=         {order = 42,  unlocked = true,  discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 1, cost = 4, name = "Business Card", pos = {x=1,y=4}, set = "Joker", effect = "Face Card dollar Chance", cost_mult = 1.0, config = {extra = 2}},
        j_supernova=        {order = 43,  unlocked = true,  discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 1, cost = 5, name = "Supernova", pos = {x=2,y=4}, set = "Joker", effect = "Hand played mult", cost_mult = 1.0, config = {extra = 1}},
        j_ride_the_bus=     {order = 44,  unlocked = true,  discovered = false, blueprint_compat = true, perishable_compat = false, eternal_compat = true, rarity = 1, cost = 6, name = "Ride the Bus", pos = {x=1,y=6}, set = "Joker", effect = "", config = {extra = 1}, unlock_condition = {type = 'discard_custom'}},
        j_space=            {order = 45,  unlocked = true,  discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 2, cost = 5, name = "Space Joker", pos = {x=3,y=5}, set = "Joker", effect = "Upgrade Hand chance", cost_mult = 1.0, config = {extra = 4}},
        
        j_egg=              {order = 46,  unlocked = true,  discovered = false, blueprint_compat = false, perishable_compat = true, eternal_compat = true, rarity = 1, cost = 4, name = 'Egg', pos = {x = 0, y = 10}, set = 'Joker', config = {extra = 3}},
        j_burglar=          {order = 47,  unlocked = true,  discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 2, cost = 6, name = 'Burglar', pos = {x = 1, y = 10}, set = 'Joker', config = {extra = 3}},
        j_blackboard=       {order = 48,  unlocked = true,  discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 2, cost = 6, name = 'Blackboard', pos = {x = 2, y = 10}, set = 'Joker', config = {extra = 3}},
        j_runner=           {order = 49,  unlocked = true,  discovered = false, blueprint_compat = true, perishable_compat = false, eternal_compat = true, rarity = 1, cost = 5, name = 'Runner', pos = {x = 3, y = 10}, set = 'Joker', config = {extra = {chips = 0, chip_mod = 15}}},
        j_ice_cream=        {order = 50,  unlocked = true,  discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = false, rarity = 1, cost = 5, name = 'Ice Cream', pos = {x = 4, y = 10}, set = 'Joker', config = {extra = {chips = 100, chip_mod = 5}}},
        j_dna=              {order = 51,  unlocked = true,  discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 3, cost = 8, name = 'DNA', pos = {x = 5, y = 10}, set = 'Joker', config = {}},
        j_splash=           {order = 52,  unlocked = true,  discovered = false, blueprint_compat = false, perishable_compat = true, eternal_compat = true, rarity = 1, cost = 3, name = 'Splash', pos = {x = 6, y = 10}, set = 'Joker', config = {}},
        j_blue_joker=       {order = 53,  unlocked = true,  discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 1, cost = 5, name = 'Blue Joker', pos = {x = 7, y = 10}, set = 'Joker', config = {extra = 2}},
        j_sixth_sense=      {order = 54,  unlocked = true,  discovered = false, blueprint_compat = false, perishable_compat = true, eternal_compat = true, rarity = 2, cost = 6, name = 'Sixth Sense', pos = {x = 8, y = 10}, set = 'Joker', config = {}},
        j_constellation=    {order = 55,  unlocked = true,  discovered = false, blueprint_compat = true, perishable_compat = false, eternal_compat = true, rarity = 2, cost = 6, name = 'Constellation', pos = {x = 9, y = 10}, set = 'Joker', config = {extra = 0.1, Xmult = 1}},
        j_hiker=            {order = 56,  unlocked = true,  discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 2, cost = 5, name = 'Hiker', pos = {x = 0, y = 11}, set = 'Joker', config = {extra = 5}},
        j_faceless=         {order = 57,  unlocked = true,  discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 1, cost = 4, name = 'Faceless Joker', pos = {x = 1, y = 11}, set = 'Joker', config = {extra = {dollars = 5, faces = 3}}},
        j_green_joker=      {order = 58,  unlocked = true,  discovered = false, blueprint_compat = true, perishable_compat = false, eternal_compat = true, rarity = 1, cost = 4, name = 'Green Joker', pos = {x = 2, y = 11}, set = 'Joker', config = {extra = {hand_add = 1, discard_sub = 1}}},
        j_superposition=    {order = 59,  unlocked = true,  discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 1, cost = 4, name = 'Superposition', pos = {x = 3, y = 11}, set = 'Joker', config = {}},
        j_todo_list=        {order = 60,  unlocked = true,  discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 1, cost = 4, name = 'To Do List', pos = {x = 4, y = 11}, set = 'Joker', config = {extra = {dollars = 4, poker_hand = 'High Card'}}},

        j_cavendish=        {order = 61,  unlocked = true, discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = false, rarity = 1, cost = 4, name = "Cavendish", pos = {x=5,y=11}, set = "Joker", cost_mult = 1.0, config = {extra = {odds = 1000, Xmult = 3}}, yes_pool_flag = 'gros_michel_extinct'},
        j_card_sharp=       {order = 62,  unlocked = true, discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 2, cost = 6, name = "Card Sharp", pos = {x=6,y=11}, set = "Joker", cost_mult = 1.0, config = {extra = {Xmult = 3}}},
        j_red_card=         {order = 63,  unlocked = true, discovered = false, blueprint_compat = true, perishable_compat = false, eternal_compat = true, rarity = 1, cost = 5, name = "Red Card", pos = {x=7,y=11}, set = "Joker", cost_mult = 1.0, config = {extra = 3}},
        j_madness=          {order = 64,  unlocked = true, discovered = false, blueprint_compat = true, perishable_compat = false, eternal_compat = true, rarity = 2, cost = 7, name = "Madness", pos = {x=8,y=11}, set = "Joker", cost_mult = 1.0, config = {extra = 0.5}},
        j_square=           {order = 65,  unlocked = true, discovered = false, blueprint_compat = true, perishable_compat = false, eternal_compat = true, rarity = 1, cost = 4, name = "Square Joker", pos = {x=9,y=11}, set = "Joker", cost_mult = 1.0, config = {extra = {chips = 0, chip_mod = 4}}},
        j_seance=           {order = 66,  unlocked = true, discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 2, cost = 6, name = "Seance", pos = {x=0,y=12}, set = "Joker", cost_mult = 1.0, config = {extra = {poker_hand = 'Straight Flush'}}},
        j_riff_raff=        {order = 67,  unlocked = true, discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 1, cost = 6, name = "Riff-raff", pos = {x=1,y=12}, set = "Joker", cost_mult = 1.0, config = {extra = 2}},
        j_vampire=          {order = 68,  unlocked = true, discovered = false, blueprint_compat = true, perishable_compat = false, eternal_compat = true, rarity = 2, cost = 7, name = "Vampire",set = "Joker", config = {extra = 0.1, Xmult = 1},  pos = {x=2,y=12}},
        j_shortcut=         {order = 69,  unlocked = true, discovered = false, blueprint_compat = false, perishable_compat = true, eternal_compat = true, rarity = 2, cost = 7, name = "Shortcut",set = "Joker", config = {},  pos = {x=3,y=12}},
        j_hologram=         {order = 70,  unlocked = true, discovered = false, blueprint_compat = true, perishable_compat = false, eternal_compat = true, rarity = 2, cost = 7, name = "Hologram",set = "Joker", config = {extra = 0.25, Xmult = 1},  pos = {x=4,y=12}, soul_pos = {x=2, y=9},},
        j_vagabond=         {order = 71,  unlocked = true, discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 3, cost = 8, name = "Vagabond",set = "Joker", config = {extra = 4}, pos = {x=5,y=12}},
        j_baron=            {order = 72,  unlocked = true, discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 3, cost = 8, name = "Baron",set = "Joker", config = {extra = 1.5}, pos = {x=6,y=12}},
        j_cloud_9=          {order = 73,  unlocked = true, discovered = false, blueprint_compat = false, perishable_compat = true, eternal_compat = true, rarity = 2, cost = 7, name = "Cloud 9",set = "Joker", config = {extra = 1}, pos = {x=7,y=12}},
        j_rocket=           {order = 74,  unlocked = true, discovered = false, blueprint_compat = false, perishable_compat = false, eternal_compat = true, rarity = 2, cost = 6, name = "Rocket",set = "Joker", config = {extra = {dollars = 1, increase = 2}}, pos = {x=8,y=12}},
        j_obelisk=          {order = 75,  unlocked = true, discovered = false, blueprint_compat = true, perishable_compat = false, eternal_compat = true, rarity = 3, cost = 8, name = "Obelisk",set = "Joker", config = {extra = 0.2, Xmult = 1}, pos = {x=9,y=12}},

        j_midas_mask=       {order = 76,  unlocked = true,  discovered = false, blueprint_compat = false, perishable_compat = true, eternal_compat = true, rarity = 2, cost = 7, name = "Midas Mask",set = "Joker", config = {}, pos = {x=0,y=13}},
        j_luchador=         {order = 77,  unlocked = true,  discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = false, rarity = 2, cost = 5, name = "Luchador",set = "Joker", config = {}, pos = {x=1,y=13}},
        j_photograph=       {order = 78,  unlocked = true,  discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 1, cost = 5, name = "Photograph",set = "Joker", config = {extra = 2}, pos = {x=2,y=13}},
        j_gift=             {order = 79,  unlocked = true,  discovered = false, blueprint_compat = false, perishable_compat = true, eternal_compat = true, rarity = 2, cost = 6, name = "Gift Card",set = "Joker", config = {extra = 1}, pos = {x=3,y=13}},
        j_turtle_bean=      {order = 80,  unlocked = true,  discovered = false, blueprint_compat = false, perishable_compat = true, eternal_compat = false, rarity = 2, cost = 6, name = "Turtle Bean",set = "Joker", config = {extra = {h_size = 5, h_mod = 1}}, pos = {x=4,y=13}},
        j_erosion=          {order = 81,  unlocked = true,  discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 2, cost = 6, name = "Erosion",set = "Joker", config = {extra = 4}, pos = {x=5,y=13}},
        j_reserved_parking= {order = 82,  unlocked = true,  discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 1, cost = 6, name = "Reserved Parking",set = "Joker", config = {extra = {odds = 2, dollars = 1}}, pos = {x=6,y=13}},
        j_mail=             {order = 83,  unlocked = true,  discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 1, cost = 4, name = "Mail-In Rebate",set = "Joker", config = {extra = 5}, pos = {x=7,y=13}},
        j_to_the_moon=      {order = 84,  unlocked = true,  discovered = false, blueprint_compat = false, perishable_compat = true, eternal_compat = true, rarity = 2, cost = 5, name = "To the Moon",set = "Joker", config = {extra = 1}, pos = {x=8,y=13}},
        j_hallucination=    {order = 85,  unlocked = true,  discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 1, cost = 4, name = "Hallucination",set = "Joker", config = {extra = 2}, pos = {x=9,y=13}},
        j_fortune_teller=   {order = 86,  unlocked = true,  discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 1, cost = 6, name = "Fortune Teller", pos = {x=7,y=5}, set = "Joker", effect = "", config = {extra = 1}},
        j_juggler=          {order = 87,  unlocked = true,  discovered = false, blueprint_compat = false, perishable_compat = true, eternal_compat = true, rarity = 1, cost = 4, name = "Juggler", pos = {x=0,y=1}, set = "Joker", effect = "Hand Size", cost_mult = 1.0, config = {h_size = 1}},
        j_drunkard=         {order = 88,  unlocked = true,  discovered = false, blueprint_compat = false, perishable_compat = true, eternal_compat = true, rarity = 1, cost = 4, name = "Drunkard", pos = {x=1,y=1}, set = "Joker", effect = "Discard Size", cost_mult = 1.0, config = {d_size = 1}},
        j_stone=            {order = 89,  unlocked = true,  discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 2, cost = 6, name = "Stone Joker", pos = {x=9,y=0}, set = "Joker", effect = "Stone Card Buff", cost_mult = 1.0, config = {extra = 25}, enhancement_gate = 'm_stone'},
        j_golden=           {order = 90,  unlocked = true,  discovered = false, blueprint_compat = false, perishable_compat = true, eternal_compat = true, rarity = 1, cost = 6, name = "Golden Joker", pos = {x=9,y=2}, set = "Joker", effect = "Bonus dollars", cost_mult = 1.0, config = {extra = 4}},

        j_lucky_cat=        {order = 91,   unlocked = true, discovered = false, blueprint_compat = true, perishable_compat = false, eternal_compat = true, rarity = 2, cost = 6, name = "Lucky Cat",set = "Joker", config = {Xmult = 1, extra = 0.25}, pos = {x=5,y=14}, enhancement_gate = 'm_lucky'},
        j_baseball=         {order = 92,   unlocked = true, discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 3, cost = 8, name = "Baseball Card",set = "Joker", config = {extra = 1.5}, pos = {x=6,y=14}},
        j_bull=             {order = 93,   unlocked = true, discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 2, cost = 6, name = "Bull",set = "Joker", config = {extra = 2}, pos = {x=7,y=14}},
        j_diet_cola=        {order = 94,   unlocked = true, discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = false, rarity = 2, cost = 6, name = "Diet Cola",set = "Joker", config = {}, pos = {x=8,y=14}},
        j_trading=          {order = 95,   unlocked = true, discovered = false, blueprint_compat = false, perishable_compat = true, eternal_compat = true, rarity = 2, cost = 6, name = "Trading Card",set = "Joker", config = {extra = 3}, pos = {x=9,y=14}},
        j_flash=            {order = 96,   unlocked = true, discovered = false, blueprint_compat = true, perishable_compat = false, eternal_compat = true, rarity = 2, cost = 5, name = "Flash Card",set = "Joker", config = {extra = 2, mult = 0}, pos = {x=0,y=15}},
        j_popcorn=          {order = 97,   unlocked = true, discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = false, rarity = 1, cost = 5, name = "Popcorn",set = "Joker", config = {mult = 20, extra = 4}, pos = {x=1,y=15}},
        j_trousers=         {order = 98,   unlocked = true, discovered = false, blueprint_compat = true, perishable_compat = false, eternal_compat = true, rarity = 2, cost = 6, name = "Spare Trousers",set = "Joker", config = {extra = 2}, pos = {x=4,y=15}},
        j_ancient=          {order = 99,   unlocked = true, discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 3, cost = 8, name = "Ancient Joker",set = "Joker", config = {extra = 1.5}, pos = {x=7,y=15}},
        j_ramen=            {order = 100,  unlocked = true, discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = false, rarity = 2, cost = 6, name = "Ramen",set = "Joker", config = {Xmult = 2, extra = 0.01}, pos = {x=2,y=15}},
        j_walkie_talkie=    {order = 101,  unlocked = true, discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 1, cost = 4, name = "Walkie Talkie",set = "Joker", config = {extra = {chips = 10, mult = 4}}, pos = {x=8,y=15}},
        j_selzer=           {order = 102,  unlocked = true, discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = false, rarity = 2, cost = 6, name = "Seltzer",set = "Joker", config = {extra = 10}, pos = {x=3,y=15}},
        j_castle=           {order = 103,  unlocked = true, discovered = false, blueprint_compat = true, perishable_compat = false, eternal_compat = true, rarity = 2, cost = 6, name = "Castle",set = "Joker", config = {extra = {chips = 0, chip_mod = 3}}, pos = {x=9,y=15}},
        j_smiley=           {order = 104,  unlocked = true, discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 1, cost = 4, name = "Smiley Face",set = "Joker", config = {extra = 5}, pos = {x=6,y=15}},
        j_campfire=         {order = 105,  unlocked = true, discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 3, cost = 9, name = "Campfire",set = "Joker", config = {extra = 0.25}, pos = {x=5,y=15}},

        j_ticket=           {order = 106,  unlocked = false, discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 1, cost = 5, name = "Golden Ticket", pos = {x=5,y=3}, set = "Joker", effect = "dollars for Gold cards", cost_mult = 1.0, config = {extra = 4},unlock_condition = {type = 'hand_contents', extra = 'Gold'}, enhancement_gate = 'm_gold'},
        j_mr_bones=         {order = 107,  unlocked = false, discovered = false, blueprint_compat = false, perishable_compat = true, eternal_compat = false, rarity = 2, cost = 5, name = "Mr. Bones", pos = {x=3,y=4}, set = "Joker", effect = "Prevent Death", cost_mult = 1.0, config = {},unlock_condition = {type = 'c_losses', extra = 5}},
        j_acrobat=          {order = 108,  unlocked = false, discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 2, cost = 6, name = "Acrobat", pos = {x=2,y=1}, set = "Joker", effect = "Shop size", cost_mult = 1.0, config = {extra = 3},unlock_condition = {type = 'c_hands_played', extra = 200}},
        j_sock_and_buskin=  {order = 109,  unlocked = false, discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 2, cost = 6, name = "Sock and Buskin", pos = {x=3,y=1}, set = "Joker", effect = "Face card double", cost_mult = 1.0, config = {extra = 1},unlock_condition = {type = 'c_face_cards_played', extra = 300}},
        j_swashbuckler=     {order = 110,  unlocked = false, discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 1, cost = 4, name = "Swashbuckler", pos = {x=9,y=5}, set = "Joker", effect = "Set Mult", cost_mult = 1.0, config = {mult = 1},unlock_condition = {type = 'c_jokers_sold', extra = 20}},
        j_troubadour=       {order = 111,  unlocked = false, discovered = false, blueprint_compat = false, perishable_compat = true, eternal_compat = true, rarity = 2, cost = 6, name = "Troubadour", pos = {x=0,y=2}, set = "Joker", effect = "Hand Size, Plays", cost_mult = 1.0, config = {extra = {h_size = 2, h_plays = -1}}, unlock_condition = {type = 'round_win', extra = 5}},
        j_certificate=      {order = 112,  unlocked = false, discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 2, cost = 6, name = "Certificate", pos = {x=8,y=8}, set = "Joker", effect = "", config = {}, unlock_condition = {type = 'double_gold'}},
        j_smeared=          {order = 113,  unlocked = false, discovered = false, blueprint_compat = false, perishable_compat = true, eternal_compat = true, rarity = 2, cost = 7, name = "Smeared Joker", pos = {x=4,y=6}, set = "Joker", effect = "", config = {}, unlock_condition = {type = 'modify_deck', extra = {count = 3, enhancement = 'Wild Card', e_key = 'm_wild'}}},
        j_throwback=        {order = 114,  unlocked = false, discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 2, cost = 6, name = "Throwback", pos = {x=5,y=7}, set = "Joker", effect = "", config = {extra = 0.25}, unlock_condition = {type = 'continue_game'}},        
        j_hanging_chad=     {order = 115,  unlocked = false, discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 1, cost = 4, name = "Hanging Chad", pos = {x=9,y=6}, set = "Joker", effect = "", config = {extra = 2}, unlock_condition = {type = 'round_win', extra = 'High Card'}},
        j_rough_gem=        {order = 116,  unlocked = false, discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 2, cost = 7, name = "Rough Gem", pos = {x=9,y=7}, set = "Joker", effect = "", config = {extra = 1}, unlock_condition = {type = 'modify_deck', extra = {count = 30, suit = 'Diamonds'}}},
        j_bloodstone=       {order = 117,  unlocked = false, discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 2, cost = 7, name = "Bloodstone", pos = {x=0,y=8}, set = "Joker", effect = "", config = {extra = {odds = 2, Xmult = 1.5}}, unlock_condition = {type = 'modify_deck', extra = {count = 30, suit = 'Hearts'}}},
        j_arrowhead=        {order = 118,  unlocked = false, discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 2, cost = 7, name = "Arrowhead", pos = {x=1,y=8}, set = "Joker", effect = "", config = {extra = 50}, unlock_condition = {type = 'modify_deck', extra = {count = 30, suit = 'Spades'}}},
        j_onyx_agate=       {order = 119,  unlocked = false, discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 2, cost = 7, name = "Onyx Agate", pos = {x=2,y=8}, set = "Joker", effect = "", config = {extra = 7}, unlock_condition = {type = 'modify_deck', extra = {count = 30, suit = 'Clubs'}}},
        j_glass=            {order = 120,  unlocked = false, discovered = false, blueprint_compat = true, perishable_compat = false, eternal_compat = true, rarity = 2, cost = 6, name = "Glass Joker", pos = {x=1,y=3}, set = "Joker", effect = "Glass Card", cost_mult = 1.0, config = {extra = 0.75, Xmult = 1}, unlock_condition = {type = 'modify_deck', extra = {count = 5, enhancement = 'Glass Card', e_key = 'm_glass'}}, enhancement_gate = 'm_glass'},

        j_ring_master=      {order = 121,  unlocked = false, discovered = false, blueprint_compat = false, perishable_compat = true, eternal_compat = true, rarity = 2, cost = 5, name = "Showman", pos = {x=6,y=5}, set = "Joker", effect = "", config = {}, unlock_condition = {type = 'ante_up', ante = 4}},
        j_flower_pot=       {order = 122,  unlocked = false, discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 2, cost = 6, name = "Flower Pot", pos = {x=0,y=6}, set = "Joker", effect = "", config = {extra = 3}, unlock_condition = {type = 'ante_up', ante = 8}},
        j_blueprint=        {order = 123,  unlocked = false, discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 3, cost = 10,name = "Blueprint", pos = {x=0,y=3}, set = "Joker", effect = "Copycat", cost_mult = 1.0, config = {},unlock_condition = {type = 'win_custom'}},
        j_wee=              {order = 124,  unlocked = false, discovered = false, blueprint_compat = true, perishable_compat = false, eternal_compat = true, rarity = 3, cost = 8, name = "Wee Joker", pos = {x=0,y=0}, set = "Joker", effect = "", config = {extra = {chips = 0, chip_mod = 8}}, unlock_condition = {type = 'win', n_rounds = 18}},
        j_merry_andy=       {order = 125,  unlocked = false, discovered = false, blueprint_compat = false, perishable_compat = true, eternal_compat = true, rarity = 2, cost = 7, name = "Merry Andy", pos = {x=8,y=0}, set = "Joker", effect = "", cost_mult = 1.0, config = {d_size = 3, h_size = -1}, unlock_condition = {type = 'win', n_rounds = 12}},
        j_oops=             {order = 126,  unlocked = false, discovered = false, blueprint_compat = false, perishable_compat = true, eternal_compat = true, rarity = 2, cost = 4, name = "Oops! All 6s", pos = {x=5,y=6}, set = "Joker", effect = "", config = {}, unlock_condition = {type = 'chip_score', chips = 10000}},
        j_idol=             {order = 127,  unlocked = false, discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 2, cost = 6, name = "The Idol", pos = {x=6,y=7}, set = "Joker", effect = "", config = {extra = 2}, unlock_condition = {type = 'chip_score', chips = 1000000}},
        j_seeing_double=    {order = 128,  unlocked = false, discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 2, cost = 6, name = "Seeing Double", pos = {x=4,y=4}, set = "Joker", effect = "X1.5 Mult club 7", cost_mult = 1.0, config = {extra = 2},unlock_condition = {type = 'hand_contents', extra = 'four 7 of Clubs'}},
        j_matador=          {order = 129,  unlocked = false, discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 2, cost = 7, name = "Matador", pos = {x=4,y=5}, set = "Joker", effect = "", config = {extra = 8}, unlock_condition = {type = 'round_win'}},
        j_hit_the_road=     {order = 130,  unlocked = false, discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 3, cost = 8, name = "Hit the Road", pos = {x=8,y=5}, set = "Joker", effect = "Jack Discard Effect", cost_mult = 1.0, config = {extra = 0.5}, unlock_condition = {type = 'discard_custom'}},
        j_duo=              {order = 131,  unlocked = false, discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 3, cost = 8, name = "The Duo", pos = {x=5,y=4}, set = "Joker", effect = "X1.5 Mult", cost_mult = 1.0, config = {Xmult = 2, type = 'Pair'}, unlock_condition = {type = 'win_no_hand', extra = 'Pair'}},
        j_trio=             {order = 132,  unlocked = false, discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 3, cost = 8, name = "The Trio", pos = {x=6,y=4}, set = "Joker", effect = "X2 Mult", cost_mult = 1.0, config = {Xmult = 3, type = 'Three of a Kind'}, unlock_condition = {type = 'win_no_hand', extra = 'Three of a Kind'}},
        j_family=           {order = 133,  unlocked = false, discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 3, cost = 8, name = "The Family", pos = {x=7,y=4}, set = "Joker", effect = "X3 Mult", cost_mult = 1.0, config = {Xmult = 4, type = 'Four of a Kind'}, unlock_condition = {type = 'win_no_hand', extra = 'Four of a Kind'}},
        j_order=            {order = 134,  unlocked = false, discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 3, cost = 8, name = "The Order", pos = {x=8,y=4}, set = "Joker", effect = "X3 Mult", cost_mult = 1.0, config = {Xmult = 3, type = 'Straight'}, unlock_condition = {type = 'win_no_hand', extra = 'Straight'}},
        j_tribe=            {order = 135,  unlocked = false, discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 3, cost = 8, name = "The Tribe", pos = {x=9,y=4}, set = "Joker", effect = "X3 Mult", cost_mult = 1.0, config = {Xmult = 2, type = 'Flush'}, unlock_condition = {type = 'win_no_hand', extra = 'Flush'}},
        
        j_stuntman=         {order = 136,  unlocked = false, discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 3, cost = 7, name = "Stuntman", pos = {x=8,y=6}, set = "Joker", effect = "", config = {extra = {h_size = 2, chip_mod = 250}}, unlock_condition = {type = 'chip_score', chips = 100000000}},
        j_invisible=        {order = 137,  unlocked = false, discovered = false, blueprint_compat = false, perishable_compat = true, eternal_compat = false, rarity = 3, cost = 8, name = "Invisible Joker", pos = {x=1,y=7}, set = "Joker", effect = "", config = {extra = 2}, unlock_condition = {type = 'win_custom'}},
        j_brainstorm=       {order = 138,  unlocked = false, discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 3, cost = 10, name = "Brainstorm", pos = {x=7,y=7}, set = "Joker", effect = "Copycat", config = {}, unlock_condition = {type = 'discard_custom'}},
        j_satellite=        {order = 139,  unlocked = false, discovered = false, blueprint_compat = false, perishable_compat = true, eternal_compat = true, rarity = 2, cost = 6, name = "Satellite", pos = {x=8,y=7}, set = "Joker", effect = "", config = {extra = 1}, unlock_condition = {type = 'money', extra = 400}},
        j_shoot_the_moon=   {order = 140,  unlocked = false, discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 1, cost = 5, name = "Shoot the Moon", pos = {x=2,y=6}, set = "Joker", effect = "", config = {extra = 13}, unlock_condition = {type = 'play_all_hearts'}},
        j_drivers_license=  {order = 141,  unlocked = false, discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 3, cost = 7, name = "Driver's License", pos = {x=0,y=7}, set = "Joker", effect = "", config = {extra = 3}, unlock_condition = {type = 'modify_deck', extra = {count = 16, tally = 'total'}}},
        j_cartomancer=      {order = 142,  unlocked = false, discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 2, cost = 6, name = "Cartomancer", pos = {x=7,y=3}, set = "Joker", effect = "Tarot Buff", cost_mult = 1.0, config = {}, unlock_condition = {type = 'discover_amount', tarot_count = 22}},
        j_astronomer=       {order = 143,  unlocked = false, discovered = false, blueprint_compat = false, perishable_compat = true, eternal_compat = true, rarity = 2, cost = 8, name = "Astronomer", pos = {x=2,y=7}, set = "Joker", effect = "", config = {}, unlock_condition = {type = 'discover_amount', planet_count = 12}},
        j_burnt=            {order = 144,  unlocked = false, discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 3, cost = 8, name = "Burnt Joker", pos = {x=3,y=7}, set = "Joker", effect = "", config = {h_size = 0, extra = 4}, unlock_condition = {type = 'c_cards_sold', extra = 50}},
        j_bootstraps=       {order = 145,  unlocked = false, discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 2, cost = 7, name = "Bootstraps", pos = {x=9,y=8}, set = "Joker", effect = "", config = {extra = {mult = 2, dollars = 5}}, unlock_condition = {type = 'modify_jokers', extra = {polychrome = true, count = 2}}},
        j_caino=            {order = 146,  unlocked = false, discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 4, cost = 20, name = "Caino", pos = {x=3,y=8}, soul_pos = {x=3, y=9}, set = "Joker", effect = "", config = {extra = 1}, unlock_condition = {type = '', extra = '', hidden = true}},
        j_triboulet=        {order = 147,  unlocked = false, discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 4, cost = 20, name = "Triboulet", pos = {x=4,y=8}, soul_pos = {x=4, y=9}, set = "Joker", effect = "", config = {extra = 2}, unlock_condition = {type = '', extra = '', hidden = true}},
        j_yorick=           {order = 148,  unlocked = false, discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 4, cost = 20, name = "Yorick", pos = {x=5,y=8}, soul_pos = {x=5, y=9}, set = "Joker", effect = "", config = {extra = {xmult = 1, discards = 23}}, unlock_condition = {type = '', extra = '', hidden = true}},
        j_chicot=           {order = 149,  unlocked = false, discovered = false, blueprint_compat = false, perishable_compat = true, eternal_compat = true, rarity = 4, cost = 20, name = "Chicot", pos = {x=6,y=8}, soul_pos = {x=6, y=9}, set = "Joker", effect = "", config = {}, unlock_condition = {type = '', extra = '', hidden = true}},
        j_perkeo=           {order = 150,  unlocked = false, discovered = false, blueprint_compat = true, perishable_compat = true, eternal_compat = true, rarity = 4, cost = 20, name = "Perkeo", pos = {x=7,y=8}, soul_pos = {x=7, y=9}, set = "Joker", effect = "", config = {}, unlock_condition = {type = '', extra = '', hidden = true}},



        --All Consumeables

        --Tarots
        c_fool=             {order = 1,     discovered = false, cost = 3, consumeable = true, name = "The Fool", pos = {x=0,y=0}, set = "Tarot", effect = "Disable Blind Effect", cost_mult = 1.0, config = {}},
        c_magician=         {order = 2,     discovered = false, cost = 3, consumeable = true, name = "The Magician", pos = {x=1,y=0}, set = "Tarot", effect = "Enhance", cost_mult = 1.0, config = {mod_conv = 'm_lucky', max_highlighted = 2}},
        c_high_priestess=   {order = 3,     discovered = false, cost = 3, consumeable = true, name = "The High Priestess", pos = {x=2,y=0}, set = "Tarot", effect = "Round Bonus", cost_mult = 1.0, config = {planets = 2}},
        c_empress=          {order = 4,     discovered = false, cost = 3, consumeable = true, name = "The Empress", pos = {x=3,y=0}, set = "Tarot", effect = "Enhance", cost_mult = 1.0, config = {mod_conv = 'm_mult', max_highlighted = 2}},
        c_emperor=          {order = 5,     discovered = false, cost = 3, consumeable = true, name = "The Emperor", pos = {x=4,y=0}, set = "Tarot", effect = "Round Bonus", cost_mult = 1.0, config = {tarots = 2}},
        c_heirophant=       {order = 6,     discovered = false, cost = 3, consumeable = true, name = "The Hierophant", pos = {x=5,y=0}, set = "Tarot", effect = "Enhance", cost_mult = 1.0, config = {mod_conv = 'm_bonus', max_highlighted = 2}},
        c_lovers=           {order = 7,     discovered = false, cost = 3, consumeable = true, name = "The Lovers", pos = {x=6,y=0}, set = "Tarot", effect = "Enhance", cost_mult = 1.0, config = {mod_conv = 'm_wild', max_highlighted = 1}},
        c_chariot=          {order = 8,     discovered = false, cost = 3, consumeable = true, name = "The Chariot", pos = {x=7,y=0}, set = "Tarot", effect = "Enhance", cost_mult = 1.0, config = {mod_conv = 'm_steel', max_highlighted = 1}},
        c_justice=          {order = 9,     discovered = false, cost = 3, consumeable = true, name = "Justice", pos = {x=8,y=0}, set = "Tarot", effect = "Enhance", cost_mult = 1.0, config = {mod_conv = 'm_glass', max_highlighted = 1}},
        c_hermit=           {order = 10,    discovered = false, cost = 3, consumeable = true, name = "The Hermit", pos = {x=9,y=0}, set = "Tarot", effect = "Dollar Doubler", cost_mult = 1.0, config = {extra = 20}},
        c_wheel_of_fortune= {order = 11,    discovered = false, cost = 3, consumeable = true, name = "The Wheel of Fortune", pos = {x=0,y=1}, set = "Tarot", effect = "Round Bonus", cost_mult = 1.0, config = {extra = 4}},
        c_strength=         {order = 12,    discovered = false, cost = 3, consumeable = true, name = "Strength", pos = {x=1,y=1}, set = "Tarot", effect = "Round Bonus", cost_mult = 1.0, config = {mod_conv = 'up_rank', max_highlighted = 2}},
        c_hanged_man=       {order = 13,    discovered = false, cost = 3, consumeable = true, name = "The Hanged Man", pos = {x=2,y=1}, set = "Tarot", effect = "Card Removal", cost_mult = 1.0, config = {remove_card = true, max_highlighted = 2}},
        c_death=            {order = 14,    discovered = false, cost = 3, consumeable = true, name = "Death", pos = {x=3,y=1}, set = "Tarot", effect = "Card Conversion", cost_mult = 1.0, config = {mod_conv = 'card', max_highlighted = 2, min_highlighted = 2}},
        c_temperance=       {order = 15,    discovered = false, cost = 3, consumeable = true, name = "Temperance", pos = {x=4,y=1}, set = "Tarot", effect = "Joker Payout", cost_mult = 1.0, config = {extra = 50}},
        c_devil=            {order = 16,    discovered = false, cost = 3, consumeable = true, name = "The Devil", pos = {x=5,y=1}, set = "Tarot", effect = "Enhance", cost_mult = 1.0, config = {mod_conv = 'm_gold', max_highlighted = 1}},
        c_tower=            {order = 17,    discovered = false, cost = 3, consumeable = true, name = "The Tower", pos = {x=6,y=1}, set = "Tarot", effect = "Enhance", cost_mult = 1.0, config = {mod_conv = 'm_stone', max_highlighted = 1}},
        c_star=             {order = 18,    discovered = false, cost = 3, consumeable = true, name = "The Star", pos = {x=7,y=1}, set = "Tarot", effect = "Suit Conversion", cost_mult = 1.0, config = {suit_conv = 'Diamonds', max_highlighted = 3}},
        c_moon=             {order = 19,    discovered = false, cost = 3, consumeable = true, name = "The Moon", pos = {x=8,y=1}, set = "Tarot", effect = "Suit Conversion", cost_mult = 1.0, config = {suit_conv = 'Clubs', max_highlighted = 3}},
        c_sun=              {order = 20,    discovered = false, cost = 3, consumeable = true, name = "The Sun", pos = {x=9,y=1}, set = "Tarot", effect = "Suit Conversion", cost_mult = 1.0, config = {suit_conv = 'Hearts', max_highlighted = 3}},
        c_judgement=        {order = 21,    discovered = false, cost = 3, consumeable = true, name = "Judgement", pos = {x=0,y=2}, set = "Tarot", effect = "Random Joker", cost_mult = 1.0, config = {}},
        c_world=            {order = 22,    discovered = false, cost = 3, consumeable = true, name = "The World", pos = {x=1,y=2}, set = "Tarot", effect = "Suit Conversion", cost_mult = 1.0, config = {suit_conv = 'Spades', max_highlighted = 3}},

        --Planets
        c_mercury=          {order = 1,    discovered = false, cost = 3, consumeable = true, freq = 1, name = "Mercury", pos = {x=0,y=3}, set = "Planet", effect = "Hand Upgrade", cost_mult = 1.0, config = {hand_type = 'Pair'}},
        c_venus=            {order = 2,    discovered = false, cost = 3, consumeable = true, freq = 1, name = "Venus", pos = {x=1,y=3}, set = "Planet", effect = "Hand Upgrade", cost_mult = 1.0, config = {hand_type = 'Three of a Kind'}},
        c_earth=            {order = 3,    discovered = false, cost = 3, consumeable = true, freq = 1, name = "Earth", pos = {x=2,y=3}, set = "Planet", effect = "Hand Upgrade", cost_mult = 1.0, config = {hand_type = 'Full House'}},
        c_mars=             {order = 4,    discovered = false, cost = 3, consumeable = true, freq = 1, name = "Mars", pos = {x=3,y=3}, set = "Planet", effect = "Hand Upgrade", cost_mult = 1.0, config = {hand_type = 'Four of a Kind'}},
        c_jupiter=          {order = 5,    discovered = false, cost = 3, consumeable = true, freq = 1, name = "Jupiter", pos = {x=4,y=3}, set = "Planet", effect = "Hand Upgrade", cost_mult = 1.0, config = {hand_type = 'Flush'}},
        c_saturn=           {order = 6,    discovered = false, cost = 3, consumeable = true, freq = 1, name = "Saturn", pos = {x=5,y=3}, set = "Planet", effect = "Hand Upgrade", cost_mult = 1.0, config = {hand_type = 'Straight'}},
        c_uranus=           {order = 7,    discovered = false, cost = 3, consumeable = true, freq = 1, name = "Uranus", pos = {x=6,y=3}, set = "Planet", effect = "Hand Upgrade", cost_mult = 1.0, config = {hand_type = 'Two Pair'}},
        c_neptune=          {order = 8,    discovered = false, cost = 3, consumeable = true, freq = 1, name = "Neptune", pos = {x=7,y=3}, set = "Planet", effect = "Hand Upgrade", cost_mult = 1.0, config = {hand_type = 'Straight Flush'}},
        c_pluto=            {order = 9,    discovered = false, cost = 3, consumeable = true, freq = 1, name = "Pluto", pos = {x=8,y=3}, set = "Planet", effect = "Hand Upgrade", cost_mult = 1.0, config = {hand_type = 'High Card'}},
        c_planet_x=         {order = 10,   discovered = false, cost = 3, consumeable = true, freq = 1, name = "Planet X", pos = {x=9,y=2}, set = "Planet", effect = "Hand Upgrade", cost_mult = 1.0, config = {hand_type = 'Five of a Kind', softlock = true}},
        c_ceres=            {order = 11,   discovered = false, cost = 3, consumeable = true, freq = 1, name = "Ceres", pos = {x=8,y=2}, set = "Planet", effect = "Hand Upgrade", cost_mult = 1.0, config = {hand_type = 'Flush House', softlock = true}},
        c_eris=             {order = 12,   discovered = false, cost = 3, consumeable = true, freq = 1, name = "Eris", pos = {x=3,y=2}, set = "Planet", effect = "Hand Upgrade", cost_mult = 1.0, config = {hand_type = 'Flush Five', softlock = true}},

        --Spectral
        c_familiar=         {order = 1,    discovered = false, cost = 4, consumeable = true, name = "Familiar", pos = {x=0,y=4}, set = "Spectral", config = {remove_card = true, extra = 3}},
        c_grim=             {order = 2,    discovered = false, cost = 4, consumeable = true, name = "Grim",     pos = {x=1,y=4}, set = "Spectral", config = {remove_card = true, extra = 2}},
        c_incantation=      {order = 3,    discovered = false, cost = 4, consumeable = true, name = "Incantation", pos = {x=2,y=4}, set = "Spectral", config = {remove_card = true, extra = 4}},
        c_talisman=         {order = 4,    discovered = false, cost = 4, consumeable = true, name = "Talisman", pos = {x=3,y=4}, set = "Spectral", config = {extra = 'Gold', max_highlighted = 1}},
        c_aura=             {order = 5,    discovered = false, cost = 4, consumeable = true, name = "Aura", pos = {x=4,y=4}, set = "Spectral", config = {}},
        c_wraith=           {order = 6,    discovered = false, cost = 4, consumeable = true, name = "Wraith", pos = {x=5,y=4}, set = "Spectral", config = {}},
        c_sigil=            {order = 7,    discovered = false, cost = 4, consumeable = true, name = "Sigil", pos = {x=6,y=4}, set = "Spectral", config = {}},
        c_ouija=            {order = 8,    discovered = false, cost = 4, consumeable = true, name = "Ouija", pos = {x=7,y=4}, set = "Spectral", config = {}},
        c_ectoplasm=        {order = 9,    discovered = false, cost = 4, consumeable = true, name = "Ectoplasm", pos = {x=8,y=4}, set = "Spectral", config = {}},
        c_immolate=         {order = 10,   discovered = false, cost = 4, consumeable = true, name = "Immolate", pos = {x=9,y=4}, set = "Spectral", config = {remove_card = true, extra = {destroy = 5, dollars = 20}}},
        c_ankh=             {order = 11,   discovered = false, cost = 4, consumeable = true, name = "Ankh", pos = {x=0,y=5}, set = "Spectral", config = {extra = 2}},
        c_deja_vu=          {order = 12,   discovered = false, cost = 4, consumeable = true, name = "Deja Vu", pos = {x=1,y=5}, set = "Spectral", config = {extra = 'Red', max_highlighted = 1}},
        c_hex=              {order = 13,   discovered = false, cost = 4, consumeable = true, name = "Hex", pos = {x=2,y=5}, set = "Spectral", config = {extra = 2}},
        c_trance=           {order = 14,   discovered = false, cost = 4, consumeable = true, name = "Trance", pos = {x=3,y=5}, set = "Spectral", config = {extra = 'Blue', max_highlighted = 1}},
        c_medium=           {order = 15,   discovered = false, cost = 4, consumeable = true, name = "Medium", pos = {x=4,y=5}, set = "Spectral", config = {extra = 'Purple', max_highlighted = 1}},
        c_cryptid=          {order = 16,   discovered = false, cost = 4, consumeable = true, name = "Cryptid", pos = {x=5,y=5}, set = "Spectral", config = {extra = 2, max_highlighted = 1}},
        c_soul=             {order = 17,   discovered = false, cost = 4, consumeable = true, name = "The Soul", pos = {x=2,y=2}, set = "Spectral", effect = "Unlocker", config = {}, hidden = true},
        c_black_hole=       {order = 18,   discovered = false, cost = 4, consumeable = true, name = "Black Hole", pos = {x=9,y=3}, set = "Spectral", config = {}, hidden = true},

        --Vouchers

        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}},
        v_clearance_sale=   {order = 3,     discovered = false, unlocked = true , available = true, cost = 10, name = "Clearance Sale", pos = {x=3,y=0}, set = "Voucher", config = {extra = 25}},
        v_hone=             {order = 5,     discovered = false, unlocked = true , available = true, cost = 10, name = "Hone", pos = {x=4,y=0}, set = "Voucher", config = {extra = 2}},
        v_reroll_surplus=   {order = 7,    discovered = false, unlocked = true , available = true, cost = 10, name = "Reroll Surplus", pos = {x=0,y=2}, set = "Voucher", config = {extra = 2}},
        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}},
        v_telescope=        {order = 11,    discovered = false, unlocked = true , available = true, cost = 10, name = "Telescope", pos = {x=3,y=2}, set = "Voucher", config = {extra = 3}},
        v_grabber=          {order = 13,    discovered = false, unlocked = true , available = true, cost = 10, name = "Grabber", pos = {x=5,y=0}, set = "Voucher", config = {extra = 1}},
        v_wasteful=         {order = 15,    discovered = false, unlocked = true , available = true, cost = 10, name = "Wasteful", pos = {x=6,y=0}, set = "Voucher", config = {extra = 1}},
        v_tarot_merchant=   {order = 17,     discovered = false, unlocked = true , available = true, cost = 10, name = "Tarot Merchant", pos = {x=1,y=0}, set = "Voucher", config = {extra = 9.6/4, extra_disp = 2}},
        v_planet_merchant=  {order = 19,     discovered = false, unlocked = true , available = true, cost = 10, name = "Planet Merchant", pos = {x=2,y=0}, set = "Voucher", config = {extra = 9.6/4, extra_disp = 2}},
        v_seed_money=       {order = 21,    discovered = false, unlocked = true , available = true, cost = 10, name = "Seed Money", pos = {x=1,y=2}, set = "Voucher", config = {extra = 50}},
        v_blank=            {order = 23,    discovered = false, unlocked = true , available = true, cost = 10, name = "Blank", pos = {x=7,y=0}, set = "Voucher", config = {extra = 5}},
        v_magic_trick=      {order = 25,    discovered = false, unlocked = true , available = true, cost = 10, name = "Magic Trick", pos = {x=4,y=2}, set = "Voucher", config = {extra = 4}},
        v_hieroglyph=       {order = 27,    discovered = false, unlocked = true , available = true, cost = 10, name = "Hieroglyph", pos = {x=5,y=2}, set = "Voucher", config = {extra = 1}},
        v_directors_cut=    {order = 29,    discovered = false, unlocked = true , available = true, cost = 10, name = "Director's Cut", pos = {x=6,y=2}, set = "Voucher", config = {extra = 10}},
        v_paint_brush=      {order = 31,    discovered = false, unlocked = true , available = true, cost = 10, name = "Paint Brush", pos = {x=7,y=2}, set = "Voucher", config = {extra = 1}},
  
        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}},
        v_liquidation=      {order = 4,     discovered = false, unlocked = false, available = true, cost = 10, name = "Liquidation", pos = {x=3,y=1}, set = "Voucher", config = {extra = 50}, requires = {'v_clearance_sale'},unlock_condition = {type = 'run_redeem', extra = 10}},
        v_glow_up=          {order = 6,    discovered = false, unlocked = false, available = true,  cost = 10, name = "Glow Up", pos = {x=4,y=1}, set = "Voucher", config = {extra = 4}, requires = {'v_hone'},unlock_condition = {type = 'have_edition', extra = 5}},
        v_reroll_glut=      {order = 8,    discovered = false, unlocked = false, available = true,  cost = 10, name = "Reroll Glut", pos = {x=0,y=3}, set = "Voucher", config = {extra = 2}, requires = {'v_reroll_surplus'},unlock_condition = {type = 'c_shop_rerolls', extra = 100}},
        v_omen_globe=       {order = 10,    discovered = false, unlocked = false, available = true, cost = 10, name = "Omen Globe", pos = {x=2,y=3}, set = "Voucher", config = {extra = 4}, requires = {'v_crystal_ball'},unlock_condition = {type = 'c_tarot_reading_used', extra = 25}},
        v_observatory=      {order = 12,    discovered = false, unlocked = false, available = true, cost = 10, name = "Observatory", pos = {x=3,y=3}, set = "Voucher", config = {extra = 1.5}, requires = {'v_telescope'},unlock_condition = {type = 'c_planetarium_used', extra = 25}},
        v_nacho_tong=       {order = 14,    discovered = false, unlocked = false, available = true, cost = 10, name = "Nacho Tong", pos = {x=5,y=1}, set = "Voucher", config = {extra = 1}, requires = {'v_grabber'},unlock_condition = {type = 'c_cards_played', extra = 2500}},
        v_recyclomancy=     {order = 16,    discovered = false, unlocked = false, available = true, cost = 10, name = "Recyclomancy", pos = {x=6,y=1}, set = "Voucher", config = {extra = 1}, requires = {'v_wasteful'},unlock_condition = {type = 'c_cards_discarded', extra = 2500}},
        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}},
        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}},
        v_money_tree=       {order = 22,    discovered = false, unlocked = false, available = true, cost = 10, name = "Money Tree", pos = {x=1,y=3}, set = "Voucher", config = {extra = 100}, requires = {'v_seed_money'},unlock_condition = {type = 'interest_streak', extra = 10}},
        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}},
        v_illusion=         {order = 26,    discovered = false, unlocked = false, available = true, cost = 10, name = "Illusion", pos = {x=4,y=3}, set = "Voucher", config = {extra = 4}, requires = {'v_magic_trick'},unlock_condition = {type = 'c_playing_cards_bought', extra = 20}},
        v_petroglyph=       {order = 28,    discovered = false, unlocked = false, available = true, cost = 10, name = "Petroglyph", pos = {x=5,y=3}, set = "Voucher", config = {extra = 1}, requires = {'v_hieroglyph'},unlock_condition = {type = 'ante_up', ante = 12, extra = 12}},
        v_retcon=           {order = 30,    discovered = false, unlocked = false, available = true, cost = 10, name = "Retcon", pos = {x=6,y=3}, set = "Voucher", config = {extra = 10}, requires = {'v_directors_cut'},unlock_condition = {type = 'blind_discoveries', extra = 25}},
        v_palette=          {order = 32,    discovered = false, unlocked = false, available = true, cost = 10, name = "Palette", pos = {x=7,y=3}, set = "Voucher", config = {extra = 1}, requires = {'v_paint_brush'},unlock_condition = {type = 'min_hand_size', extra = 5}},

        --Backs

        b_red=              {name = "Red Deck",         stake = 1, unlocked = true,order = 1, pos =   {x=0,y=0}, set = "Back", config = {discards = 1}, discovered = true},
        b_blue=             {name = "Blue Deck",        stake = 1, unlocked = false,order = 2, pos =  {x=0,y=2}, set = "Back", config = {hands = 1}, unlock_condition = {type = 'discover_amount', amount = 20}},
        b_yellow=           {name = "Yellow Deck",      stake = 1, unlocked = false,order = 3, pos =  {x=1,y=2}, set = "Back", config = {dollars = 10}, unlock_condition = {type = 'discover_amount', amount = 50}},
        b_green=            {name = "Green Deck",       stake = 1, unlocked = false,order = 4, pos =  {x=2,y=2}, set = "Back", config = {extra_hand_bonus = 2, extra_discard_bonus = 1, no_interest = true}, unlock_condition = {type = 'discover_amount', amount = 75}},
        b_black=            {name = "Black Deck",       stake = 1, unlocked = false,order = 5, pos =  {x=3,y=2}, set = "Back", config = {hands = -1, joker_slot = 1}, unlock_condition = {type = 'discover_amount', amount = 100}},
        b_magic=            {name = "Magic Deck",       stake = 1, unlocked = false,order = 6, pos =  {x=0,y=3}, set = "Back", config = {voucher = 'v_crystal_ball', consumables = {'c_fool', 'c_fool'}}, unlock_condition = {type = 'win_deck', deck = 'b_red'}},
        b_nebula=           {name = "Nebula Deck",      stake = 1, unlocked = false,order = 7, pos =  {x=3,y=0}, set = "Back", config = {voucher = 'v_telescope', consumable_slot = -1}, unlock_condition = {type = 'win_deck', deck = 'b_blue'}},
        b_ghost=            {name = "Ghost Deck",       stake = 1, unlocked = false,order = 8, pos =  {x=6,y=2}, set = "Back", config = {spectral_rate = 2, consumables = {'c_hex'}}, unlock_condition = {type = 'win_deck', deck = 'b_yellow'}},
        b_abandoned=        {name = "Abandoned Deck",   stake = 1, unlocked = false,order = 9, pos =  {x=3,y=3}, set = "Back", config = {remove_faces = true}, unlock_condition = {type = 'win_deck', deck = 'b_green'}},
        b_checkered=        {name = "Checkered Deck",   stake = 1, unlocked = false,order = 10,pos =  {x=1,y=3}, set = "Back", config = {}, unlock_condition = {type = 'win_deck', deck = 'b_black'}},
        b_zodiac=           {name = "Zodiac Deck",      stake = 1, unlocked = false,order = 11, pos = {x=3,y=4}, set = "Back", config = {vouchers = {'v_tarot_merchant','v_planet_merchant', 'v_overstock_norm'}}, unlock_condition = {type = 'win_stake', stake = 2}},
        b_painted=          {name = "Painted Deck",     stake = 1, unlocked = false,order = 12, pos = {x=4,y=3}, set = "Back", config = {hand_size = 2, joker_slot = -1}, unlock_condition = {type = 'win_stake', stake=3}},
        b_anaglyph=         {name = "Anaglyph Deck",    stake = 1, unlocked = false,order = 13, pos = {x=2,y=4}, set = "Back", config = {}, unlock_condition = {type = 'win_stake', stake = 4}},
        b_plasma=           {name = "Plasma Deck",      stake = 1, unlocked = false,order = 14, pos = {x=4,y=2}, set = "Back", config = {ante_scaling = 2}, unlock_condition = {type = 'win_stake', stake=5}},
        b_erratic=          {name = "Erratic Deck",     stake = 1, unlocked = false,order = 15, pos = {x=2,y=3}, set = "Back", config = {randomize_rank_suit = true}, unlock_condition = {type = 'win_stake', stake=7}},
    
        b_challenge=        {name = "Challenge Deck",   stake = 1, unlocked = true,order = 16, pos = {x=0,y=4}, set = "Back", config = {}, omit = true}, 

        
        --All enhanced card types here
        m_bonus =   {max = 500, order = 2, name = "Bonus", set = "Enhanced", pos = {x=1,y=1}, effect = "Bonus Card", label = "Bonus Card", config = {bonus=30}},
        m_mult =    {max = 500, order = 3, name = "Mult", set = "Enhanced", pos = {x=2,y=1}, effect = "Mult Card", label = "Mult Card", config = {mult = 4}},
        m_wild =    {max = 500, order = 4, name = "Wild Card", set = "Enhanced", pos = {x=3,y=1}, effect = "Wild Card", label = "Wild Card", config = {}},
        m_glass =   {max = 500, order = 5, name = "Glass Card", set = "Enhanced", pos = {x=5,y=1}, effect = "Glass Card", label = "Glass Card", config = {Xmult = 2, extra = 4}},
        m_steel =   {max = 500, order = 6, name = "Steel Card", set = "Enhanced", pos = {x=6,y=1}, effect = "Steel Card", label = "Steel Card", config = {h_x_mult = 1.5}},
        m_stone =   {max = 500, order = 7, name = "Stone Card", set = "Enhanced", pos = {x=5,y=0}, effect = "Stone Card", label = "Stone Card", config = {bonus = 50}},
        m_gold =    {max = 500, order = 8, name = "Gold Card", set = "Enhanced", pos = {x=6,y=0}, effect = "Gold Card", label = "Gold Card", config = {h_dollars = 3}},
        m_lucky =   {max = 500, order = 9, name = "Lucky Card", set = "Enhanced", pos = {x=4,y=1}, effect = "Lucky Card", label = "Lucky Card", config = {mult=20, p_dollars = 20}},

        --editions
        e_base =       {order = 1,  unlocked = true, discovered = false, name = "Base", pos = {x=0,y=0}, atlas = 'Joker', set = "Edition", config = {}},
        e_foil =       {order = 2,  unlocked = true, discovered = false, name = "Foil", pos = {x=0,y=0}, atlas = 'Joker', set = "Edition", config = {extra = 50}},
        e_holo =       {order = 3,  unlocked = true, discovered = false, name = "Holographic", pos = {x=0,y=0}, atlas = 'Joker', set = "Edition", config = {extra = 10}},
        e_polychrome = {order = 4,  unlocked = true, discovered = false, name = "Polychrome", pos = {x=0,y=0}, atlas = 'Joker', set = "Edition", config = {extra = 1.5}},
        e_negative =   {order = 5,  unlocked = true, discovered = false, name = "Negative", pos = {x=0,y=0}, atlas = 'Joker', set = "Edition", config = {extra = 1}},

        --booster packs
        p_arcana_normal_1 =         {order = 1,  discovered = false, name = "Arcana Pack", weight = 1, kind = 'Arcana', cost = 4, pos = {x=0,y=0}, atlas = 'Booster', set = 'Booster', config = {extra = 3, choose = 1}},
        p_arcana_normal_2 =         {order = 2,  discovered = false, name = "Arcana Pack", weight = 1, kind = 'Arcana', cost = 4, pos = {x=1,y=0}, atlas = 'Booster', set = 'Booster', config = {extra = 3, choose = 1}},
        p_arcana_normal_3 =         {order = 3,  discovered = false, name = "Arcana Pack", weight = 1, kind = 'Arcana', cost = 4, pos = {x=2,y=0}, atlas = 'Booster', set = 'Booster', config = {extra = 3, choose = 1}},
        p_arcana_normal_4 =         {order = 4,  discovered = false, name = "Arcana Pack", weight = 1, kind = 'Arcana', cost = 4, pos = {x=3,y=0}, atlas = 'Booster', set = 'Booster', config = {extra = 3, choose = 1}},
        p_arcana_jumbo_1 =          {order = 5,  discovered = false, name = "Jumbo Arcana Pack", weight = 1, kind = 'Arcana', cost = 6, pos = {x=0,y=2}, atlas = 'Booster', set = 'Booster', config = {extra = 5, choose = 1}},
        p_arcana_jumbo_2 =          {order = 6,  discovered = false, name = "Jumbo Arcana Pack", weight = 1, kind = 'Arcana', cost = 6, pos = {x=1,y=2}, atlas = 'Booster', set = 'Booster', config = {extra = 5, choose = 1}},
        p_arcana_mega_1 =           {order = 7,  discovered = false, name = "Mega Arcana Pack", weight = 0.25, kind = 'Arcana', cost = 8, pos = {x=2,y=2}, atlas = 'Booster', set = 'Booster', config = {extra = 5, choose = 2}},
        p_arcana_mega_2 =           {order = 8,  discovered = false, name = "Mega Arcana Pack", weight = 0.25, kind = 'Arcana', cost = 8, pos = {x=3,y=2}, atlas = 'Booster', set = 'Booster', config = {extra = 5, choose = 2}},
        p_celestial_normal_1 =      {order = 9,  discovered = false, name = "Celestial Pack", weight = 1, kind = 'Celestial', cost = 4, pos = {x=0,y=1}, atlas = 'Booster', set = 'Booster', config = {extra = 3, choose = 1}},
        p_celestial_normal_2 =      {order = 10, discovered = false, name = "Celestial Pack", weight = 1, kind = 'Celestial', cost = 4, pos = {x=1,y=1}, atlas = 'Booster', set = 'Booster', config = {extra = 3, choose = 1}},
        p_celestial_normal_3 =      {order = 11, discovered = false, name = "Celestial Pack", weight = 1, kind = 'Celestial', cost = 4, pos = {x=2,y=1}, atlas = 'Booster', set = 'Booster', config = {extra = 3, choose = 1}},
        p_celestial_normal_4 =      {order = 12, discovered = false, name = "Celestial Pack", weight = 1, kind = 'Celestial', cost = 4, pos = {x=3,y=1}, atlas = 'Booster', set = 'Booster', config = {extra = 3, choose = 1}},
        p_celestial_jumbo_1 =       {order = 13, discovered = false, name = "Jumbo Celestial Pack", weight = 1, kind = 'Celestial', cost = 6, pos = {x=0,y=3}, atlas = 'Booster', set = 'Booster', config = {extra = 5, choose = 1}},
        p_celestial_jumbo_2 =       {order = 14, discovered = false, name = "Jumbo Celestial Pack", weight = 1, kind = 'Celestial', cost = 6, pos = {x=1,y=3}, atlas = 'Booster', set = 'Booster', config = {extra = 5, choose = 1}},
        p_celestial_mega_1 =        {order = 15, discovered = false, name = "Mega Celestial Pack", weight = 0.25, kind = 'Celestial', cost = 8, pos = {x=2,y=3}, atlas = 'Booster', set = 'Booster', config = {extra = 5, choose = 2}},
        p_celestial_mega_2 =        {order = 16, discovered = false, name = "Mega Celestial Pack", weight = 0.25, kind = 'Celestial', cost = 8, pos = {x=3,y=3}, atlas = 'Booster', set = 'Booster', config = {extra = 5, choose = 2}},
        p_spectral_normal_1 =       {order = 29, discovered = false, name = "Spectral Pack", weight = 0.3, kind = 'Spectral', cost = 4, pos = {x=0,y=4}, atlas = 'Booster', set = 'Booster', config = {extra = 2, choose = 1}},
        p_spectral_normal_2 =       {order = 30, discovered = false, name = "Spectral Pack", weight = 0.3, kind = 'Spectral', cost = 4, pos = {x=1,y=4}, atlas = 'Booster', set = 'Booster', config = {extra = 2, choose = 1}},
        p_spectral_jumbo_1 =        {order = 31, discovered = false, name = "Jumbo Spectral Pack", weight = 0.3, kind = 'Spectral', cost = 6, pos = {x=2,y=4}, atlas = 'Booster', set = 'Booster', config = {extra = 4, choose = 1}},
        p_spectral_mega_1 =         {order = 32, discovered = false, name = "Mega Spectral Pack", weight = 0.07, kind = 'Spectral', cost = 8, pos = {x=3,y=4}, atlas = 'Booster', set = 'Booster', config = {extra = 4, choose = 2}},
        p_standard_normal_1 =       {order = 17, discovered = false, name = "Standard Pack", weight = 1, kind = 'Standard', cost = 4, pos = {x=0,y=6}, atlas = 'Booster', set = 'Booster', config = {extra = 3, choose = 1}},
        p_standard_normal_2 =       {order = 18, discovered = false, name = "Standard Pack", weight = 1, kind = 'Standard', cost = 4, pos = {x=1,y=6}, atlas = 'Booster', set = 'Booster', config = {extra = 3, choose = 1}},
        p_standard_normal_3 =       {order = 19, discovered = false, name = "Standard Pack", weight = 1, kind = 'Standard', cost = 4, pos = {x=2,y=6}, atlas = 'Booster', set = 'Booster', config = {extra = 3, choose = 1}},
        p_standard_normal_4 =       {order = 20, discovered = false, name = "Standard Pack", weight = 1, kind = 'Standard', cost = 4, pos = {x=3,y=6}, atlas = 'Booster', set = 'Booster', config = {extra = 3, choose = 1}},
        p_standard_jumbo_1 =        {order = 21, discovered = false, name = "Jumbo Standard Pack", weight = 1, kind = 'Standard', cost = 6, pos = {x=0,y=7}, atlas = 'Booster', set = 'Booster', config = {extra = 5, choose = 1}},
        p_standard_jumbo_2 =        {order = 22, discovered = false, name = "Jumbo Standard Pack", weight = 1, kind = 'Standard', cost = 6, pos = {x=1,y=7}, atlas = 'Booster', set = 'Booster', config = {extra = 5, choose = 1}},
        p_standard_mega_1 =         {order = 23, discovered = false, name = "Mega Standard Pack", weight = 0.25, kind = 'Standard', cost = 8, pos = {x=2,y=7}, atlas = 'Booster', set = 'Booster', config = {extra = 5, choose = 2}},
        p_standard_mega_2 =         {order = 24, discovered = false, name = "Mega Standard Pack", weight = 0.25, kind = 'Standard', cost = 8, pos = {x=3,y=7}, atlas = 'Booster', set = 'Booster', config = {extra = 5, choose = 2}},
        p_buffoon_normal_1 =        {order = 25, discovered = false, name = "Buffoon Pack", weight = 0.6, kind = 'Buffoon', cost = 4, pos = {x=0,y=8}, atlas = 'Booster', set = 'Booster', config = {extra = 2, choose = 1}},
        p_buffoon_normal_2 =        {order = 26, discovered = false, name = "Buffoon Pack", weight = 0.6, kind = 'Buffoon', cost = 4, pos = {x=1,y=8}, atlas = 'Booster', set = 'Booster', config = {extra = 2, choose = 1}},
        p_buffoon_jumbo_1 =         {order = 27, discovered = false, name = "Jumbo Buffoon Pack", weight = 0.6, kind = 'Buffoon', cost = 6, pos = {x=2,y=8}, atlas = 'Booster', set = 'Booster', config = {extra = 4, choose = 1}},
        p_buffoon_mega_1 =          {order = 28, discovered = false, name = "Mega Buffoon Pack", weight = 0.15, kind = 'Buffoon', cost = 8, pos = {x=3,y=8}, atlas = 'Booster', set = 'Booster', config = {extra = 4, choose = 2}},

        --Extras       
        soul={pos = {x=0,y=1}},
        undiscovered_joker={pos = {x=5,y=3}},
        undiscovered_tarot={pos = {x=6,y=3}},
    }

    self.P_CENTER_POOLS = {
        Booster = {},
        Default = {},
        Enhanced = {},
        Edition = {},
        Joker = {},
        Tarot = {},
        Planet = {},
        Tarot_Planet = {},
        Spectral = {},
        Consumeables = {},
        Voucher = {},
        Back = {},
        Tag = {},
        Seal = {},
        Stake = {},
        Demo = {}
    }

    self.P_JOKER_RARITY_POOLS = {
        {},{},{},{}
    }

    self.P_LOCKED = {}

    self:save_progress()


    -------------------------------------
    local TESTHELPER_unlocks = false and not _RELEASE_MODE
    -------------------------------------
    if not love.filesystem.getInfo(G.SETTINGS.profile..'') then love.filesystem.createDirectory( G.SETTINGS.profile..'' ) end
    if not love.filesystem.getInfo(G.SETTINGS.profile..'/'..'meta.jkr') then love.filesystem.append( G.SETTINGS.profile..'/'..'meta.jkr', 'return {}') end

    convert_save_to_meta()

    local meta = STR_UNPACK(get_compressed(G.SETTINGS.profile..'/'..'meta.jkr') or 'return {}')
    meta.unlocked = meta.unlocked or {}
    meta.discovered = meta.discovered or {}
    meta.alerted = meta.alerted or {}
    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
    
    for k, v in pairs(self.P_CENTERS) do
        if not v.wip and not v.demo then 
            if TESTHELPER_unlocks then v.unlocked = true; v.discovered = true;v.alerted = true end --REMOVE THIS
            if not v.unlocked and (string.find(k, '^j_') or string.find(k, '^b_') or string.find(k, '^v_')) and meta.unlocked[k] then 
                v.unlocked = true
            end
            if not v.unlocked and (string.find(k, '^j_') or string.find(k, '^b_') or string.find(k, '^v_')) then self.P_LOCKED[#self.P_LOCKED+1] = v end
            if not v.discovered and (string.find(k, '^j_') or string.find(k, '^b_') or string.find(k, '^e_') or string.find(k, '^c_') or string.find(k, '^p_') or string.find(k, '^v_')) and meta.discovered[k] then 
                v.discovered = true
            end
            if v.discovered and meta.alerted[k] or v.set == 'Back' or v.start_alerted then 
                v.alerted = true
            elseif v.discovered then
                v.alerted = false
            end
        end
    end

    table.sort(self.P_LOCKED, function (a, b) return not a.order or not b.order or a.order < b.order end)

    for k, v in pairs(self.P_BLINDS) do
        v.key = k
        if not v.wip and not v.demo then 
            if TESTHELPER_unlocks then v.discovered = true; v.alerted = true  end --REMOVE THIS
            if not v.discovered and meta.discovered[k] then 
                v.discovered = true
            end
            if v.discovered and meta.alerted[k] then 
                v.alerted = true
            elseif v.discovered then
                v.alerted = false
            end
        end
    end
    for k, v in pairs(self.P_TAGS) do
        v.key = k
        if not v.wip and not v.demo then 
            if TESTHELPER_unlocks then v.discovered = true; v.alerted = true  end --REMOVE THIS
            if not v.discovered and meta.discovered[k] then 
                v.discovered = true
            end
            if v.discovered and meta.alerted[k] then 
                v.alerted = true
            elseif v.discovered then
                v.alerted = false
            end
            table.insert(self.P_CENTER_POOLS['Tag'], v)
        end
    end
    for k, v in pairs(self.P_SEALS) do
        v.key = k
        if not v.wip and not v.demo then 
            if TESTHELPER_unlocks then v.discovered = true; v.alerted = true  end --REMOVE THIS
            if not v.discovered and meta.discovered[k] then 
                v.discovered = true
            end
            if v.discovered and meta.alerted[k] then 
                v.alerted = true
            elseif v.discovered then
                v.alerted = false
            end
            table.insert(self.P_CENTER_POOLS['Seal'], v)
        end
    end
    for k, v in pairs(self.P_STAKES) do
        v.key = k
        table.insert(self.P_CENTER_POOLS['Stake'], v)
    end

    for k, v in pairs(self.P_CENTERS) do
        v.key = k
        if v.set == 'Joker' then table.insert(self.P_CENTER_POOLS['Joker'], v) end
        if v.set and v.demo and v.pos then table.insert(self.P_CENTER_POOLS['Demo'], v) end
        if not v.wip then 
            if v.set and v.set ~= 'Joker' and not v.skip_pool and not v.omit then table.insert(self.P_CENTER_POOLS[v.set], v) end
            if v.set == 'Tarot' or v.set == 'Planet' then table.insert(self.P_CENTER_POOLS['Tarot_Planet'], v) end
            if v.consumeable then table.insert(self.P_CENTER_POOLS['Consumeables'], v) end
            if v.rarity and v.set == 'Joker' and not v.demo then table.insert(self.P_JOKER_RARITY_POOLS[v.rarity], v) end
        end
    end

    table.sort(self.P_CENTER_POOLS["Joker"], function (a, b) return a.order < b.order end)
    table.sort(self.P_CENTER_POOLS["Tarot"], function (a, b) return a.order < b.order end)
    table.sort(self.P_CENTER_POOLS["Planet"], function (a, b) return a.order < b.order end)
    table.sort(self.P_CENTER_POOLS["Tarot_Planet"], function (a, b) return a.order < b.order end)
    table.sort(self.P_CENTER_POOLS["Spectral"], function (a, b) return a.order < b.order end)
    table.sort(self.P_CENTER_POOLS["Voucher"], function (a, b) return a.order < b.order end)
    table.sort(self.P_CENTER_POOLS["Booster"], function (a, b) return a.order < b.order end)
    table.sort(self.P_CENTER_POOLS["Consumeables"], function (a, b) return a.order < b.order end)
    table.sort(self.P_CENTER_POOLS["Back"], function (a, b) return (a.order - (a.unlocked and 100 or 0)) < (b.order - (b.unlocked and 100 or 0)) end)
    table.sort(self.P_CENTER_POOLS["Enhanced"], function (a, b) return a.order < b.order end)
    table.sort(self.P_CENTER_POOLS["Edition"], function (a, b) return a.order < b.order end)
    table.sort(self.P_CENTER_POOLS["Stake"], function (a, b) return a.order < b.order end)
    table.sort(self.P_CENTER_POOLS["Tag"], function (a, b) return a.order < b.order end)
    table.sort(self.P_CENTER_POOLS["Seal"], function (a, b) return a.order < b.order end)
    table.sort(self.P_CENTER_POOLS["Demo"], function (a, b) return a.order + (a.set == 'Joker' and 1000 or 0) < b.order + (b.set == 'Joker' and 1000 or 0) end)
    for i = 1, 4 do 
        table.sort(self.P_JOKER_RARITY_POOLS[i], function (a, b) return a.order < b.order end)
    end
end

function Game:load_profile(_profile)
    if not G.PROFILES[_profile] then _profile = 1 end
    G.SETTINGS.profile = _profile
    
    --Load the settings file
    local info = get_compressed(_profile..'/profile.jkr')
    if info ~= nil then
        for k, v in pairs(STR_UNPACK(info)) do
            G.PROFILES[G.SETTINGS.profile][k] = v
        end
    end

    local temp_profile = {
        MEMORY = {
            deck = 'Red Deck',
            stake = 1,
        },
        stake = 1,
        
        high_scores = {
            hand = {label = 'Best Hand', amt = 0},
            furthest_round = {label = 'Highest Round', amt = 0},
            furthest_ante = {label = 'Highest Ante', amt = 0},
            most_money = {label = 'Most Money', amt = 0},
            boss_streak = {label = 'Most Bosses in a Row', amt = 0},
            collection = {label = 'Collection', amt = 0, tot = 1},
            win_streak = {label = 'Best Win Streak', amt = 0},
            current_streak = {label = '', amt = 0},
            poker_hand = {label = 'Most Played Hand', amt = 0}
        },
    
        career_stats = {
            c_round_interest_cap_streak = 0,
            c_dollars_earned = 0,
            c_shop_dollars_spent = 0,
            c_tarots_bought = 0,
            c_planets_bought = 0,
            c_playing_cards_bought = 0,
            c_vouchers_bought = 0,
            c_tarot_reading_used = 0,
            c_planetarium_used = 0,
            c_shop_rerolls = 0,
            c_cards_played = 0,
            c_cards_discarded = 0,
            c_losses = 0,
            c_wins = 0,
            c_rounds = 0,
            c_hands_played = 0,
            c_face_cards_played = 0,
            c_jokers_sold = 0,
            c_cards_sold = 0,
            c_single_hand_round_streak = 0,
        },
        progress = {

        },
        joker_usage = {},
        consumeable_usage = {},
        voucher_usage = {},
        hand_usage = {},
        deck_usage = {},
        deck_stakes = {},
        challenges_unlocked = nil,
        challenge_progress = {
            completed = {},
            unlocked = {}
        }
    }
    local recursive_init 
    recursive_init = function(t1, t2) 
        for k, v in pairs(t1) do
            if not t2[k] then 
                t2[k] = v
            elseif type(t2[k]) == 'table' and type(v) == 'table' then
                recursive_init(v, t2[k])
            end
        end
    end

    recursive_init(temp_profile, G.PROFILES[G.SETTINGS.profile])
end

function Game:set_language()
    if not self.LANGUAGES then 
        if false then
            ------------------------------------------
            --SET LANGUAGE FOR FIRST TIME STARTUP HERE

            ------------------------------------------

            G.SETTINGS.language = 'en-us'
        end
        -------------------------------------------------------
        --IF LANGUAGE NEEDS TO BE SET ON EVERY REBOOT, SET HERE

        -------------------------------------------------------

        self.LANGUAGES = {
            ['en-us'] = {font = 1, label = "English", key = 'en-us', button = "Language Feedback", warning = {'This language is still in Beta. To help us','improve it, please click on the feedback button.', 'Click again to confirm'}},
            ['de'] = {font = 1, label = "Deutsch", key = 'de', beta = nil, button = "Feedback zur Übersetzung", warning = {'Diese Übersetzung ist noch im Beta-Stadium. Willst du uns helfen,','sie zu verbessern? Dann klicke bitte auf die Feedback-Taste.', "Zum Bestätigen erneut klicken"}},
            ['es_419'] = {font = 1, label = "Español (México)", key = 'es_419', beta = nil, button = "Sugerencias de idioma", warning = {'Este idioma todavía está en Beta. Pulsa el botón','de sugerencias para ayudarnos a mejorarlo.', "Haz clic de nuevo para confirmar"}},
            ['es_ES'] = {font = 1, label = "Español (España)", key = 'es_ES', beta = nil, button = "Sugerencias de idioma", warning = {'Este idioma todavía está en Beta. Pulsa el botón','de sugerencias para ayudarnos a mejorarlo.', "Haz clic de nuevo para confirmar"}},
            ['fr'] = {font = 1, label = "Français", key = 'fr', beta = nil, button = "Partager votre avis", warning = {'La traduction française est encore en version bêta. ','Veuillez cliquer sur le bouton pour nous donner votre avis.', "Cliquez à nouveau pour confirmer"}},
            ['id'] = {font = 1, label = "Bahasa Indonesia", key = 'id', beta = true, button = "Umpan Balik Bahasa", warning = {'Bahasa ini masih dalam tahap Beta. Untuk membantu','kami meningkatkannya, silakan klik tombol umpan balik.', "Klik lagi untuk mengonfirmasi"}},
            ['it'] = {font = 1, label = "Italiano", key = 'it', beta = nil, button = "Feedback traduzione", warning = {'Questa traduzione è ancora in Beta. Per','aiutarci a migliorarla, clicca il tasto feedback', "Fai clic di nuovo per confermare"}},
            ['ja'] = {font = 5, label = "日本語", key = 'ja', beta = nil, button = "提案する", warning = {'この翻訳は現在ベータ版です。提案があった場合、','ボタンをクリックしてください。', "もう一度クリックして確認"}},
            ['ko'] = {font = 4, label = "한국어", key = 'ko', beta = nil, button = "번역 피드백", warning = {'이 언어는 아직 베타 단계에 있습니다. ','번역을 도와주시려면 피드백 버튼을 눌러주세요.', "다시 클릭해서 확인하세요"}},
            ['nl'] = {font = 1, label = "Nederlands", key = 'nl', beta = nil, button = "Taal suggesties", warning = {'Deze taal is nog in de Beta fase. Help ons het te ','verbeteren door op de suggestie knop te klikken.', "Klik opnieuw om te bevestigen"}},
            ['pl'] = {font = 1, label = "Polski", key = 'pl', beta = nil, button = "Wyślij uwagi do tłumaczenia", warning = {'Polska wersja językowa jest w fazie Beta. By pomóc nam poprawić',' jakość tłumaczenia, kliknij przycisk i podziel się swoją opinią i uwagami.', "Kliknij ponownie, aby potwierdzić"}},
            ['pt_BR'] = {font = 1, label = "Português", key = 'pt_BR', beta = nil, button = "Feedback de Tradução", warning = {'Esta tradução ainda está em Beta. Se quiser nos ajudar','a melhorá-la, clique no botão de feedback por favor', "Clique novamente para confirmar"}},
            ['ru'] = {font = 6, label = "Русский", key = 'ru', beta = true, button = "Отзыв о языке", warning = {'Этот язык все еще находится в Бета-версии. Чтобы помочь','нам его улучшить, пожалуйста, нажмите на кнопку обратной связи.', "Щелкните снова, чтобы подтвердить"}},
            ['zh_CN'] = {font = 2, label = "简体中文", key = 'zh_CN', beta = nil, button = "意见反馈", warning = {'这个语言目前尚为Beta版本。 请帮助我们改善翻译品质，','点击”意见反馈” 来提供你的意见。', "再次点击确认"}},
            ['zh_TW'] = {font = 3, label = "繁體中文", key = 'zh_TW', beta = nil, button = "意見回饋", warning = {'這個語言目前尚為Beta版本。請幫助我們改善翻譯品質，','點擊”意見回饋” 來提供你的意見。', "再按一下即可確認"}},
            ['all1'] = {font = 8, label = "English", key = 'all', omit = true},
            ['all2'] = {font = 9, label = "English", key = 'all', omit = true},
        }
        --if G.F_ENGLISH_ONLY then
        --    self.LANGUAGES = {
        --        ['en-us'] = self.LANGUAGES['en-us']
        --    }
        --end
        
        --load the font and set filter
        self.FONTS = {
            {file = "resources/fonts/m6x11plus.ttf", render_scale = self.TILESIZE*10, TEXT_HEIGHT_SCALE = 0.83, TEXT_OFFSET = {x=10,y=-20}, FONTSCALE = 0.1, squish = 1, DESCSCALE = 1},
            {file = "resources/fonts/NotoSansSC-Bold.ttf", render_scale = self.TILESIZE*7, TEXT_HEIGHT_SCALE = 0.7, TEXT_OFFSET = {x=0,y=-35}, FONTSCALE = 0.12, squish = 1, DESCSCALE = 1.1},
            {file = "resources/fonts/NotoSansTC-Bold.ttf", render_scale = self.TILESIZE*7, TEXT_HEIGHT_SCALE = 0.7, TEXT_OFFSET = {x=0,y=-35}, FONTSCALE = 0.12, squish = 1, DESCSCALE = 1.1},
            {file = "resources/fonts/NotoSansKR-Bold.ttf", render_scale = self.TILESIZE*7, TEXT_HEIGHT_SCALE = 0.8, TEXT_OFFSET = {x=0,y=-20}, FONTSCALE = 0.12, squish = 1, DESCSCALE = 1},
            {file = "resources/fonts/NotoSansJP-Bold.ttf", render_scale = self.TILESIZE*7, TEXT_HEIGHT_SCALE = 0.8, TEXT_OFFSET = {x=0,y=-20}, FONTSCALE = 0.12, squish = 1, DESCSCALE = 1},
            {file = "resources/fonts/NotoSans-Bold.ttf", render_scale = self.TILESIZE*7, TEXT_HEIGHT_SCALE = 0.65, TEXT_OFFSET = {x=0,y=-40}, FONTSCALE = 0.12, squish = 1, DESCSCALE = 1},
            {file = "resources/fonts/m6x11plus.ttf", render_scale = self.TILESIZE*10, TEXT_HEIGHT_SCALE = 0.9, TEXT_OFFSET = {x=10,y=15}, FONTSCALE = 0.1, squish = 1, DESCSCALE = 1},
            {file = "resources/fonts/GoNotoCurrent-Bold.ttf", render_scale = self.TILESIZE*10, TEXT_HEIGHT_SCALE = 0.8, TEXT_OFFSET = {x=10,y=-20}, FONTSCALE = 0.1, squish = 1, DESCSCALE = 1},
            {file = "resources/fonts/GoNotoCJKCore.ttf", render_scale = self.TILESIZE*10, TEXT_HEIGHT_SCALE = 0.8, TEXT_OFFSET = {x=10,y=-20}, FONTSCALE = 0.1, squish = 1, DESCSCALE = 1},
        }
        for _, v in ipairs(self.FONTS) do
            if love.filesystem.getInfo(v.file) then 
                v.FONT = love.graphics.newFont( v.file, v.render_scale)
            end
        end
        for _, v in pairs(self.LANGUAGES) do
            v.font = self.FONTS[v.font]
        end
    end

    self.LANG = self.LANGUAGES[self.SETTINGS.real_language or self.SETTINGS.language] or self.LANGUAGES['en-us']

    local localization = love.filesystem.getInfo('localization/'..G.SETTINGS.language..'.lua') or love.filesystem.getInfo('localization/en-us.lua')
    if localization ~= nil then
      self.localization = assert(loadstring(love.filesystem.read('localization/'..G.SETTINGS.language..'.lua') or love.filesystem.read('localization/en-us.lua')))()
      init_localization()
    end
end

function Game:set_render_settings()
    self.SETTINGS.GRAPHICS.texture_scaling = self.SETTINGS.GRAPHICS.texture_scaling or 2

    --Set fiter to linear interpolation and nearest, best for pixel art
    love.graphics.setDefaultFilter(
        self.SETTINGS.GRAPHICS.texture_scaling == 1 and 'nearest' or 'linear',
        self.SETTINGS.GRAPHICS.texture_scaling == 1 and 'nearest' or 'linear', 1)

    love.graphics.setLineStyle("rough")

    --spritesheets
    self.animation_atli = {
        {name = "blind_chips", path = "resources/textures/"..self.SETTINGS.GRAPHICS.texture_scaling.."x/BlindChips.png",px=34,py=34, frames = 21},
        {name = "shop_sign", path = "resources/textures/"..self.SETTINGS.GRAPHICS.texture_scaling.."x/ShopSignAnimation.png",px=113,py=57, frames = 4}
    }
    self.asset_atli = {
        {name = "cards_1", path = "resources/textures/"..self.SETTINGS.GRAPHICS.texture_scaling.."x/8BitDeck.png",px=71,py=95},
        {name = "cards_2", path = "resources/textures/"..self.SETTINGS.GRAPHICS.texture_scaling.."x/8BitDeck_opt2.png",px=71,py=95},
        {name = "centers", path = "resources/textures/"..self.SETTINGS.GRAPHICS.texture_scaling.."x/Enhancers.png",px=71,py=95},
        {name = "Joker", path = "resources/textures/"..self.SETTINGS.GRAPHICS.texture_scaling.."x/Jokers.png",px=71,py=95},
        {name = "Tarot", path = "resources/textures/"..self.SETTINGS.GRAPHICS.texture_scaling.."x/Tarots.png",px=71,py=95},
        {name = "Voucher", path = "resources/textures/"..self.SETTINGS.GRAPHICS.texture_scaling.."x/Vouchers.png",px=71,py=95},
        {name = "Booster", path = "resources/textures/"..self.SETTINGS.GRAPHICS.texture_scaling.."x/boosters.png",px=71,py=95},
        {name = "ui_1", path = "resources/textures/"..self.SETTINGS.GRAPHICS.texture_scaling.."x/ui_assets.png",px=18,py=18},
        {name = "ui_2", path = "resources/textures/"..self.SETTINGS.GRAPHICS.texture_scaling.."x/ui_assets_opt2.png",px=18,py=18},
        {name = "balatro", path = "resources/textures/"..self.SETTINGS.GRAPHICS.texture_scaling.."x/balatro.png",px=333,py=216},        
        {name = 'gamepad_ui', path = "resources/textures/"..self.SETTINGS.GRAPHICS.texture_scaling.."x/gamepad_ui.png",px=32,py=32},
        {name = 'icons', path = "resources/textures/"..self.SETTINGS.GRAPHICS.texture_scaling.."x/icons.png",px=66,py=66},
        {name = 'tags', path = "resources/textures/"..self.SETTINGS.GRAPHICS.texture_scaling.."x/tags.png",px=34,py=34},
        {name = 'stickers', path = "resources/textures/"..self.SETTINGS.GRAPHICS.texture_scaling.."x/stickers.png",px=71,py=95},
        {name = 'chips', path = "resources/textures/"..self.SETTINGS.GRAPHICS.texture_scaling.."x/chips.png",px=29,py=29},

        {name = 'collab_AU_1', path = "resources/textures/"..self.SETTINGS.GRAPHICS.texture_scaling.."x/collabs/collab_AU_1.png",px=71,py=95},
        {name = 'collab_AU_2', path = "resources/textures/"..self.SETTINGS.GRAPHICS.texture_scaling.."x/collabs/collab_AU_2.png",px=71,py=95},
        {name = 'collab_TW_1', path = "resources/textures/"..self.SETTINGS.GRAPHICS.texture_scaling.."x/collabs/collab_TW_1.png",px=71,py=95},
        {name = 'collab_TW_2', path = "resources/textures/"..self.SETTINGS.GRAPHICS.texture_scaling.."x/collabs/collab_TW_2.png",px=71,py=95},
        {name = 'collab_VS_1', path = "resources/textures/"..self.SETTINGS.GRAPHICS.texture_scaling.."x/collabs/collab_VS_1.png",px=71,py=95},
        {name = 'collab_VS_2', path = "resources/textures/"..self.SETTINGS.GRAPHICS.texture_scaling.."x/collabs/collab_VS_2.png",px=71,py=95},
        {name = 'collab_DTD_1', path = "resources/textures/"..self.SETTINGS.GRAPHICS.texture_scaling.."x/collabs/collab_DTD_1.png",px=71,py=95},
        {name = 'collab_DTD_2', path = "resources/textures/"..self.SETTINGS.GRAPHICS.texture_scaling.."x/collabs/collab_DTD_2.png",px=71,py=95},
        {name = 'collab_CYP_1', path = "resources/textures/"..self.SETTINGS.GRAPHICS.texture_scaling.."x/collabs/collab_CYP_1.png",px=71,py=95},
        {name = 'collab_CYP_2', path = "resources/textures/"..self.SETTINGS.GRAPHICS.texture_scaling.."x/collabs/collab_CYP_2.png",px=71,py=95},
        {name = 'collab_STS_1', path = "resources/textures/"..self.SETTINGS.GRAPHICS.texture_scaling.."x/collabs/collab_STS_1.png",px=71,py=95},
        {name = 'collab_STS_2', path = "resources/textures/"..self.SETTINGS.GRAPHICS.texture_scaling.."x/collabs/collab_STS_2.png",px=71,py=95},
        {name = 'collab_TBoI_1', path = "resources/textures/"..self.SETTINGS.GRAPHICS.texture_scaling.."x/collabs/collab_TBoI_1.png",px=71,py=95},
        {name = 'collab_TBoI_2', path = "resources/textures/"..self.SETTINGS.GRAPHICS.texture_scaling.."x/collabs/collab_TBoI_2.png",px=71,py=95},
        {name = 'collab_SV_1', path = "resources/textures/"..self.SETTINGS.GRAPHICS.texture_scaling.."x/collabs/collab_SV_1.png",px=71,py=95},
        {name = 'collab_SV_2', path = "resources/textures/"..self.SETTINGS.GRAPHICS.texture_scaling.."x/collabs/collab_SV_2.png",px=71,py=95},
        
        {name = 'collab_SK_1', path = "resources/textures/"..self.SETTINGS.GRAPHICS.texture_scaling.."x/collabs/collab_SK_1.png",px=71,py=95},
        {name = 'collab_SK_2', path = "resources/textures/"..self.SETTINGS.GRAPHICS.texture_scaling.."x/collabs/collab_SK_2.png",px=71,py=95},
        {name = 'collab_DS_1', path = "resources/textures/"..self.SETTINGS.GRAPHICS.texture_scaling.."x/collabs/collab_DS_1.png",px=71,py=95},
        {name = 'collab_DS_2', path = "resources/textures/"..self.SETTINGS.GRAPHICS.texture_scaling.."x/collabs/collab_DS_2.png",px=71,py=95},
        {name = 'collab_CL_1', path = "resources/textures/"..self.SETTINGS.GRAPHICS.texture_scaling.."x/collabs/collab_CL_1.png",px=71,py=95},
        {name = 'collab_CL_2', path = "resources/textures/"..self.SETTINGS.GRAPHICS.texture_scaling.."x/collabs/collab_CL_2.png",px=71,py=95},
        {name = 'collab_D2_1', path = "resources/textures/"..self.SETTINGS.GRAPHICS.texture_scaling.."x/collabs/collab_D2_1.png",px=71,py=95},
        {name = 'collab_D2_2', path = "resources/textures/"..self.SETTINGS.GRAPHICS.texture_scaling.."x/collabs/collab_D2_2.png",px=71,py=95},
        {name = 'collab_PC_1', path = "resources/textures/"..self.SETTINGS.GRAPHICS.texture_scaling.."x/collabs/collab_PC_1.png",px=71,py=95},
        {name = 'collab_PC_2', path = "resources/textures/"..self.SETTINGS.GRAPHICS.texture_scaling.."x/collabs/collab_PC_2.png",px=71,py=95},
        {name = 'collab_WF_1', path = "resources/textures/"..self.SETTINGS.GRAPHICS.texture_scaling.."x/collabs/collab_WF_1.png",px=71,py=95},
        {name = 'collab_WF_2', path = "resources/textures/"..self.SETTINGS.GRAPHICS.texture_scaling.."x/collabs/collab_WF_2.png",px=71,py=95},
        {name = 'collab_EG_1', path = "resources/textures/"..self.SETTINGS.GRAPHICS.texture_scaling.."x/collabs/collab_EG_1.png",px=71,py=95},
        {name = 'collab_EG_2', path = "resources/textures/"..self.SETTINGS.GRAPHICS.texture_scaling.."x/collabs/collab_EG_2.png",px=71,py=95},
        {name = 'collab_XR_1', path = "resources/textures/"..self.SETTINGS.GRAPHICS.texture_scaling.."x/collabs/collab_XR_1.png",px=71,py=95},
        {name = 'collab_XR_2', path = "resources/textures/"..self.SETTINGS.GRAPHICS.texture_scaling.."x/collabs/collab_XR_2.png",px=71,py=95},
    }
    self.asset_images = {
        {name = "playstack_logo", path = "resources/textures/1x/playstack-logo.png", px=1417,py=1417},
        {name = "localthunk_logo", path = "resources/textures/1x/localthunk-logo.png", px=1390,py=560}
    }

    --Load in all atli defined above
    for i=1, #self.animation_atli do
        self.ANIMATION_ATLAS[self.animation_atli[i].name] = {}
        self.ANIMATION_ATLAS[self.animation_atli[i].name].name = self.animation_atli[i].name
        self.ANIMATION_ATLAS[self.animation_atli[i].name].image = love.graphics.newImage(self.animation_atli[i].path, {mipmaps = true, dpiscale = self.SETTINGS.GRAPHICS.texture_scaling})
        self.ANIMATION_ATLAS[self.animation_atli[i].name].px = self.animation_atli[i].px
        self.ANIMATION_ATLAS[self.animation_atli[i].name].py = self.animation_atli[i].py
        self.ANIMATION_ATLAS[self.animation_atli[i].name].frames = self.animation_atli[i].frames
    end

    for i=1, #self.asset_atli do
        self.ASSET_ATLAS[self.asset_atli[i].name] = {}
        self.ASSET_ATLAS[self.asset_atli[i].name].name = self.asset_atli[i].name
        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})
        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
        self.ASSET_ATLAS[self.asset_atli[i].name].type = self.asset_atli[i].type
        self.ASSET_ATLAS[self.asset_atli[i].name].px = self.asset_atli[i].px
        self.ASSET_ATLAS[self.asset_atli[i].name].py = self.asset_atli[i].py
    end
    for i=1, #self.asset_images do
        self.ASSET_ATLAS[self.asset_images[i].name] = {}
        self.ASSET_ATLAS[self.asset_images[i].name].name = self.asset_images[i].name
        self.ASSET_ATLAS[self.asset_images[i].name].image = love.graphics.newImage(self.asset_images[i].path, {mipmaps = true, dpiscale = 1})
        self.ASSET_ATLAS[self.asset_images[i].name].type = self.asset_images[i].type
        self.ASSET_ATLAS[self.asset_images[i].name].px = self.asset_images[i].px
        self.ASSET_ATLAS[self.asset_images[i].name].py = self.asset_images[i].py
    end

    for _, v in pairs(G.I.SPRITE) do
        v:reset()
    end

    self.ASSET_ATLAS.Planet = self.ASSET_ATLAS.Tarot
    self.ASSET_ATLAS.Spectral = self.ASSET_ATLAS.Tarot
end

function Game:init_window(reset)
    --Initialize the window
    self.ROOM_PADDING_H= 0.7
    self.ROOM_PADDING_W = 1
    self.WINDOWTRANS = {
        x = 0, y = 0,
        w = self.TILE_W+2*self.ROOM_PADDING_W, 
        h = self.TILE_H+2*self.ROOM_PADDING_H
    }
    self.window_prev = {
        orig_scale = self.TILESCALE,
        w=self.WINDOWTRANS.w*self.TILESIZE*self.TILESCALE,
        h=self.WINDOWTRANS.h*self.TILESIZE*self.TILESCALE,
        orig_ratio = self.WINDOWTRANS.w*self.TILESIZE*self.TILESCALE/(self.WINDOWTRANS.h*self.TILESIZE*self.TILESCALE)}
    G.SETTINGS.QUEUED_CHANGE = G.SETTINGS.QUEUED_CHANGE or {}
    G.SETTINGS.QUEUED_CHANGE.screenmode = G.SETTINGS.WINDOW.screenmode
    
    G.FUNCS.apply_window_changes(true)
end

function Game:delete_run()
    if self.ROOM then
        remove_all(G.STAGE_OBJECTS[G.STAGE])
        self.load_shop_booster = nil
        self.load_shop_jokers = nil
        self.load_shop_vouchers = nil
        if self.buttons then self.buttons:remove(); self.buttons = nil end
        if self.deck_preview then self.deck_preview:remove(); self.deck_preview = nil end
        if self.shop and not G.GAME.USING_CODE then self.shop:remove(); self.shop = nil end
        if self.blind_select then self.blind_select:remove(); self.blind_select = nil end
        if self.booster_pack then self.booster_pack:remove(); self.booster_pack = nil end
        if self.MAIN_MENU_UI then self.MAIN_MENU_UI:remove(); self.MAIN_MENU_UI = nil end
        if self.SPLASH_FRONT then self.SPLASH_FRONT:remove(); self.SPLASH_FRONT = nil end
        if self.SPLASH_BACK then self.SPLASH_BACK:remove(); self.SPLASH_BACK = nil end
        if self.SPLASH_LOGO then self.SPLASH_LOGO:remove(); self.SPLASH_LOGO = nil end
        if self.GAME_OVER_UI then self.GAME_OVER_UI:remove(); self.GAME_OVER_UI = nil end
        if self.collection_alert then self.collection_alert:remove(); self.collection_alert = nil end
        if self.HUD then self.HUD:remove(); self.HUD = nil end
        if self.HUD_blind then self.HUD_blind:remove(); self.HUD_blind = nil end
        if self.HUD_tags then
            for k, v in pairs(self.HUD_tags) do
                v:remove()
            end
            self.HUD_tags = nil
        end
        if self.OVERLAY_MENU then self.OVERLAY_MENU:remove(); self.OVERLAY_MENU = nil end
        if self.OVERLAY_TUTORIAL then
            G.OVERLAY_TUTORIAL.Jimbo:remove()
            if G.OVERLAY_TUTORIAL.content then G.OVERLAY_TUTORIAL.content:remove() end
            G.OVERLAY_TUTORIAL:remove()
            G.OVERLAY_TUTORIAL = nil
        end
        for k, v in pairs(G) do
            if (type(v) == "table") and v.is and v:is(CardArea) then 
              G[k] = nil
            end
          end
          G.I.CARD = {}
    end
    G.VIEWING_DECK = nil
    G.E_MANAGER:clear_queue()
    G.CONTROLLER:mod_cursor_context_layer(-1000)
    G.CONTROLLER.focus_cursor_stack = {}
    G.CONTROLLER.focus_cursor_stack_level = 1
    if G.GAME then G.GAME.won = false end

    G.STATE = -1
end



function Game:save_progress()
    G.ARGS.save_progress = G.ARGS.save_progress or {}
    G.ARGS.save_progress.UDA = EMPTY(G.ARGS.save_progress.UDA)
    G.ARGS.save_progress.SETTINGS = G.SETTINGS
    G.ARGS.save_progress.PROFILE = G.PROFILES[G.SETTINGS.profile]

    for k, v in pairs(self.P_CENTERS) do
        G.ARGS.save_progress.UDA[k] = (v.unlocked and 'u' or '')..(v.discovered and 'd' or '')..(v.alerted and 'a' or '')
    end
    for k, v in pairs(self.P_BLINDS) do
        G.ARGS.save_progress.UDA[k] = (v.unlocked and 'u' or '')..(v.discovered and 'd' or '')..(v.alerted and 'a' or '')
    end
    for k, v in pairs(self.P_TAGS) do
        G.ARGS.save_progress.UDA[k] = (v.unlocked and 'u' or '')..(v.discovered and 'd' or '')..(v.alerted and 'a' or '')
    end
    for k, v in pairs(self.P_SEALS) do
        G.ARGS.save_progress.UDA[k] = (v.unlocked and 'u' or '')..(v.discovered and 'd' or '')..(v.alerted and 'a' or '')
    end

    G.FILE_HANDLER = G.FILE_HANDLER or {}
    G.FILE_HANDLER.progress = true
    G.FILE_HANDLER.update_queued = true
end

function Game:save_notify(card)
    G.SAVE_MANAGER.channel:push({
        type = 'save_notify',
        save_notify = card.key,
        profile_num = G.SETTINGS.profile
      })
end

function Game:save_settings()
    G.ARGS.save_settings = G.SETTINGS
    G.FILE_HANDLER = G.FILE_HANDLER or {}
    G.FILE_HANDLER.settings = true
    G.FILE_HANDLER.update_queued = true
end

function Game:save_metrics()
    G.ARGS.save_metrics = G.METRICS
    G.FILE_HANDLER = G.FILE_HANDLER or {}
    G.FILE_HANDLER.settings = true
    G.FILE_HANDLER.update_queued = true
end

function Game:prep_stage(new_stage, new_state, new_game_obj)
    for k, v in pairs(self.CONTROLLER.locks) do
        self.CONTROLLER.locks[k] = nil
    end
    if new_game_obj then self.GAME = self:init_game_object() end
    if Talisman and Talisman.igo then self.GAME = Talisman.igo(self.GAME) end
    self.STAGE = new_stage or self.STAGES.MAIN_MENU
    self.STATE = new_state or self.STATES.MENU
    self.STATE_COMPLETE = false
    self.SETTINGS.paused = false

    self.ROOM = Node{T={
        x = self.ROOM_PADDING_W,
        y = self.ROOM_PADDING_H,
        w = self.TILE_W,
        h = self.TILE_H}
    }
    self.ROOM.jiggle = 0
    self.ROOM.states.drag.can = false
    self.ROOM:set_container(self.ROOM)

    self.ROOM_ATTACH = Moveable{T={
        x = 0,
        y = 0,
        w = self.TILE_W,
        h = self.TILE_H}
    }
    self.ROOM_ATTACH.states.drag.can = false
    self.ROOM_ATTACH:set_container(self.ROOM)
    love.resize(love.graphics.getWidth( ),love.graphics.getHeight( ))
end

function Game:sandbox() 
    G.TIMERS.REAL = 0
    G.TIMERS.TOTAL = 0

    self:prep_stage(G.STAGES.SANDBOX, G.STATES.SANDBOX, true)
    self.GAME.selected_back = Back(G.P_CENTERS.b_red)

    ease_background_colour{new_colour = G.C.BLACK, contrast = 1}

    G.SANDBOX = {
        vort_time = 7,
        vort_speed = 0,
        col_op = {'RED','BLUE','GREEN','BLACK','L_BLACK','WHITE','EDITION','DARK_EDITION','ORANGE','PURPLE'},
        col1 = G.C.RED,col2 = G.C.BLUE,
        mid_flash = 0,
        joker_text = '',
        edition = 'base',
        tilt = 1,
        card_size = 1,
        base_size = {w = G.CARD_W, h = G.CARD_H},
        gamespeed = 0
    }

    if G.SPLASH_FRONT then G.SPLASH_FRONT:remove(); G.SPLASH_FRONT = nil end
    if G.SPLASH_BACK then G.SPLASH_BACK:remove(); G.SPLASH_BACK = nil end

    G.SPLASH_BACK = Sprite(-30, -13, G.ROOM.T.w+60, G.ROOM.T.h+22, G.ASSET_ATLAS["ui_"..(G.SETTINGS.colourblind_option and 2 or 1)], {x = 2, y = 0})
    G.SPLASH_BACK:set_alignment({
        major = G.ROOM_ATTACH,
        type = 'cm',
        offset = {x=0,y=0}
    })

    G.SPLASH_BACK:define_draw_steps({{
        shader = 'splash',
        send = {
            {name = 'time', ref_table = G.SANDBOX, ref_value = 'vort_time'},
            {name = 'vort_speed', val = 0.4},
            {name = 'colour_1', ref_table = G.SANDBOX, ref_value = 'col1'},
            {name = 'colour_2', ref_table = G.SANDBOX, ref_value = 'col2'},
            {name = 'mid_flash', ref_table = G.SANDBOX, ref_value = 'mid_flash'},
            {name = 'vort_offset', val = 0},
    }}})

    function create_UIBox_sandbox_controls()
        G.FUNCS.col1change = function(args)
          G.SANDBOX.col1 = G.C[args.to_val]
        end
        G.FUNCS.col2change = function(args)
          G.SANDBOX.col2 = G.C[args.to_val]
        end
        G.FUNCS.edition_change = function(args)
            G.SANDBOX.edition = args.to_val
            if G.SANDBOX.joker then G.SANDBOX.joker:set_edition({[args.to_val] = true}, true, true) end
          end
          G.FUNCS.pulseme = function(e)
            if math.random() > 0.998 then e.config.object:pulse(1) end
          end
        G.FUNCS.spawn_joker = function(e) G.FUNCS.rem_joker(); G.SANDBOX.joker = add_joker(G.SANDBOX.joker_text, G.SANDBOX.edition) end
        G.FUNCS.rem_joker = function(e) if G.SANDBOX.joker then G.SANDBOX.joker:remove(); G.SANDBOX.joker = nil end end 
        G.FUNCS.do_time = function(args) if args.to_val == 'PLAY' then G.SANDBOX.gamespeed = 1 else G.SANDBOX.gamespeed = 0 end end
        G.FUNCS.cb = function(rt) G.CARD_W = rt.ref_table[rt.ref_value]*G.SANDBOX.base_size.w; G.CARD_H = rt.ref_table[rt.ref_value]*G.SANDBOX.base_size.h end
        G.E_MANAGER:add_event(Event({
            func = (function()
                G.SANDBOX.file_reload_timer = (G.SANDBOX.file_reload_timer or 0)
                if G.SANDBOX.file_reload_timer < G.TIMERS.REAL then 
                    G.SANDBOX.file_reload_timer = G.SANDBOX.file_reload_timer+0.25
                end
                if G.SANDBOX.joker then G.SANDBOX.joker.ambient_tilt = G.SANDBOX.tilt end
                G.SANDBOX.vort_time = G.SANDBOX.vort_time + G.real_dt*G.SANDBOX.gamespeed
                G.CONTROLLER.lock_input = false
            end)
          }))
      
        local t = {
          n=G.UIT.ROOT, config = {align = "cm",colour = G.C.CLEAR}, nodes={   
            {n=G.UIT.R, config={align = "cm", padding = 0.05, r = 0.1, emboss = 0.1, colour = G.C.L_BLACK}, nodes={
              create_slider({label = 'Time', w = 2, h = 0.3, text_scale = 0.2, label_scale = 0.3, ref_table = G.SANDBOX, ref_value = 'vort_time', min = 0, max = 30}),
              create_option_cycle({options = {'PLAY','PAUSE'}, opt_callback = 'do_time', current_option = 1, colour = G.C.RED, w = 2, scale = 0.7}),
              create_slider({label = 'tilt', w = 2, h = 0.3, text_scale = 0.2, label_scale = 0.3, ref_table = G.SANDBOX, ref_value = 'tilt', min = 0, max = 3, decimal_places = 2}),
              create_slider({label = 'Card size', w = 2, h = 0.3, text_scale = 0.2, label_scale = 0.3, ref_table = G.SANDBOX, ref_value = 'card_size', min = 0.1, max = 3, callback = 'cb', decimal_places = 2}),
              create_option_cycle({options = G.SANDBOX.col_op, opt_callback = 'col1change', current_option = 1, colour = G.C.RED, w = 2, scale = 0.7}),
              create_option_cycle({options = G.SANDBOX.col_op, opt_callback = 'col2change', current_option = 2, colour = G.C.RED, w = 2, scale = 0.7}),
              {n=G.UIT.R, config={align = "cm", padding = 0.05}, nodes = {
                UIBox_button{ label = {"+"}, button = "spawn_joker", minw = 0.7, col = true},
                create_text_input({prompt_text = 'Joker key', extended_corpus = true, ref_table = G.SANDBOX, ref_value = 'joker_text', text_scale = 0.3, w = 1.5, h = 0.6}),
                UIBox_button{ label = {"-"}, button = "rem_joker", minw = 0.7, col = true},
              }},
              create_option_cycle({options = {'base', 'foil', 'holo', 'polychrome','negative'}, opt_callback = 'edition_change', current_option = 1, colour = G.C.RED, w = 2, scale = 0.7}),
            }}
          }}
        return t
      end


    G.SANDBOX.UI = UIBox{
        definition = create_UIBox_sandbox_controls(), 
        config = {align="cli", offset = {x=0,y=0}, major = G.ROOM_ATTACH, bond = 'Weak'}
    }
    
    G.SANDBOX.UI:recalculate(true)
end

function Game:splash_screen()
    --If the skip splash screen option is set, immediately go to the main menu here
    if G.SETTINGS.skip_splash == 'Yes' then 
        G:main_menu()
        return 
    end

    self:prep_stage(G.STAGES.MAIN_MENU, G.STATES.SPLASH, true)
    G.E_MANAGER:add_event(Event({
        func = (function()
            discover_card()
            return true
        end)
      }))


      G.E_MANAGER:add_event(Event({
        trigger = 'immediate',
        func = (function()
            G.TIMERS.TOTAL = 0
            G.TIMERS.REAL = 0
            --Prep the splash screen shaders for both the background(colour swirl) and the foreground(white flash), starting at black
            G.SPLASH_BACK = Sprite(-30, -13, G.ROOM.T.w+60, G.ROOM.T.h+22, G.ASSET_ATLAS["ui_1"], {x = 2, y = 0})
            G.SPLASH_BACK:define_draw_steps({{
                shader = 'splash',
                send = {
                    {name = 'time', ref_table = G.TIMERS, ref_value = 'REAL'},
                    {name = 'vort_speed', val = 1},
                    {name = 'colour_1', ref_table = G.C, ref_value = 'BLUE'},
                    {name = 'colour_2', ref_table = G.C, ref_value = 'WHITE'},
                    {name = 'mid_flash', val = 0},
                    {name = 'vort_offset', val = (2*90.15315131*os.time())%100000},
                }}})
            G.SPLASH_BACK:set_alignment({
                major = G.ROOM_ATTACH,
                type = 'cm',
                offset = {x=0,y=0}
            })
            G.SPLASH_FRONT = Sprite(0,-20, G.ROOM.T.w*2, G.ROOM.T.h*4, G.ASSET_ATLAS["ui_1"], {x = 2, y = 0})
            G.SPLASH_FRONT:define_draw_steps({{
                shader = 'flash',
                send = {
                    {name = 'time', ref_table = G.TIMERS, ref_value = 'REAL'},
                    {name = 'mid_flash', val = 1}
                }}})
            G.SPLASH_FRONT:set_alignment({
                major = G.ROOM_ATTACH,
                type = 'cm',
                offset = {x=0,y=0}
            })

            --spawn in splash card
            local SC = nil
            G.E_MANAGER:add_event(Event({trigger = 'after',delay = 0.2,func = (function()
                local SC_scale = 1.2
                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'])
                if Cryptid.enabled["Menu"] then
                	if Cryptid.enabled["M Jokers"] then
                 		local mcard = {}
                			for k, _ in pairs(Cryptid.M_jokers) do
                				if G.P_CENTERS[k] then
                					mcard[#mcard + 1] = k
                				end
                			end
                 		local option = math.random(#mcard)
                   		local chosenoption = mcard[option]
                       		if chosenoption == "j_cry_biggestm" or chosenoption == "j_cry_reverse" then --These don't render properly; replace these with loopy instead
                			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_cry_loopy'])
                   		else
                     			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[chosenoption])
                     		end
                  	else
                   		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'])
                	end
                end
                SC.T.y = G.ROOM.T.h/2 - SC_scale*G.CARD_H/2
                SC.ambient_tilt = 1
                SC.states.drag.can = false
                SC.states.hover.can = false
                SC.no_ui = true
                G.VIBRATION = G.VIBRATION + 2
                play_sound('whoosh1', 0.7, 0.2)
                play_sound('introPad1', 0.704, 0.6)
            return true;end)}))

            --dissolve fool card and start to fade in the vortex
            G.E_MANAGER:add_event(Event({trigger = 'after',delay = 1.8,func = (function() --|||||||||||
                SC:start_dissolve({G.C.WHITE, G.C.WHITE},true, 12, true)
                play_sound('magic_crumple', 1, 0.5)
                play_sound('splash_buildup', 1, 0.7)
            return true;end)}))

            --create all the cards and suck them in
            function make_splash_card(args)
                args = args or {}
                local angle = math.random()*2*3.14
                local card_size = (args.scale or 1.5)*(math.random() + 1)
                local card_pos = args.card_pos or {
                    x = (18 + card_size)*math.sin(angle),
                    y = (18 + card_size)*math.cos(angle)
                }
                local card = Card(  card_pos.x + G.ROOM.T.w/2 - G.CARD_W*card_size/2,
                                    card_pos.y + G.ROOM.T.h/2 - G.CARD_H*card_size/2,
                                    card_size*G.CARD_W, card_size*G.CARD_H, pseudorandom_element(G.P_CARDS), G.P_CENTERS.c_base)
                if Cryptid.enabled["Menu"] then card:set_ability(get_random_consumable('cry_splash',{"no_grc"},nil,nil,true), true, nil) end
                if math.random() > 0.8 then card.sprite_facing = 'back'; card.facing = 'back' end
                card.no_shadow = true
                card.states.hover.can = false
                card.states.drag.can = false
                card.vortex = true and not args.no_vortex
                card.T.r = angle
                return card, card_pos
            end

            G.vortex_time = G.TIMERS.REAL
            local temp_del = nil

            for i = 1, 200 do
                temp_del = temp_del or 3
                G.E_MANAGER:add_event(Event({
                    trigger = 'after',
                    blockable = false,
                    delay = temp_del,
                    func = (function()
                    local card, card_pos = make_splash_card({scale = 2 - i/300})
                    local speed = math.max(2. - i*0.005, 0.001)
                    ease_value(card.T, 'scale', -card.T.scale, nil, nil, nil, 1.*speed, 'elastic')
                    ease_value(card.T, 'x', -card_pos.x, nil, nil, nil, 0.9*speed)
                    ease_value(card.T, 'y', -card_pos.y, nil, nil, nil, 0.9*speed)
                    local temp_pitch = i*0.007 + 0.6
                    local temp_i = i
                    G.E_MANAGER:add_event(Event({
                        blockable = false,
                        func = (function()
                            if card.T.scale <= 0 then
                                if temp_i < 30 then 
                                    play_sound('whoosh1', temp_pitch + math.random()*0.05, 0.25*(1 - temp_i/50))
                                end

                                if temp_i == 15 then
                                    play_sound('whoosh_long',0.9, 0.7)
                                end
                                G.VIBRATION = G.VIBRATION + 0.1
                                card:remove()
                                return true
                            end
                        end)}))
                        return true
                    end)}))
                    temp_del = temp_del + math.max(1/(i), math.max(0.2*(170-i)/500, 0.016))
            end

            --when faded to white, spit out the 'Fool's' cards and slowly have them settle in to place
            G.E_MANAGER:add_event(Event({trigger = 'after',delay = 2.,func = (function()
                G.SPLASH_BACK:remove()
                G.SPLASH_BACK = G.SPLASH_FRONT
                G.SPLASH_FRONT = nil
                G:main_menu('splash')
            return true;end)}))
        return true
    end)
    }))
end

function Game:main_menu(change_context) --True if main menu is accessed from the splash screen, false if it is skipped or accessed from the game
    if change_context ~= 'splash' then 
        --Skip the timer to 14 seconds for all shaders that need it
        G.TIMERS.REAL = 12
        G.TIMERS.TOTAL = 12
    else
        --keep all sounds that came from splash screen
        RESET_STATES(G.STATES.MENU)
    end

    --Prepare the main menu, reset the default deck
    self:prep_stage(G.STAGES.MAIN_MENU, G.STATES.MENU, true)
    self.GAME.selected_back = Back(G.P_CENTERS.b_red)

    if (not G.SETTINGS.tutorial_complete) and G.SETTINGS.tutorial_progress.completed_parts['big_blind'] then G.SETTINGS.tutorial_complete = true end

    G.FUNCS.change_shadows{to_key = G.SETTINGS.GRAPHICS.shadows == 'On' and 1 or 2}

    ease_background_colour{new_colour = G.C.BLACK, contrast = 1}

    if G.SPLASH_FRONT then G.SPLASH_FRONT:remove(); G.SPLASH_FRONT = nil end
    if G.SPLASH_BACK then G.SPLASH_BACK:remove(); G.SPLASH_BACK = nil end
    G.SPLASH_BACK = Sprite(-30, -13, G.ROOM.T.w+60, G.ROOM.T.h+22, G.ASSET_ATLAS["ui_1"], {x = 2, y = 0})
    G.SPLASH_BACK:set_alignment({
        major = G.ROOM_ATTACH,
        type = 'cm',
        offset = {x=0,y=0}
    })
    local splash_args = {mid_flash = change_context == 'splash' and 1.6 or 0.}
    ease_value(splash_args, 'mid_flash', -(change_context == 'splash' and 1.6 or 0), nil, nil, nil, 4)

    G.SPLASH_BACK:define_draw_steps({{
        shader = 'splash',
        send = {
            {name = 'time', ref_table = G.TIMERS, ref_value = 'REAL_SHADER'},
            {name = 'vort_speed', val = 0.4},
            {name = 'colour_1', ref_table = G.C, ref_value = 'RED'},
            {name = 'colour_2', ref_table = G.C, ref_value = 'BLUE'},
            {name = 'mid_flash', ref_table = splash_args, ref_value = 'mid_flash'},
            {name = 'vort_offset', val = 0},
        }}})

    --Display the unlocked decks and cards from the previous run
    G.E_MANAGER:add_event(Event({
        trigger = 'immediate',
        func = (function()
            unlock_notify()
            return true
        end)
      }))

    
    local SC_scale = 1.1*(G.debug_splash_size_toggle and 0.8 or 1)
    local CAI = {
        TITLE_TOP_W = G.CARD_W,
        TITLE_TOP_H = G.CARD_H,
    }
    self.title_top = CardArea(
        0, 0,
        CAI.TITLE_TOP_W,CAI.TITLE_TOP_H,
        {card_limit = 1, type = 'title'})

    
    G.SPLASH_LOGO = Sprite(0, 0, 
        13*SC_scale, 
        13*SC_scale*(G.ASSET_ATLAS["balatro"].py/G.ASSET_ATLAS["balatro"].px),
        G.ASSET_ATLAS["balatro"], {x=0,y=0})

    G.SPLASH_LOGO:set_alignment({
        major = G.title_top,
        type = 'cm',
        bond = 'Strong',
        offset = {x=0,y=0}
    })
    G.SPLASH_LOGO:define_draw_steps({{
            shader = 'dissolve',
        }})

    G.SPLASH_LOGO.dissolve_colours = {G.C.WHITE, G.C.WHITE}
    G.SPLASH_LOGO.dissolve = 1   


    local replace_card = Card(self.title_top.T.x, self.title_top.T.y, 1.2*G.CARD_W*SC_scale, 1.2*G.CARD_H*SC_scale, G.P_CARDS.S_A, G.P_CENTERS.c_base)
    self.title_top:emplace(replace_card)

    replace_card:set_edition(G.P_CENTERS.e_cry_glitched and 'e_cry_glitched' or 'e_negative',true,true)
    replace_card:set_seal('Gold', true, true)
    replace_card.states.visible = false
    replace_card.no_ui = true
    replace_card.ambient_tilt = 0.0

    G.E_MANAGER:add_event(Event({
        trigger = 'after',
        delay = change_context == 'game' and 1.5 or 0,
        blockable = false,
        blocking = false,
        func = (function()
            if change_context == 'splash' then 
                replace_card.states.visible = true
                replace_card:start_materialize({G.C.WHITE,G.C.WHITE}, true, 2.5)
                play_sound('whoosh1', math.random()*0.1 + 0.3,0.3)
                play_sound('crumple'..math.random(1,5), math.random()*0.2 + 0.6,0.65)
            else
                replace_card.states.visible = true
                replace_card:start_materialize({G.C.WHITE,G.C.WHITE}, nil, 1.2)
            end
            G.VIBRATION = G.VIBRATION + 1
            return true
    end)}))

    G.E_MANAGER:add_event(Event({
        trigger = 'after',
        delay = change_context == 'splash' and 1.8 or change_context == 'game' and 2 or 0.5,
        blockable = false,
        blocking = false,
        func = (function()
            play_sound('magic_crumple'..(change_context == 'splash' and 2 or 3), (change_context == 'splash' and 1 or 1.3), 0.9)
            play_sound('whoosh1', 0.4, 0.8)
            ease_value(G.SPLASH_LOGO, 'dissolve', -1, nil, nil, nil, change_context == 'splash' and 2.3 or 0.9)
            G.VIBRATION = G.VIBRATION + 1.5
            return true
    end)}))

    delay(0.1 + (change_context == 'splash' and 2 or change_context == 'game' and 1.5 or 0))

    if replace_card and (G.P_CENTERS.j_blueprint.unlocked) then
        local viable_unlockables = {}
        for k, v in ipairs(self.P_LOCKED) do
            if (v.set == 'Voucher' or v.set == 'Joker') and not v.demo then 
                viable_unlockables[#viable_unlockables+1] = v
            end
        end
        if #viable_unlockables > 0 then 
            local card
            G.E_MANAGER:add_event(Event({
                trigger = 'after',
                delay = 4.04,
                func = (function()
                    card = Card(self.title_top.T.x, self.title_top.T.y, 1.2*G.CARD_W*SC_scale, 1.2*G.CARD_H*SC_scale, nil, pseudorandom_element(viable_unlockables) or self.P_CENTERS.j_joker)
                    card.no_ui = #viable_unlockables == 0
                    card.states.visible = false
                    replace_card.parent = nil
                    replace_card:start_dissolve({G.C.BLACK, G.C.ORANGE, G.C.RED, G.C.GOLD})
                    return true
            end)}))
            G.E_MANAGER:add_event(Event({
                trigger = 'after',
                delay = 1.04,
                func = (function()
                    card:start_materialize()
                    self.title_top:emplace(card)
                    return true
            end)}))
        end
    end

    G.E_MANAGER:add_event(Event({func = function() G.CONTROLLER.lock_input = false; return true end}))
    set_screen_positions()

    self.title_top:sort('order')
    self.title_top:set_ranks()
    self.title_top:align_cards()
    self.title_top:hard_set_cards()

    G.E_MANAGER:add_event(Event({
        trigger = 'after',
        delay = change_context == 'splash' and 4.05 or change_context == 'game' and 3 or 1.5,
        blockable = false,
        blocking = false,
        func = (function()
                set_main_menu_UI()
                return true
            end)
        }))

    --Do all career stat unlock checking here as well
    for k, v in pairs(G.PROFILES[G.SETTINGS.profile].career_stats) do
        check_for_unlock({type = 'career_stat', statname = k})
    end
    check_for_unlock({type = 'blind_discoveries'})
    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

    G.E_MANAGER:add_event(Event({
        blockable = false,
        func = function()
            set_discover_tallies()
            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
            set_profile_progress()
            G.REFRESH_ALERTS = true
        return true
        end
      }))

    --VERSION
    UIBox{
        definition = 
        {n=G.UIT.ROOT, config={align = "cm", colour = G.C.UI.TRANSPARENT_DARK}, nodes={
            {n=G.UIT.T, config={text = G.VERSION, scale = 0.3, colour = G.C.UI.TEXT_LIGHT}}
        }}, 
        config = {align="tri", offset = {x=0,y=0}, major = G.ROOM_ATTACH, bond = 'Weak'}
    }
end

function Game:demo_cta() --True if main menu is accessed from the splash screen, false if it is skipped or accessed from the game
    --G.TIMERS.REAL = 12
    --G.TIMERS.TOTAL = 12
    --Prepare the main menu, reset the default deck
    self:prep_stage(G.STAGES.MAIN_MENU, G.STATES.DEMO_CTA, true)

    self.GAME.selected_back = Back(G.P_CENTERS.b_red)

    G.FUNCS.change_shadows{to_key = G.SETTINGS.GRAPHICS.shadows == 'On' and 1 or 2}

    ease_background_colour{new_colour = G.C.BLACK, contrast = 1}

    if G.SPLASH_FRONT then G.SPLASH_FRONT:remove(); G.SPLASH_FRONT = nil end
    if G.SPLASH_BACK then G.SPLASH_BACK:remove(); G.SPLASH_BACK = nil end
    G.SPLASH_BACK = Sprite(-30, -13, G.ROOM.T.w+60, G.ROOM.T.h+22, G.ASSET_ATLAS["ui_1"], {x = 2, y = 0})
    G.SPLASH_BACK:set_alignment({
        major = G.ROOM_ATTACH,
        type = 'cm',
        offset = {x=0,y=0}
    })
    local splash_args = {mid_flash = 1.6}
    ease_value(splash_args, 'mid_flash', -1.6, nil, nil, nil, 4)

    G.SPLASH_BACK:define_draw_steps({{
        shader = 'splash',
        send = {
            {name = 'time', ref_table = G.TIMERS, ref_value = 'REAL_SHADER'},
            {name = 'vort_speed', val = 0.4},
            {name = 'colour_1', ref_table = G.C, ref_value = 'RED'},
            {name = 'colour_2', ref_table = G.C, ref_value = 'BLUE'},
            {name = 'mid_flash', ref_table = splash_args, ref_value = 'mid_flash'},
            {name = 'vort_offset', val = 0},
        }}})

    local SC_scale = 0.9*(G.debug_splash_size_toggle and 0.8 or 1)

    local CAI = {
        TITLE_TOP_W = G.CARD_W,
        TITLE_TOP_H = G.CARD_H,
    }
    self.title_top = CardArea(
        0, 0,
        CAI.TITLE_TOP_W,CAI.TITLE_TOP_H,
        {card_limit = 1, type = 'title'})

    
    G.SPLASH_LOGO = Sprite(0, 0, 
        13*SC_scale, 
        13*SC_scale*(G.ASSET_ATLAS["balatro"].py/G.ASSET_ATLAS["balatro"].px),
        G.ASSET_ATLAS["balatro"], {x=0,y=0})

    G.SPLASH_LOGO:set_alignment({
        major = G.title_top,
        type = 'cm',
        bond = 'Strong',
        offset = {x=0,y=0}
    })
    G.SPLASH_LOGO:define_draw_steps({{
            shader = 'dissolve',
        }})

    G.SPLASH_LOGO.dissolve_colours = {G.C.WHITE, G.C.WHITE}
    G.SPLASH_LOGO.dissolve = 1   

    local replace_card = Card(self.title_top.T.x, self.title_top.T.y, 1.2*G.CARD_W*SC_scale, 1.2*G.CARD_H*SC_scale, G.P_CARDS.S_A, G.P_CENTERS.c_base)
    self.title_top:emplace(replace_card)

    replace_card:set_edition(G.P_CENTERS.e_cry_glitched and 'e_cry_glitched' or 'e_negative',true,true)
    replace_card:set_seal('Gold', true, true)
    replace_card.states.visible = false
    replace_card.no_ui = true
    replace_card.ambient_tilt = 0.0

    G.E_MANAGER:add_event(Event({
        trigger = 'after',
        delay = 1.1,
        blockable = false,
        blocking = false,
        func = (function()
            replace_card.states.visible = true
            replace_card:start_materialize({G.C.WHITE,G.C.WHITE}, true, 2.5)
            play_sound('whoosh1', math.random()*0.1 + 0.3,0.3)
            play_sound('crumple'..math.random(1,5), math.random()*0.2 + 0.6,0.65)
            return true
    end)}))

    G.E_MANAGER:add_event(Event({
        trigger = 'after',
        delay = 1.8,
        blockable = false,
        blocking = false,
        func = (function()
            play_sound('magic_crumple'..(2), 1, 0.9)
            play_sound('whoosh1', 0.4, 0.8)
            ease_value(G.SPLASH_LOGO, 'dissolve', -1, nil, nil, nil, 2.3)
            return true
    end)}))

    delay(0.1 + 2)

    G.E_MANAGER:add_event(Event({func = function() G.CONTROLLER.lock_input = false; return true end}))
    set_screen_positions()

    self.title_top:sort('order')
    self.title_top:set_ranks()
    self.title_top:align_cards()
    self.title_top:hard_set_cards()

    local playstack = Sprite(0,0,1.7,1.7,G.ASSET_ATLAS["playstack_logo"], {x=0, y=0})
    playstack.states.drag.can = false
    local localthunk = Sprite(0,0,1*1390/560,1,G.ASSET_ATLAS["localthunk_logo"], {x=0, y=0})
    localthunk.states.drag.can = false

    self.MAIN_MENU_UI = UIBox{
        definition = {n=G.UIT.ROOT, config = {align = "cm",colour = G.C.CLEAR}, nodes={   
            {n=G.UIT.R, config={align = "cm", padding = 0.3}, nodes={
                {n=G.UIT.O, config={object = DynaText({string = {'Sign up for the next demo!'}, colours = {G.C.WHITE},shadow = true, rotate = true, float = true, bump = true, scale = 0.9, spacing = 1, pop_in = 4.5})}}
            }},
            {n=G.UIT.R, config={align = "cm", padding = 0.3}, nodes={
                {n=G.UIT.C, config={align = "cl", minw = 5, minh = 1}, nodes={
                    UIBox_button{button = 'go_to_menu', colour = G.C.ORANGE, minw = 2, minh = 1, label = {'BACK'}, scale = 0.4, col = true},
                }},
                UIBox_button{id = 'demo_cta_playbalatro', button = "go_to_playbalatro", colour = G.C.BLUE, minw = 7.65, minh = 1.95, label = {'PLAYBALATRO.COM'}, scale = 0.9, col = true},
                {n=G.UIT.C, config={align = "cr", minw = 5, minh = 1}, nodes={
                    {n=G.UIT.O, config={object = localthunk}},
                    {n=G.UIT.O, config={object = playstack}},
                }}
            }}
        }}, 
        config = {align="bmi", offset = {x=0,y=10}, major = G.ROOM_ATTACH, bond = 'Weak'}
    }
    self.MAIN_MENU_UI.states.visible = false
    
    G.E_MANAGER:add_event(Event({
        trigger = 'after',
        delay = 4.05,
        blockable = false,
        blocking = false,
        func = (function()
                self.MAIN_MENU_UI.states.visible = true
                self.MAIN_MENU_UI.alignment.offset.y = 0
                self.MAIN_MENU_UI:align_to_major()
                G.CONTROLLER:snap_to{node = self.MAIN_MENU_UI:get_UIE_by_ID('demo_cta_playbalatro')}
                return true
            end)
        }))
end

function Game:init_game_object()
    local cards_played = {}
    for _,v in ipairs(SMODS.Rank.obj_buffer) do
        cards_played[v] = { suits = {}, total = 0 }
    end
    local bosses_used = {}
    for k, v in pairs(G.P_BLINDS) do 
        if v.boss then bosses_used[k] = 0 end
    end
    return {
        won = false,
        round_scores = {
            furthest_ante = {label = 'Ante', amt = 0},
            furthest_round = {label = 'Round', amt = 0},
            hand = {label = 'Best Hand', amt = 0},
            poker_hand = {label = 'Most Played Hand', amt = 0},
            new_collection = {label = 'New Discoveries', amt = 0},
            cards_played = {label = 'Cards Played', amt = 0},
            cards_discarded = {label = 'Cards Discarded', amt = 0},
            times_rerolled = {label = 'Times Rerolled', amt = 0},
            cards_purchased = {label = 'Cards Purchased', amt = 0},
        },
        joker_usage = {},
        consumeable_usage = {},
        hand_usage = {},
        last_tarot_planet = nil,
        win_ante = 8,
        stake = 1,
        modifiers = {},
        starting_params = get_starting_params(),
        banned_keys = {},
        round = 0,
        probabilities = {
            normal = 1,
        },
        bosses_used = bosses_used,
        pseudorandom = {},
        starting_deck_size = 52,
        ecto_minus = 1,
        pack_size = 2,
        skips = 0,
        STOP_USE = 0,
        edition_rate = 1,
        joker_rate = 20,
        tarot_rate = 4,
        planet_rate = 4, 
        spectral_rate = 0,
        playing_card_rate = 0,
        consumeable_buffer = 0,
        joker_buffer = 0,
        discount_percent = 0,
        interest_cap = 25,
        interest_amount = 1,
        inflation = 0,
        hands_played = 0,
        unused_discards = 0,
        perishable_rounds = 5,
        rental_rate = 3,
        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,
        blind =  nil,
        chips = to_big(0),
        chips_text = '0',
        voucher_text = '',
        dollars = 0,
        max_jokers = 0,
        bankrupt_at = 0,
        current_boss_streak = 0,
        base_reroll_cost = 5,
        blind_on_deck = nil,
        sort = 'desc',
        previous_round = {
            dollars = 4
        },
        tags = {},
        tag_tally = 0,
        pool_flags = {},
        used_jokers = {},
        used_vouchers = {},
        cry_owned_vouchers = {},
        current_round = {
            current_hand = {
                chips = to_big(0),
                chip_text = '0',
                mult = 0,
                mult_text = '0',
                chip_total = 0,
                chip_total_text = '',
                                cry_asc_num = 0,
                                cry_asc_num_text = '',
                handname = "",
                hand_level = ''
            },
            used_packs = {},
            cards_flipped = 0,
            round_text = 'Round ',
            idol_card = {suit = 'Spades', rank = 'Ace'},
            mail_card = {rank = 'Ace'},
            ancient_card = {suit = 'Spades'},
            castle_card = {suit = 'Spades'},
            hands_left = 0,
            hands_played = 0,
            discards_left = 0,
            discards_used = 0,
            dollars = 0,
            reroll_cost = 5,
            reroll_cost_increase = 0,
            jokers_purchased = 0,
            free_rerolls = 0,
            round_dollars = 0,
            dollars_to_be_earned = '!!!',
            most_played_poker_hand = 'High Card',
        },
        round_resets = {
            hands = 1, 
            discards = 1,
            reroll_cost = 1,
            temp_reroll_cost = nil,
            temp_handsize = nil,
            ante = 1,
            ante_disp = number_format(1),
            blind_ante = 1,
            blind_states = {Small = 'Select', Big = 'Upcoming', Boss = 'Upcoming'},
            loc_blind_states = {Small = '', Big = '', Boss = ''},
            blind_choices = {Small = 'bl_small', Big = 'bl_big'},
            boss_rerolled = false,
        },
        round_bonus = {
            next_hands = 0,
            discards = 0,
        },
        shop = {
            joker_max = 2,
        },
            cards_played = cards_played,
            disabled_suits = {},
            disabled_ranks = {},
        hands = {
            ["Flush Five"] =        {visible = false,   order = 1, mult = 16,  chips = 160, s_mult = 16,  s_chips = 160, level = 1, l_mult = 3, l_chips = 50, played = 0, played_this_round = 0, example = {{'S_A', true},{'S_A', true},{'S_A', true},{'S_A', true},{'S_A', true}}},
            ["Flush House"] =       {visible = false,   order = 2, mult = 14,  chips = 140, s_mult = 14,  s_chips = 140, level = 1, l_mult = 4, l_chips = 40, played = 0, played_this_round = 0, example = {{'D_7', true},{'D_7', true},{'D_7', true},{'D_4', true},{'D_4', true}}},
            ["Five of a Kind"] =    {visible = false,   order = 3, mult = 12,  chips = 120, s_mult = 12,  s_chips = 120, level = 1, l_mult = 3, l_chips = 35, played = 0, played_this_round = 0, example = {{'S_A', true},{'H_A', true},{'H_A', true},{'C_A', true},{'D_A', true}}},
            ["Straight Flush"] =    {visible = true,    order = 4, mult = 8,   chips = 100, s_mult = 8,   s_chips = 100, level = 1, l_mult = 4, l_chips = 40, played = 0, played_this_round = 0, example = {{'S_Q', true},{'S_J', true},{'S_T', true},{'S_9', true},{'S_8', true}}},
            ["Four of a Kind"] =    {visible = true,    order = 5, mult = 7,   chips = 60,  s_mult = 7,   s_chips = 60,  level = 1, l_mult = 3, l_chips = 30, played = 0, played_this_round = 0, example = {{'S_J', true},{'H_J', true},{'C_J', true},{'D_J', true},{'C_3', false}}},
            ["Full House"] =        {visible = true,    order = 6, mult = 4,   chips = 40,  s_mult = 4,   s_chips = 40,  level = 1, l_mult = 2, l_chips = 25, played = 0, played_this_round = 0, example = {{'H_K', true},{'C_K', true},{'D_K', true},{'S_2', true},{'D_2', true}}},
            ["Flush"] =             {visible = true,    order = 7, mult = 4,   chips = 35,  s_mult = 4,   s_chips = 35,  level = 1, l_mult = 2, l_chips = 15, played = 0, played_this_round = 0, example = {{'H_A', true},{'H_K', true},{'H_T', true},{'H_5', true},{'H_4', true}}},
            ["Straight"] =          {visible = true,    order = 8, mult = 4,   chips = 30,  s_mult = 4,   s_chips = 30,  level = 1, l_mult = 3, l_chips = 30, played = 0, played_this_round = 0, example = {{'D_J', true},{'C_T', true},{'C_9', true},{'S_8', true},{'H_7', true}}},
            ["Three of a Kind"] =   {visible = true,    order = 9, mult = 3,   chips = 30,  s_mult = 3,   s_chips = 30,  level = 1, l_mult = 2, l_chips = 20, played = 0, played_this_round = 0, example = {{'S_T', true},{'C_T', true},{'D_T', true},{'H_6', false},{'D_5', false}}},
            ["Two Pair"] =          {visible = true,    order = 10,mult = 2,   chips = 20,  s_mult = 2,   s_chips = 20,  level = 1, l_mult = 1, l_chips = 20, played = 0, played_this_round = 0, example = {{'H_A', true},{'D_A', true},{'C_Q', false},{'H_4', true},{'C_4', true}}},
            ["Pair"] =              {visible = true,    order = 11,mult = 2,   chips = 10,  s_mult = 2,   s_chips = 10,  level = 1, l_mult = 1, l_chips = 15, played = 0, played_this_round = 0, example = {{'S_K', false},{'S_9', true},{'D_9', true},{'H_6', false},{'D_3', false}}},
            ["High Card"] =         {visible = true,    order = 12,mult = 1,   chips = 5,   s_mult = 1,   s_chips = 5,   level = 1, l_mult = 1, l_chips = 10, played = 0, played_this_round = 0, example = {{'S_A', true},{'D_Q', false},{'D_9', false},{'C_4', false},{'D_3', false}}},
        }
    }
end

function Game:start_run(args)
    args = args or {}

    local saveTable = args.savetext or nil
    G.SAVED_GAME = nil

    self:prep_stage(G.STAGES.RUN, saveTable and saveTable.STATE or G.STATES.BLIND_SELECT)
    
    G.STAGE = G.STAGES.RUN
    if saveTable then 
        check_for_unlock({type = 'continue_game'})
    end

    G.STATE_COMPLETE = false
    G.RESET_BLIND_STATES = true

    if not saveTable then ease_background_colour_blind(G.STATE, 'Small Blind')
    else ease_background_colour_blind(G.STATE, saveTable.BLIND.name:gsub("%s+", "") ~= '' and saveTable.BLIND.name or 'Small Blind') end

    local selected_back = saveTable and saveTable.BACK.name or (args.challenge and args.challenge.deck and args.challenge.deck.type) or (self.GAME.viewed_back and self.GAME.viewed_back.name) or self.GAME.selected_back and self.GAME.selected_back.name or 'Red Deck'
    selected_back = get_deck_from_name(selected_back)
    self.GAME = saveTable and saveTable.GAME or self:init_game_object()
    if Talisman and Talisman.igo then self.GAME = Talisman.igo(self.GAME) end
    Handy.UI.init()
    self.GAME.modifiers = self.GAME.modifiers or {}
    self.GAME.stake = args.stake or self.GAME.stake or 1
    self.GAME.STOP_USE = 0
    self.GAME.selected_back = Back(selected_back)
    self.GAME.selected_back_key = selected_back

    G.C.UI_CHIPS[1], G.C.UI_CHIPS[2], G.C.UI_CHIPS[3], G.C.UI_CHIPS[4] = G.C.BLUE[1], G.C.BLUE[2], G.C.BLUE[3], G.C.BLUE[4]
    G.C.UI_MULT[1], G.C.UI_MULT[2], G.C.UI_MULT[3], G.C.UI_MULT[4] = G.C.RED[1], G.C.RED[2], G.C.RED[3], G.C.RED[4]

    if not saveTable then 
        if false then
        if self.GAME.stake >= 2 then 
            self.GAME.modifiers.no_blind_reward = self.GAME.modifiers.no_blind_reward or {}
            self.GAME.modifiers.no_blind_reward.Small = true
        end
        if self.GAME.stake >= 3 then self.GAME.modifiers.scaling = 2 end
        if self.GAME.stake >= 4 then self.GAME.modifiers.enable_eternals_in_shop = true end
        if self.GAME.stake >= 5 then self.GAME.starting_params.discards = self.GAME.starting_params.discards - 1 end
        if self.GAME.stake >= 6 then self.GAME.modifiers.scaling = 3 end
        if self.GAME.stake >= 7 then self.GAME.modifiers.enable_perishables_in_shop = true end
        if self.GAME.stake >= 8 then self.GAME.modifiers.enable_rentals_in_shop = true end
        end SMODS.setup_stake(self.GAME.stake)

        self.GAME.selected_back:apply_to_run()

        if args.challenge then
            self.GAME.challenge = args.challenge.id
            self.GAME.challenge_tab = args.challenge
            local _ch = args.challenge
            if _ch.jokers then
                for k, v in ipairs(_ch.jokers) do
                    G.E_MANAGER:add_event(Event({
                        func = function()
                            local _joker = add_joker(v.id, v.edition, k ~= 1)
                            if v.eternal then _joker:set_eternal(true) end
                            if v.pinned then _joker.pinned = true end
                        return true
                        end
                    }))
                end
            end
            if _ch.consumeables then
                for k, v in ipairs(_ch.consumeables) do
                    G.E_MANAGER:add_event(Event({
                        func = function()
                            add_joker(v.id, nil, k ~= 1)
                        return true
                        end
                    }))
                end
            end
            if _ch.vouchers then
                for k, v in ipairs(_ch.vouchers) do
                    G.GAME.used_vouchers[v.id] = true
                    G.GAME.cry_owned_vouchers[v.id] = true
                    G.E_MANAGER:add_event(Event({
                        func = function()
                            G.GAME.starting_voucher_count = (G.GAME.starting_voucher_count or 0) + 1
                            Card.apply_to_run(nil, G.P_CENTERS[v.id])
                        return true
                        end
                    }))
                end
            end
            if _ch.rules then
                if _ch.rules.modifiers then
                    for k, v in ipairs(_ch.rules.modifiers) do
                        self.GAME.starting_params[v.id] = v.value
                    end
                end
                if _ch.rules.custom then
                    for k, v in ipairs(_ch.rules.custom) do
                        if v.id == 'no_reward' then 
                            self.GAME.modifiers.no_blind_reward = self.GAME.modifiers.no_blind_reward or {}
                            self.GAME.modifiers.no_blind_reward.Small = true
                            self.GAME.modifiers.no_blind_reward.Big = true
                            self.GAME.modifiers.no_blind_reward.Boss = true
                        elseif v.id == 'no_reward_specific' then
                            self.GAME.modifiers.no_blind_reward = self.GAME.modifiers.no_blind_reward or {}
                            self.GAME.modifiers.no_blind_reward[v.value] = true
                        elseif v.value then
                            self.GAME.modifiers[v.id] = v.value
                        elseif v.id == 'no_shop_jokers' then 
                            self.GAME.joker_rate = 0
                        else
                            self.GAME.modifiers[v.id] = true 
                        end
                    end
                end
            end
            if _ch.restrictions then
                if _ch.restrictions.banned_cards then
                    for k, v in ipairs(_ch.restrictions.banned_cards) do
                        G.GAME.banned_keys[v.id] = true
                        if v.ids then
                            for kk, vv in ipairs(v.ids) do
                                G.GAME.banned_keys[vv] = true
                            end
                        end
                    end
                end
                if _ch.restrictions.banned_tags then
                    for k, v in ipairs(_ch.restrictions.banned_tags) do
                        G.GAME.banned_keys[v.id] = true
                    end
                end
                if _ch.restrictions.banned_other then
                    for k, v in ipairs(_ch.restrictions.banned_other) do
                        G.GAME.banned_keys[v.id] = true
                    end
                end
            end
        end

        self.GAME.round_resets.hands = self.GAME.starting_params.hands
        self.GAME.round_resets.discards = self.GAME.starting_params.discards
        self.GAME.round_resets.reroll_cost = self.GAME.starting_params.reroll_cost
        self.GAME.dollars = self.GAME.starting_params.dollars
        self.GAME.base_reroll_cost = self.GAME.starting_params.reroll_cost
        self.GAME.round_resets.reroll_cost = self.GAME.base_reroll_cost
        self.GAME.current_round.reroll_cost = self.GAME.base_reroll_cost
    end

    G.GAME.chips_text = ''
    G.GAME.cry_voucher_centers = {}
    for k, v in pairs(G.P_CENTERS) do
    	if v.set == 'Voucher' then
    		G.GAME.cry_voucher_centers[k] = {config = {}}
    		G.GAME.cry_voucher_centers[k].config = copy_table(v.config)
    	end
    end

    if not saveTable then
        if args.seed then self.GAME.seeded = true end
        self.GAME.pseudorandom.seed = args.seed or (not (G.SETTINGS.tutorial_complete or G.SETTINGS.tutorial_progress.completed_parts['big_blind']) and "TUTORIAL") or generate_starting_seed()
    end

    for k, v in pairs(self.GAME.pseudorandom) do if v == 0 then self.GAME.pseudorandom[k] = pseudohash(k..self.GAME.pseudorandom.seed) end end
    self.GAME.pseudorandom.hashed_seed = pseudohash(self.GAME.pseudorandom.seed)
    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 * cry_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 * cry_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 * cry_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 * cry_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

    G:save_settings()

    if not self.GAME.round_resets.blind_tags then
        self.GAME.round_resets.blind_tags = {}
    end

    if not saveTable then
        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
        self.GAME.round_resets.blind_choices.Boss = get_new_boss()
        if not self.GAME.modifiers.cry_no_vouchers then
            if not G.GAME.modifiers.cry_voucher_restock_antes or G.GAME.round_resets.ante % G.GAME.modifiers.cry_voucher_restock_antes == 0 then
                self.GAME.current_round.voucher = G.SETTINGS.tutorial_progress and G.SETTINGS.tutorial_progress.forced_voucher or get_next_voucher_key()
            end
        else
            very_fair_quip = pseudorandom_element(G.localization.misc.very_fair_quips, pseudoseed("cry_very_fair"))
        end
        self.GAME.current_round.cry_voucher_edition = cry_get_next_voucher_edition()
        self.GAME.current_round.cry_voucher_stickers = cry_get_next_voucher_stickers()
        self.GAME.round_resets.blind_tags.Small = G.SETTINGS.tutorial_progress and G.SETTINGS.tutorial_progress.forced_tags and G.SETTINGS.tutorial_progress.forced_tags[1] or get_next_tag_key()
        self.GAME.round_resets.blind_tags.Big = G.SETTINGS.tutorial_progress and G.SETTINGS.tutorial_progress.forced_tags and G.SETTINGS.tutorial_progress.forced_tags[2] or get_next_tag_key()
    else
        if self.GAME.round_resets.blind and self.GAME.round_resets.blind.key then 
            self.GAME.round_resets.blind = G.P_BLINDS[self.GAME.round_resets.blind.key]
        end
    end
    G.CONTROLLER.locks.load = true
    G.E_MANAGER:add_event(Event({
        no_delete = true,
        trigger = 'after',
        blocking = false,blockable = false,
        delay = 3.5,
        timer = 'TOTAL',
        func = function()
            G.CONTROLLER.locks.load = nil
          return true
        end
      }))

    if saveTable and saveTable.ACTION then
        G.E_MANAGER:add_event(Event({delay = 0.5, trigger = 'after', blocking = false,blockable = false,func = (function() 
            G.E_MANAGER:add_event(Event({func = (function() 
                G.E_MANAGER:add_event(Event({func = (function() 
                    for k, v in pairs(G.I.CARD) do
                        if v.sort_id == saveTable.ACTION.card then
                            G.FUNCS.use_card({config = {ref_table = v}}, nil, true)
                        end
                    end
                            return true
                        end)
                    }))
                        return true
                    end)
                }))
                return true
            end)
        }))
    end

    local CAI = {
        discard_W = G.CARD_W,
        discard_H = G.CARD_H,
        deck_W = G.CARD_W*1.1,
        deck_H = 0.95*G.CARD_H,
        hand_W = 6*G.CARD_W,
        hand_H = 0.95*G.CARD_H,
        play_W = 5.3*G.CARD_W,
        play_H = 0.95*G.CARD_H,
        joker_W = 4.9*G.CARD_W,
        joker_H = 0.95*G.CARD_H,
        consumeable_W = 2.3*G.CARD_W,
        consumeable_H = 0.95*G.CARD_H
    }


    if not G.GAME.modifiers.cry_beta then
    self.consumeables = CardArea(
        0, 0,
        CAI.consumeable_W,
        CAI.consumeable_H, 
        {card_limit = self.GAME.starting_params.consumable_slots, type = 'joker', highlight_limit = 1e100})

    self.jokers = CardArea(
        0, 0,
        CAI.joker_W,
        CAI.joker_H, 
        {card_limit = self.GAME.starting_params.joker_slots, type = 'joker', highlight_limit = 1e100})

    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
    self.discard = CardArea(
        0, 0,
        CAI.discard_W,CAI.discard_H,
        {card_limit = 1e308, type = 'discard'})
    self.vouchers = CardArea(
        G.discard.T.x, G.discard.T.y,
        G.discard.T.w, G.discard.T.h,
        { type = "discard", card_limit = 1e308 }
    )
    self.deck = CardArea(
        0, 0,
        CAI.deck_W,CAI.deck_H, 
        {card_limit = 52, type = 'deck'})
    self.hand = CardArea(
        0, 0,
        CAI.hand_W,CAI.hand_H, 
        {card_limit = self.GAME.starting_params.hand_size, type = 'hand'})
    self.play = CardArea(
        0, 0,
        CAI.play_W,CAI.play_H, 
        {card_limit = 5, type = 'play'})
    
    G.playing_cards = {}

    set_screen_positions()

    G.SPLASH_BACK = Sprite(-30, -6, G.ROOM.T.w+60, G.ROOM.T.h+12, G.ASSET_ATLAS["ui_1"], {x = 2, y = 0})
    G.SPLASH_BACK:set_alignment({
        major = G.play,
        type = 'cm',
        bond = 'Strong',
        offset = {x=0,y=0}
    })

    G.ARGS.spin = {
        amount = 0,
        real = 0,
        eased = 0
    }

    G.SPLASH_BACK:define_draw_steps({{
        shader = 'background',
        send = {
            {name = 'time', ref_table = G.TIMERS, ref_value = 'REAL_SHADER'},
            {name = 'spin_time', ref_table = G.TIMERS, ref_value = 'BACKGROUND'},
            {name = 'colour_1', ref_table = G.C.BACKGROUND, ref_value = 'C'},
            {name = 'colour_2', ref_table = G.C.BACKGROUND, ref_value = 'L'},
            {name = 'colour_3', ref_table = G.C.BACKGROUND, ref_value = 'D'},
            {name = 'contrast', ref_table = G.C.BACKGROUND, ref_value = 'contrast'},
            {name = 'spin_amount', ref_table = G.ARGS.spin, ref_value = 'amount'}
        }}})
    
    G.E_MANAGER:add_event(Event({
        trigger = 'immediate',
        blocking = false,
        blockable = false,
        func = (function() 
            local _dt = G.ARGS.spin.amount > G.ARGS.spin.eased and G.real_dt*2. or 0.3*G.real_dt
            local delta = G.ARGS.spin.real - G.ARGS.spin.eased
            if math.abs(delta) > _dt then delta = delta*_dt/math.abs(delta) end
            G.ARGS.spin.eased = G.ARGS.spin.eased + delta
            G.ARGS.spin.amount = _dt*(G.ARGS.spin.eased) + (1 - _dt)*G.ARGS.spin.amount
            G.TIMERS.BACKGROUND = G.TIMERS.BACKGROUND - 60*(G.ARGS.spin.eased - G.ARGS.spin.amount)*_dt
        end)
    }))

    if saveTable then 
        local cardAreas = saveTable.cardAreas
        for k, v in pairs(cardAreas) do
            if G[k] then G[k]:load(v)
            else
            G['load_'..k] = v
            print("ERROR LOADING GAME: Card area '"..k.."' not instantiated before load") end
        end

        for k, v in pairs(G.I.CARD) do
            if v.playing_card then
                table.insert(G.playing_cards, v)
            end
        end
        for k, v in pairs(G.I.CARDAREA) do
            v:align_cards()
            v:hard_set_cards()
        end
        table.sort(G.playing_cards, function (a, b) return a.playing_card > b.playing_card end )
    else
        local card_protos = nil
        local _de = nil
        if args.challenge and args.challenge.deck then
            _de = args.challenge.deck
        end

        if _de and _de.cards then
            card_protos = _de.cards
        end

        if not card_protos then 
            card_protos = {}
            for k, v in pairs(self.P_CARDS) do
                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
                local _ = nil
                if self.GAME.starting_params.erratic_suits_and_ranks then
                    v, k = pseudorandom_element(G.P_CARDS, pseudoseed('erratic'), {starting_deck = true})
                end
                local _r, _s = SMODS.Ranks[v.value].card_key, SMODS.Suits[v.suit].card_key
                local keep, _e, _d, _g = true, nil, nil, nil
                if _de then
                    if _de.yes_ranks and not _de.yes_ranks[_r] then keep = false end
                    if _de.no_ranks and _de.no_ranks[_r] then keep = false end
                    if _de.yes_suits and not _de.yes_suits[_s] then keep = false end
                    if _de.no_suits and _de.no_suits[_s] then keep = false end
                    if _de.enhancement then _e = _de.enhancement end
                    if _de.edition then _d = _de.edition end
                    if _de.gold_seal then _g = _de.gold_seal end
                end

                if self.GAME.starting_params.no_faces and SMODS.Ranks[v.value].face then keep = false end
                
                if keep then card_protos[#card_protos+1] = {s=_s,r=_r,e=_e,d=_d,g=_g} end
                ::continue::
            end
        end 

        if self.GAME.starting_params.extra_cards then 
            for k, v in pairs(self.GAME.starting_params.extra_cards) do
                card_protos[#card_protos+1] = v
            end
        end

        table.sort(card_protos, function (a, b) return 
            ((a.s or '')..(a.r or '')..(a.e or '')..(a.d or '')..(a.g or '')) < 
            ((b.s or '')..(b.r or '')..(b.e or '')..(b.d or '')..(b.g or '')) end)

        for k, v in ipairs(card_protos) do
            card_from_control(v)
        end

        if G.GAME.modifiers.cry_ccd then
            for k, v in pairs(G.playing_cards) do
                v:set_ability(get_random_consumable('cry_ccd',{"no_doe", "no_grc"}, nil, nil, true), true, nil)
            end
        end
        self.GAME.starting_deck_size = #G.playing_cards
    end

    delay(0.5)

    if not saveTable then
        G.GAME.current_round.discards_left = G.GAME.round_resets.discards
        G.GAME.current_round.hands_left = G.GAME.round_resets.hands
        self.deck:shuffle()
        self.deck:hard_set_T()
        reset_idol_card()
        reset_mail_rank()
        self.GAME.current_round.ancient_card.suit = nil
        reset_ancient_card()
        reset_castle_card()        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
    end

    G.GAME.blind = Blind(0,0,2, 1)
    self.deck:align_cards()
    self.deck:hard_set_cards()
    
    self.HUD = UIBox{
        definition = create_UIBox_HUD(),
        config = {align=('cli'), offset = {x=-0.7,y=0},major = G.ROOM_ATTACH}
    }
    self.HUD_blind = UIBox{
        definition = create_UIBox_HUD_blind(),
        config = {major = G.HUD:get_UIE_by_ID('row_blind_bottom'), align = 'bmi', offset = {x=0,y=-10}, bond = 'Weak'}
    }
    self.HUD_tags = {}

    G.hand_text_area = {
        chips = self.HUD:get_UIE_by_ID('hand_chips'),
        mult = self.HUD:get_UIE_by_ID('hand_mult'),
        ante = self.HUD:get_UIE_by_ID('ante_UI_count'),
        round = self.HUD:get_UIE_by_ID('round_UI_count'),
        chip_total = self.HUD:get_UIE_by_ID('hand_chip_total'),
        handname = self.HUD:get_UIE_by_ID('hand_name'),
        hand_level = self.HUD:get_UIE_by_ID('hand_level'),
        game_chips = self.HUD:get_UIE_by_ID('chip_UI_count'),
        blind_chips = self.HUD_blind:get_UIE_by_ID('HUD_blind_count'),
        blind_spacer = self.HUD:get_UIE_by_ID('blind_spacer')
    }

    check_and_set_high_score('most_money', G.GAME.dollars)

    if saveTable then 
        G.GAME.blind:load(saveTable.BLIND)
        G.GAME.tags = {}
        local tags = saveTable.tags or {}
        for k, v in ipairs(tags) do
            local _tag = Tag('tag_uncommon')
            _tag:load(v)
            add_tag(_tag, nil, true)
        end
    else
        G.GAME.blind:set_blind(nil, nil, true)
        reset_blinds()
    end

    G.FUNCS.blind_chip_UI_scale(G.hand_text_area.blind_chips)
     
    self.HUD:recalculate()

    G.E_MANAGER:add_event(Event({
        trigger = 'immediate',
        func = (function()
            unlock_notify()
            return true
        end)
      }))
    
end

function Game:update(dt)
    nuGC(nil, nil, true)

    G.MAJORS = 0
    G.MINORS = 0

    G.FRAMES.MOVE = G.FRAMES.MOVE + 1
                timer_checkpoint('start->discovery', 'update')
    if not G.SETTINGS.tutorial_complete then G.FUNCS.tutorial_controller() end
                timer_checkpoint('tallies', 'update')
    modulate_sound(dt)
                timer_checkpoint('sounds', 'update')
    update_canvas_juice(dt)
                timer_checkpoint('canvas and juice', 'update')
    --Smooth out the dts to avoid any big jumps
    self.TIMERS.REAL = self.TIMERS.REAL + dt
    self.TIMERS.REAL_SHADER = G.SETTINGS.reduced_motion and 300 or self.TIMERS.REAL
    self.TIMERS.UPTIME = self.TIMERS.UPTIME + dt
    self.SETTINGS.DEMO.total_uptime = (self.SETTINGS.DEMO.total_uptime or 0) + dt
    self.TIMERS.BACKGROUND = self.TIMERS.BACKGROUND + dt*(G.ARGS.spin and G.ARGS.spin.amount or 0)
    self.real_dt = dt

    if self.real_dt > 0.05 then print('LONG DT @ '..math.floor(G.TIMERS.REAL)..': '..self.real_dt) end
    if not G.fbf or G.new_frame then
        G.new_frame = false

    set_alerts()
                timer_checkpoint('alerts', 'update')

    local http_resp = G.HTTP_MANAGER.in_channel:pop()
    if http_resp then
        G.ARGS.HIGH_SCORE_RESPONSE = http_resp
    end


    if G.SETTINGS.paused then dt = 0 end

        if G.STATE ~= G.ACC_state then G.ACC = 0 end
        G.ACC_state = G.STATE

        if (G.STATE == G.STATES.HAND_PLAYED) or (G.STATE == G.STATES.NEW_ROUND) then 
            G.ACC = math.min((G.ACC or 0) + dt*0.2*self.SETTINGS.GAMESPEED, 16)
             elseif Handy.insta_cash_out.is_skipped then G.ACC = 999 
        else
            G.ACC = 0
        end

        self.SPEEDFACTOR = (G.STAGE == G.STAGES.RUN and not G.SETTINGS.paused and not G.screenwipe) and self.SETTINGS.GAMESPEED or 1
        self.SPEEDFACTOR = self.SPEEDFACTOR + math.max(0, math.abs(G.ACC) - 2)
        self.SPEEDFACTOR = self.SPEEDFACTOR * Handy.speed_multiplier.value or 1

        self.TIMERS.TOTAL = self.TIMERS.TOTAL + dt*(self.SPEEDFACTOR)

        self.C.DARK_EDITION[1] = 0.6+0.2*math.sin(self.TIMERS.REAL*1.3)
        self.C.DARK_EDITION[3] = 0.6+0.2*(1- math.sin(self.TIMERS.REAL*1.3))
        self.C.DARK_EDITION[2] = math.min(self.C.DARK_EDITION[3], self.C.DARK_EDITION[1])

        self.C.EDITION[1] = 0.7+0.2*(1+math.sin(self.TIMERS.REAL*1.5 + 0))
        self.C.EDITION[3] = 0.7+0.2*(1+math.sin(self.TIMERS.REAL*1.5 + 3))
        self.C.EDITION[2] = 0.7+0.2*(1+math.sin(self.TIMERS.REAL*1.5 + 6))
        for k, v in pairs(SMODS.Rarities) do
            if v.gradient and type(v.gradient) == "function" then v:gradient(dt) end
        end

        
        self.E_MANAGER:update(self.real_dt)
                    timer_checkpoint('e_manager', 'update')

        if G.GAME.blind and G.boss_throw_hand and self.STATE == self.STATES.SELECTING_HAND then
            if not self.boss_warning_text then 
                self.boss_warning_text = UIBox{
                    definition = 
                      {n=G.UIT.ROOT, config = {align = 'cm', colour = G.C.CLEAR, padding = 0.2}, nodes={
                        {n=G.UIT.R, config = {align = 'cm', maxw = 1}, nodes={
                            {n=G.UIT.O, config={object = DynaText({scale = 0.7, string = localize('ph_unscored_hand'), maxw = 9, colours = {G.C.WHITE},float = true, shadow = true, silent = true, pop_in = 0, pop_in_rate = 6})}},
                        }},
                        {n=G.UIT.R, config = {align = 'cm', maxw = 1}, nodes={
                            {n=G.UIT.O, config={object = DynaText({scale = 0.6, string = G.GAME.blind:get_loc_debuff_text(), maxw = 9, colours = {G.C.WHITE},float = true, shadow = true, silent = true, pop_in = 0, pop_in_rate = 6})}},
                        }}
                    }}, 
                    config = {
                        align = 'cm',
                        offset ={x=0,y=-3.1}, 
                        major = G.play,
                      }
                  }
                  self.boss_warning_text.attention_text = true
                  self.boss_warning_text.states.collide.can = false
                  G.GAME.blind.children.animatedSprite:juice_up(0.05, 0.02)
                  play_sound('chips1', math.random()*0.1 + 0.55, 0.12)
            end
        else
            G.boss_throw_hand = nil
            if self.boss_warning_text then 
                self.boss_warning_text:remove()
                self.boss_warning_text = nil
            end
        end


        if G.GAME.USING_RUN then self.STATE = self.STATES.SHOP end
        if self.STATE == self.STATES.SELECTING_HAND then
            if (not G.hand.cards[1]) and G.deck.cards[1] then 
                G.STATE = G.STATES.DRAW_TO_HAND
                G.STATE_COMPLETE = false
            else
                self:update_selecting_hand(dt)
            end
        end

        if self.STATE == self.STATES.SHOP then 
            self:update_shop(dt)
        end

        if self.STATE == self.STATES.PLAY_TAROT then 
            self:update_play_tarot(dt)
        end

        if self.STATE == self.STATES.HAND_PLAYED then 
            self:update_hand_played(dt)
        end

        if self.STATE == self.STATES.DRAW_TO_HAND then 
            self:update_draw_to_hand(dt)
        end

        if self.STATE == self.STATES.NEW_ROUND then
            self:update_new_round(dt)
        end

        if self.STATE == self.STATES.BLIND_SELECT then
            self:update_blind_select(dt)
        end

        if self.STATE == self.STATES.ROUND_EVAL then
            self:update_round_eval(dt)
        end

        if G.STATE == G.STATES.SMODS_BOOSTER_OPENED then
            SMODS.OPENED_BOOSTER.config.center:update_pack(dt)
        end
        
        if self.STATE == self.STATES.TAROT_PACK then
            self:update_arcana_pack(dt)
        end

        if self.STATE == self.STATES.SPECTRAL_PACK then
            self:update_spectral_pack(dt)
        end

        if self.STATE == self.STATES.STANDARD_PACK then
            self:update_standard_pack(dt)
        end

        if self.STATE == self.STATES.BUFFOON_PACK then
            self:update_buffoon_pack(dt)
        end

        if self.STATE == self.STATES.PLANET_PACK then
            self:update_celestial_pack(dt)
        end

        if self.STATE == self.STATES.GAME_OVER then
            self:update_game_over(dt)
        end

        if self.STATE == self.STATES.MENU then
            self:update_menu(dt)
        end
                    timer_checkpoint('states', 'update')
        --animate all animated objects
        remove_nils(self.ANIMATIONS)

        for k, v in pairs(self.ANIMATIONS) do
            v:animate(self.real_dt*self.SPEEDFACTOR)
        end
                    timer_checkpoint('animate', 'update')

        --move and update all other moveables
        G.exp_times.xy = math.exp(-50*self.real_dt)
        G.exp_times.scale = math.exp(-60*self.real_dt)
        G.exp_times.r = math.exp(-190*self.real_dt)
        
        local move_dt = math.min(1/20, self.real_dt)

        G.exp_times.max_vel = 70*move_dt
        
        for k, v in pairs(self.MOVEABLES) do
            if v.FRAME.MOVE < G.FRAMES.MOVE then v:move(move_dt) end
        end
                    timer_checkpoint('move', 'update')
        
        for k, v in pairs(self.MOVEABLES) do
            v:update(dt*self.SPEEDFACTOR)
            v.states.collide.is = false
        end
                    timer_checkpoint('update', 'update')
    end
    
    self.CONTROLLER:update(self.real_dt) 

    --update loc strings if needed
    if G.prev_small_state ~= G.GAME.round_resets.blind_states.Small or
    G.prev_large_state ~= G.GAME.round_resets.blind_states.Big or
    G.prev_boss_state ~= G.GAME.round_resets.blind_states.Boss or G.RESET_BLIND_STATES then 
        G.RESET_BLIND_STATES = nil
        G.prev_small_state = G.GAME.round_resets.blind_states.Small
        G.prev_large_state = G.GAME.round_resets.blind_states.Big
        G.prev_boss_state = G.GAME.round_resets.blind_states.Boss
        G.GAME.round_resets.loc_blind_states.Small = localize(G.GAME.round_resets.blind_states.Small,'blind_states')
        G.GAME.round_resets.loc_blind_states.Big = localize(G.GAME.round_resets.blind_states.Big,'blind_states')
        G.GAME.round_resets.loc_blind_states.Boss = localize(G.GAME.round_resets.blind_states.Boss,'blind_states')
    end

    --Send all steam updates if needed
    if G.STEAM and G.STEAM.send_control.update_queued and (
        G.STEAM.send_control.force or 
        G.STEAM.send_control.last_sent_stage ~= G.STAGE or
        G.STEAM.send_control.last_sent_time < G.TIMERS.UPTIME - 120) then 
        if G.STEAM.userStats.storeStats() then
            G.STEAM.send_control.force = false
            G.STEAM.send_control.last_sent_stage = G.STAGE
            G.STEAM.send_control.last_sent_time = G.TIMERS.UPTIME
            G.STEAM.send_control.update_queued = false
        else
            G.DEBUG_VALUE = 'UNABLE TO STORE STEAM STATS'
        end
    end    


    if G.DEBUG then 
        local text_count,uie_count, card_count, uib_count, all = 0,0, 0, 0,0
        for k, v in pairs(G.STAGE_OBJECTS[G.STAGE]) do
            all = all + 1
            if v:is(DynaText) then text_count = text_count + 1 end
            if v:is(Card) then card_count = card_count + 1 end
            if v:is(UIElement) then uie_count = uie_count + 1 end
            if v:is(UIBox) then uib_count = uib_count + 1 end
        end

            G.DEBUG_VALUE = 'text: '..text_count..'\n'..
                            'uie: '..uie_count..'\n'..
                            'card: '..card_count..'\n'..
                            'uib: '..uib_count..'\n'..'all: '..all
    end
    
    --Save every 10 seconds, unless forced or paused/unpaused
    if not GLOBAL_cry_member_count_delay then GLOBAL_cry_member_count_delay = 0 end
    if (GLOBAL_cry_member_count_delay > 5) or not GLOBAL_cry_member_count then	-- it doesn't need to update this frequently? but it also doesn't need to be higher tbh...
    	if update_cry_member_count then update_cry_member_count() end	-- i honestly hate nil checks like this, wish there was a shorthand
    	GLOBAL_cry_member_count_delay = 0
    else
    	GLOBAL_cry_member_count_delay = GLOBAL_cry_member_count_delay + dt
    end
    if G.FILE_HANDLER and G.FILE_HANDLER and G.FILE_HANDLER.update_queued and (
        G.FILE_HANDLER.force or 
        G.FILE_HANDLER.last_sent_stage ~= G.STAGE or
        ((G.FILE_HANDLER.last_sent_pause ~= G.SETTINGS.paused) and G.FILE_HANDLER.run) or
        (not G.FILE_HANDLER.last_sent_time or (G.FILE_HANDLER.last_sent_time < (G.TIMERS.UPTIME - G.F_SAVE_TIMER)))) then 
            
            if G.FILE_HANDLER.metrics then
                G.SAVE_MANAGER.channel:push({
                    type = 'save_metrics',
                    save_metrics = G.ARGS.save_metrics
                  })
            end

            if G.FILE_HANDLER.progress then
                G.SAVE_MANAGER.channel:push({
                    type = 'save_progress',
                    save_progress = G.ARGS.save_progress
                  })
            elseif G.FILE_HANDLER.settings then
                G.SAVE_MANAGER.channel:push({
                    type = 'save_settings',
                    save_settings = G.ARGS.save_settings,
                    profile_num = G.SETTINGS.profile,
                    save_profile = G.PROFILES[G.SETTINGS.profile]
                  })
            end

            if G.FILE_HANDLER.run then
                G.SAVE_MANAGER.channel:push({
                    type = 'save_run',
                    talisman = Talisman.config_file.break_infinity,
                    save_table = G.ARGS.save_run,
                    profile_num = G.SETTINGS.profile})
                G.SAVED_GAME = nil
            end

            G.FILE_HANDLER.force = false
            G.FILE_HANDLER.last_sent_stage = G.STAGE
            G.FILE_HANDLER.last_sent_time = G.TIMERS.UPTIME
            G.FILE_HANDLER.last_sent_pause = G.SETTINGS.paused
            G.FILE_HANDLER.settings = nil
            G.FILE_HANDLER.progress = nil
            G.FILE_HANDLER.metrics = nil
            G.FILE_HANDLER.run = nil
    end  
end

function Game:draw()
    G.FRAMES.DRAW = G.FRAMES.DRAW + 1
    --draw the room
    reset_drawhash()
    if G.OVERLAY_TUTORIAL and not G.OVERLAY_MENU then G.under_overlay = true end
    timer_checkpoint('start->canvas', 'draw')
    love.graphics.setCanvas{self.CANVAS}
    love.graphics.push()
    love.graphics.scale(G.CANV_SCALE)
    
    love.graphics.setShader()
    love.graphics.clear(0,0,0,1)

    if G.SPLASH_BACK then
        if G.debug_background_toggle then
            love.graphics.clear({0,1,0,1})
        else
            love.graphics.push()
            G.SPLASH_BACK:translate_container()
            G.SPLASH_BACK:draw()
            love.graphics.pop()
        end
    end

    if not G.debug_UI_toggle then 

    for k, v in pairs(self.I.NODE) do
        if not v.parent then 
            love.graphics.push()
            v:translate_container()
            v:draw()
            love.graphics.pop()
        end
    end

    for k, v in pairs(self.I.MOVEABLE) do
        if not v.parent then 
            love.graphics.push()
            v:translate_container()
            v:draw()
            love.graphics.pop()
        end
    end

    if G.SPLASH_LOGO then
        love.graphics.push()
        G.SPLASH_LOGO:translate_container()
        G.SPLASH_LOGO:draw()
        love.graphics.pop()
    end

    if G.debug_splash_size_toggle then 
        for k, v in pairs(self.I.CARDAREA) do
            if not v.parent then 
                love.graphics.push()
                v:translate_container()
                v:draw()
                love.graphics.pop()
            end
        end
    else
    if (not self.OVERLAY_MENU) or (not self.F_HIDE_BG) then 
        timer_checkpoint('primatives', 'draw')
        for k, v in pairs(self.I.UIBOX) do
            if not v.attention_text and not v.parent and v ~= self.OVERLAY_MENU and v ~= self.screenwipe and v ~= self.OVERLAY_TUTORIAL and v ~= self.debug_tools and v ~= self.online_leaderboard and v ~= self.achievement_notification then 
                love.graphics.push()
                v:translate_container()
                v:draw()
                love.graphics.pop()
            end
        end
            timer_checkpoint('uiboxes', 'draw')
        for k, v in pairs(self.I.CARDAREA) do
            if not v.parent then 
                love.graphics.push()
                v:translate_container()
                v:draw()
                love.graphics.pop()
            end
        end

        for k, v in pairs(self.I.CARD) do
            if (not v.parent and v ~= self.CONTROLLER.dragging.target and v ~= self.CONTROLLER.focused.target) then
                love.graphics.push()
                v:translate_container()
                v:draw()
                love.graphics.pop()
            end
        end

        for k, v in pairs(self.I.UIBOX) do
            if v.attention_text and v ~= self.debug_tools and v ~= self.online_leaderboard and v ~= self.achievement_notification  then 
                love.graphics.push()
                v:translate_container()
                v:draw()
                love.graphics.pop()
            end
        end

        if G.SPLASH_FRONT then
            love.graphics.push()
            G.SPLASH_FRONT:translate_container()
            G.SPLASH_FRONT:draw()
            love.graphics.pop()
        end

        G.under_overlay = false
        if self.OVERLAY_TUTORIAL then
            love.graphics.push()
            self.OVERLAY_TUTORIAL:translate_container()
            self.OVERLAY_TUTORIAL:draw()
            love.graphics.pop()
            
            if self.OVERLAY_TUTORIAL.highlights then 
                for k, v in ipairs(self.OVERLAY_TUTORIAL.highlights) do
                    love.graphics.push()
                    v:translate_container()
                    v:draw()
                    if v.draw_children then
                        v:draw_self()
                        v:draw_children()
                    end
                    love.graphics.pop()
                end
            end
        end
    end         
    if (self.OVERLAY_MENU) or (not self.F_HIDE_BG) then
        if self.OVERLAY_MENU and self.OVERLAY_MENU ~= self.CONTROLLER.dragging.target then
            love.graphics.push()
            self.OVERLAY_MENU:translate_container()
            self.OVERLAY_MENU:draw()
            love.graphics.pop()
        end
    end

    if self.debug_tools then 
        if self.debug_tools ~= self.CONTROLLER.dragging.target then
            love.graphics.push()
            self.debug_tools:translate_container()
            self.debug_tools:draw()
            love.graphics.pop()
        end
    end

    G.ALERT_ON_SCREEN = nil
    for k, v in pairs(self.I.ALERT) do
        love.graphics.push()
        v:translate_container()
        v:draw()
        G.ALERT_ON_SCREEN = true
        love.graphics.pop()
    end

    if self.CONTROLLER.dragging.target and self.CONTROLLER.dragging.target ~= self.CONTROLLER.focused.target then
        love.graphics.push()
            G.CONTROLLER.dragging.target:translate_container()
            G.CONTROLLER.dragging.target:draw()
        love.graphics.pop()
    end

    if self.CONTROLLER.focused.target and getmetatable(self.CONTROLLER.focused.target) == Card and
       (self.CONTROLLER.focused.target.area ~= G.hand or self.CONTROLLER.focused.target == self.CONTROLLER.dragging.target) then 
        love.graphics.push()
            G.CONTROLLER.focused.target:translate_container()
            G.CONTROLLER.focused.target:draw()
        love.graphics.pop()
    end

    for k, v in pairs(self.I.POPUP) do
        love.graphics.push()
        v:translate_container()
        v:draw()
        love.graphics.pop()
    end

    if self.achievement_notification then 
        love.graphics.push()
            self.achievement_notification:translate_container()
            self.achievement_notification:draw()
        love.graphics.pop()
    end


    if self.screenwipe then
        love.graphics.push()
            self.screenwipe:translate_container()
            self.screenwipe:draw()
        love.graphics.pop()
    end

    love.graphics.push()
        self.CURSOR:translate_container()
        love.graphics.translate(-self.CURSOR.T.w*G.TILESCALE*G.TILESIZE*0.5, -self.CURSOR.T.h*G.TILESCALE*G.TILESIZE*0.5)
        self.CURSOR:draw()
    love.graphics.pop()
    timer_checkpoint('rest', 'draw')
    end
end
love.graphics.pop()
    
    love.graphics.setCanvas(G.AA_CANVAS)
    love.graphics.push()
        love.graphics.setColor(G.C.WHITE)
    if (not G.recording_mode or G.video_control )and true then
        G.ARGS.eased_cursor_pos = G.ARGS.eased_cursor_pos or {x=G.CURSOR.T.x,y=G.CURSOR.T.y, sx = G.CONTROLLER.cursor_position.x, sy = G.CONTROLLER.cursor_position.y}
        G.screenwipe_amt = G.screenwipe_amt and (0.95*G.screenwipe_amt + 0.05*((self.screenwipe and 0.4 or self.screenglitch and 0.4) or 0)) or 1
        G.SETTINGS.GRAPHICS.crt = G.SETTINGS.GRAPHICS.crt*0.3
        G.SHADERS['CRT']:send('distortion_fac', {1.0 + 0.07*G.SETTINGS.GRAPHICS.crt/100, 1.0 + 0.1*G.SETTINGS.GRAPHICS.crt/100})
        G.SHADERS['CRT']:send('scale_fac', {1.0 - 0.008*G.SETTINGS.GRAPHICS.crt/100, 1.0 - 0.008*G.SETTINGS.GRAPHICS.crt/100})
        G.SHADERS['CRT']:send('feather_fac', 0.01)
        G.SHADERS['CRT']:send('bloom_fac', G.SETTINGS.GRAPHICS.bloom - 1)
        G.SHADERS['CRT']:send('time',400 + G.TIMERS.REAL)
        G.SHADERS['CRT']:send('noise_fac',0.001*G.SETTINGS.GRAPHICS.crt/100)
        G.SHADERS['CRT']:send('crt_intensity', 0.16*G.SETTINGS.GRAPHICS.crt/100)
        G.SHADERS['CRT']:send('glitch_intensity', glitched_intensity or 0)
        G.SHADERS['CRT']:send('scanlines', G.CANVAS:getPixelHeight()*0.75/G.CANV_SCALE)
        G.SHADERS['CRT']:send('mouse_screen_pos', G.video_control and {love.graphics.getWidth( )/2, love.graphics.getHeight( )/2} or {G.ARGS.eased_cursor_pos.sx, G.ARGS.eased_cursor_pos.sy})
        G.SHADERS['CRT']:send('screen_scale', G.TILESCALE*G.TILESIZE)
        G.SHADERS['CRT']:send('hovering', 1)
        love.graphics.setShader( G.SHADERS['CRT'])
        G.SETTINGS.GRAPHICS.crt = G.SETTINGS.GRAPHICS.crt/0.3
    end

        love.graphics.draw(self.CANVAS, 0, 0)
    love.graphics.pop()

    love.graphics.setCanvas()
    love.graphics.setShader()

    if G.AA_CANVAS then 
        love.graphics.push()
            love.graphics.scale(1/G.CANV_SCALE)
            love.graphics.draw(G.AA_CANVAS, 0, 0)
        love.graphics.pop()
    end

    timer_checkpoint('canvas', 'draw')

    if not _RELEASE_MODE and G.DEBUG and not G.video_control and G.F_VERBOSE then 
        love.graphics.push()
        love.graphics.setColor(0, 1, 1,1)
        local fps = love.timer.getFPS( )
        love.graphics.print("Current FPS: "..fps, 10, 10)

        if G.check and G.SETTINGS.perf_mode then
            local section_h = 30
            local resolution = 60*section_h
            local poll_w = 1
            local v_off = 100
            for a, b in ipairs({G.check.update, G.check.draw}) do
                for k, v in ipairs(b.checkpoint_list) do
                    love.graphics.setColor(0,0,0,0.2)
                    love.graphics.rectangle('fill', 12, 20 + v_off,poll_w+poll_w*#v.trend,-section_h + 5)
                    for kk, vv in ipairs(v.trend) do
                        if a == 2 then 
                            love.graphics.setColor(0.3,0.7,0.7,1)
                        else
                            love.graphics.setColor(self:state_col(v.states[kk] or 123))
                        end
                        love.graphics.rectangle('fill', 10+poll_w*kk,  20 + v_off, 5*poll_w, -(vv)*resolution)
                    end
                    love.graphics.setColor(a == 2 and 0.5 or 1, a == 2 and 1 or 0.5, 1,1)
                    love.graphics.print(v.label..': '..(string.format("%.2f",1000*(v.average or 0)))..'\n', 10, -section_h + 30 + v_off)
                    v_off = v_off + section_h
                end
            end
        end

        love.graphics.pop()
    end
    timer_checkpoint('debug', 'draw')
end

function Game:state_col(_state)
    return (_state*15251252.2/5.132)%1,  (_state*1422.5641311/5.42)%1,  (_state*1522.1523122/5.132)%1, 1
end

function Game:update_selecting_hand(dt)
    if not self.deck_preview and not G.OVERLAY_MENU and (
        (self.deck and self.deck.cards[1] and self.deck.cards[1].states.collide.is and ((not self.deck.cards[1].states.drag.is) or self.CONTROLLER.HID.touch) and (not self.CONTROLLER.HID.controller)) or 
        G.CONTROLLER.held_buttons.triggerleft) then
        if self.buttons then
            self.buttons.states.visible = false
        end
        self.deck_preview = UIBox{
            definition = self.UIDEF.deck_preview(),
            config = {align='tm', offset = {x=0,y=-0.8},major = self.hand, bond = 'Weak'}
        }
        self.E_MANAGER:add_event(Event({
            blocking = false,
            blockable = false,
            func = function()
                if self.deck_preview and not (((self.deck and self.deck.cards[1] and self.deck.cards[1].states.collide.is and not self.CONTROLLER.HID.controller)) or G.CONTROLLER.held_buttons.triggerleft) then 
                    self.deck_preview:remove()
                    self.deck_preview = nil
                    local _card = G.CONTROLLER.focused.target
                    local start = G.TIMERS.REAL
                    self.E_MANAGER:add_event(Event({
                        func = function()
                            if _card and _card.area and _card.area == G.hand then
                                local _x, _y = _card:put_focused_cursor()
                                G.CONTROLLER:update_cursor({x=_x/(G.TILESCALE*G.TILESIZE),y=_y/(G.TILESCALE*G.TILESIZE)})
                            end
                            if start + 0.4 < G.TIMERS.REAL then
                                return true
                            end
                        end
                    }))
                    return true
                end
            end
        }))
    end
    if not self.buttons and not self.deck_preview then
        self.buttons = UIBox{
            definition = create_UIBox_buttons(),
            config = {align="bm", offset = {x=0,y=0.3},major = G.hand, bond = 'Weak'}
        }
    end
    if self.buttons and not self.buttons.states.visible and not self.deck_preview then
        self.buttons.states.visible = true
    end

    if #G.hand.cards < 1 and #G.deck.cards < 1 and #G.play.cards < 1 then
        end_round()
    end

    if self.shop and not G.GAME.USING_CODE then self.shop:remove(); self.shop = nil end
    if not G.STATE_COMPLETE then
        G.STATE_COMPLETE = true
        if #G.hand.cards < 1 and #G.deck.cards < 1 then
            end_round()
        else
            save_run()
            G.CONTROLLER:recall_cardarea_focus('hand')
        end
    end
end

function Game:update_shop(dt)
    if not G.STATE_COMPLETE then
        stop_use()
        if not G.GAME.USING_RUN then ease_background_colour_blind(G.STATES.SHOP) end
        local shop_exists = not not G.shop
        G.shop = G.shop or UIBox{
            definition = G.UIDEF.shop(),
            config = {align='tmi', offset = {x=0,y=G.ROOM.T.y+11},major = G.hand, bond = 'Weak'}
        }
            G.E_MANAGER:add_event(Event({
                func = function()
                    if not G.shop then return true end
                    G.shop.alignment.offset.y = -5.3
                    G.shop.alignment.offset.x = 0
                    G.E_MANAGER:add_event(Event({
                        trigger = 'after',
                        delay = 0.2,
                        blockable = false,
                        func = function()
                            if math.abs(G.shop.T.y - G.shop.VT.y) < 3 then
                                G.ROOM.jiggle = G.ROOM.jiggle + 3
                                play_sound('cardFan2')
                                for i = 1, #G.GAME.tags do
                                    G.GAME.tags[i]:apply_to_run({type = 'shop_start'})
                                end
                                local nosave_shop = nil
                                if not shop_exists then
                                
                                    if G.load_shop_jokers then 
                                        nosave_shop = true
                                        G.shop_jokers:load(G.load_shop_jokers)
                                        for k, v in ipairs(G.shop_jokers.cards) do
                                            create_shop_card_ui(v)
                                            if v.ability.consumeable then v:start_materialize() end
                                            for _kk, vvv in ipairs(G.GAME.tags) do
                                                if vvv:apply_to_run({type = 'store_joker_modify', card = v}) then break end
                                            end
                                        end
                                        G.load_shop_jokers = nil
                                    else
                                        for i = 1, G.GAME.shop.joker_max - #G.shop_jokers.cards do
                                            G.shop_jokers:emplace(create_card_for_shop(G.shop_jokers))
                                        end
                                    end
                                    
                                    if G.load_shop_vouchers then 
                                        nosave_shop = true
                                        G.shop_vouchers:load(G.load_shop_vouchers)
                                        for k, v in ipairs(G.shop_vouchers.cards) do
                                            create_shop_card_ui(v)
                                            v:start_materialize()
                                        end
                                        G.load_shop_vouchers = nil
                                    else
                                        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
                                            cry_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
                                            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
                                            create_shop_card_ui(card, 'Voucher', G.shop_vouchers)
                                            card:start_materialize()
                                            if G.GAME.current_round.cry_voucher_edition then
                                            	card:set_edition(G.GAME.current_round.cry_voucher_edition, true, true)
                                            end
                                            if G.GAME.current_round.cry_voucher_stickers then
                                            	if G.GAME.current_round.cry_voucher_stickers.eternal == true then		-- this is dumb but i'm not sure how to call functions from a string
                                            		card:set_eternal(true)
                                            		card.ability.eternal = true
                                            	end
                                            	if G.GAME.current_round.cry_voucher_stickers.perishable == true then
                                            		card.ability.perishable = true
                                            	end
                                            	if G.GAME.current_round.cry_voucher_stickers.rental == true then
                                            		card:set_rental(true)
                                            		card.ability.rental = true
                                            	end
                                            	if G.GAME.current_round.cry_voucher_stickers.pinned == true then
                                            		card.pinned = true
                                            	end
                                            	if G.GAME.current_round.cry_voucher_stickers.banana == true then
                                            		card.ability.banana = true
                                            	end
                                            end
                                            G.shop_vouchers:emplace(card)
                                        end
                                    end
                                    

                                    if G.GAME.events.ev_cry_choco10 and not G.load_shop_vouchers then
                                        local card = create_card('Joker', G.jokers, true, nil, nil, nil, nil, 'cry_antique')
                                        cry_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
                                    if G.load_shop_booster then 
                                        nosave_shop = true
                                        G.shop_booster:load(G.load_shop_booster)
                                        for k, v in ipairs(G.shop_booster.cards) do
                                            create_shop_card_ui(v)
                                            v:start_materialize()
                                        end
                                        G.load_shop_booster = nil
                                    else
                                        for i = 1, G.GAME.modifiers.cry_no_boosters and 0 or G.GAME.modifiers.cry_booster_packs or 2 do
                                            G.GAME.current_round.used_packs = G.GAME.current_round.used_packs or {}
                                            if not G.GAME.current_round.used_packs[i] then
                                                G.GAME.current_round.used_packs[i] = get_pack('shop_pack').key
                                            end

                                            if G.GAME.current_round.used_packs[i] ~= 'USED' then 
                                                local card = Card(G.shop_booster.T.x + G.shop_booster.T.w/2,
                                                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})
                                                cry_misprintize(card)
                                                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
                                                create_shop_card_ui(card, 'Booster', G.shop_booster)
                                                card.ability.booster_pos = i
                                                card:start_materialize()
                                                if G.GAME.modifiers.cry_force_edition and not G.GAME.modifiers.cry_force_random_edition then
                                                	card:set_edition(nil, true, true)
                                                elseif G.GAME.modifiers.cry_force_random_edition then
                                                	local edition = cry_poll_random_edition()
                                                	card:set_edition(edition, true, true)
                                                end
                                                
                                                local eternal_perishable_poll = pseudorandom('cry_bpet'..(key_append or '')..G.GAME.round_resets.ante)
                                                if (G.GAME.modifiers.cry_force_sticker == 'eternal') or (G.GAME.modifiers.cry_sticker_sheet_plus) or (G.GAME.modifiers.cry_any_stickers and (G.GAME.modifiers.enable_eternals_in_shop and eternal_perishable_poll > 0.8)) then	
                                                	card:set_eternal(true)
                                                	card.ability.eternal = true
                                                end
                                                if G.GAME.modifiers.enable_perishables_in_shop and G.GAME.modifiers.cry_any_stickers then	-- i don't feel like messing with this, whatever
                                                	if not G.GAME.modifiers.cry_eternal_perishable_compat and ((eternal_perishable_poll > 0.6) and (eternal_perishable_poll <= 0.8)) then
                                                		card:set_perishable(true)
                                                		card.ability.perishable = true
                                                	end
                                                	if G.GAME.modifiers.cry_eternal_perishable_compat and pseudorandom('cry_bpper'..(key_append or '')..G.GAME.round_resets.ante) > 0.8 then
                                                		card:set_perishable(true)
                                                		card.ability.perishable = true
                                                	end
                                                end
                                                if (G.GAME.modifiers.cry_force_sticker == 'perishable') or (G.GAME.modifiers.cry_sticker_sheet_plus) then
                                                	card:set_perishable(true)
                                                	card.ability.perishable = true
                                                end
                                                if (G.GAME.modifiers.cry_force_sticker == 'rental') or (G.GAME.modifiers.cry_sticker_sheet_plus) or (G.GAME.modifiers.cry_any_stickers and (G.GAME.modifiers.enable_rentals_in_shop and pseudorandom('cry_bpssjr'..(key_append or '')..G.GAME.round_resets.ante) > 0.8)) then	-- i should really just make this a function? so messy
                                                	card.ability.rental = true	-- do not set_rental here to prevent cost from decreasing
                                                end
                                                if (G.GAME.modifiers.cry_force_sticker == 'pinned') or (G.GAME.modifiers.cry_sticker_sheet_plus) or (G.GAME.modifiers.cry_any_stickers and (G.GAME.modifiers.cry_enable_pinned_in_shop and pseudorandom('cry_bppin'..(key_append or '')..G.GAME.round_resets.ante) > 0.8)) then
                                                	card.pinned = true
                                                end
                                                if G.GAME.modifiers.cry_force_sticker == 'banana' or G.GAME.modifiers.cry_sticker_sheet_plus then
                                                	card.ability.banana = true
                                                end
                                                if not G.GAME.modifiers.cry_eternal_perishable_compat and G.GAME.modifiers.enable_banana and G.GAME.modifiers.cry_any_stickers and (pseudorandom('cry_bpbanana'..(key_append or '')..G.GAME.round_resets.ante) > 0.8) and (eternal_perishable_poll <= 0.8) then
                                                	card.ability.banana = true
                                                end
                                                if G.GAME.modifiers.cry_eternal_perishable_compat and G.GAME.modifiers.enable_banana and G.GAME.modifiers.cry_any_stickers and (pseudorandom('cry_bpbanana'..(key_append or '')..G.GAME.round_resets.ante) > 0.8) then
                                                	card.ability.banana = true
                                                end
                                                if G.GAME.modifiers.cry_sticker_sheet_plus then
                                                	for k, v in pairs(SMODS.Stickers) do
                                                		if v.apply and not v.no_sticker_sheet then v:apply(card, true) end
                                                	end
                                                end
                                                G.shop_booster:emplace(card)
                                            end
                                        end

                                        for i = 1, #G.GAME.tags do
                                            G.GAME.tags[i]:apply_to_run({type = 'voucher_add'})
                                        end
                                        for i = 1, #G.GAME.tags do
                                            G.GAME.tags[i]:apply_to_run({type = 'shop_final_pass'})
                                        end
                                    end
                                end

                                G.CONTROLLER:snap_to({node = G.shop:get_UIE_by_ID('next_round_button')})
                                if not nosave_shop then G.E_MANAGER:add_event(Event({ func = function() save_run(); return true end})) end
                                return true
                            end
                        end}))
                    return true
                end
            }))
          G.STATE_COMPLETE = true
    end  
    if self.buttons then self.buttons:remove(); self.buttons = nil end          
end

function Game:update_play_tarot(dt)
    if self.buttons then self.buttons:remove(); self.buttons = nil end
end

function Game:update_hand_played(dt)
G.GAME.chips = (G.GAME.chips or 0)
G.GAME.blind.chips = (G.GAME.blind.chips or math.huge)
    if self.buttons then self.buttons:remove(); self.buttons = nil end
    if self.shop and not G.GAME.USING_CODE then self.shop:remove(); self.shop = nil end

    if not G.STATE_COMPLETE then
        G.STATE_COMPLETE = true
        G.E_MANAGER:add_event(Event({
            trigger = 'immediate',
            func = function()
        if to_big(G.GAME.chips) >= to_big(G.GAME.blind.chips) or G.GAME.current_round.hands_left < 1 then
            G.STATE = G.STATES.NEW_ROUND
        else
            G.STATE = G.STATES.DRAW_TO_HAND
        end
        G.STATE_COMPLETE = false
        return true
        end
        }))
    end
end

function Game:update_draw_to_hand(dt)
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
    if self.buttons then self.buttons:remove(); self.buttons = nil end
    if self.shop and not G.GAME.USING_CODE then self.shop:remove(); self.shop = nil end

    if not G.STATE_COMPLETE then
        G.STATE_COMPLETE = true
        for i = 1, #G.GAME.tags do
            G.GAME.tags[i]:apply_to_run({type = 'round_start_bonus'})
        end
        ease_background_colour_blind(G.STATES.DRAW_TO_HAND)
        
        G.E_MANAGER:add_event(Event({
            trigger = 'immediate',
            func = function()
                if G.FUNCS.draw_from_deck_to_hand(nil) then
                    return true
                end

                if G.GAME.current_round.hands_played == 0 and
                    G.GAME.current_round.discards_used == 0 and G.GAME.facing_blind then
                        SMODS.calculate_context({first_hand_drawn = true})
                    end
                    SMODS.calculate_context({hand_drawn = true})

                G.E_MANAGER:add_event(Event({
                    trigger = 'immediate',
                    func = function()
                    G.STATE = G.STATES.SELECTING_HAND
                    G.STATE_COMPLETE = false
                    G.GAME.blind:drawn_to_hand()
                    return true
                    end
                }))
                return true
            end
        }))
    end
end

function Game:update_new_round(dt)
    if self.buttons then self.buttons:remove(); self.buttons = nil end
    if self.shop and not G.GAME.USING_CODE then self.shop:remove(); self.shop = nil end

    if not G.STATE_COMPLETE then
        G.STATE_COMPLETE = true
        end_round()
    end
end

function Game:update_blind_select(dt)
    if self.buttons then self.buttons:remove(); self.buttons = nil end
    if self.shop and not G.GAME.USING_CODE then self.shop:remove(); self.shop = nil end

    if not G.STATE_COMPLETE then
        stop_use()
        ease_background_colour_blind(G.STATES.BLIND_SELECT)
        G.E_MANAGER:add_event(Event({ func = function() save_run(); return true end}))
        G.STATE_COMPLETE = true
        G.CONTROLLER.interrupt.focus = true
        G.E_MANAGER:add_event(Event({ func = function() 
        G.E_MANAGER:add_event(Event({
            trigger = 'immediate',
            func = function()
                --G.GAME.round_resets.blind_states = G.GAME.round_resets.blind_states or {Small = 'Select', Big = 'Upcoming', Boss = 'Upcoming'}
                --if G.GAME.round_resets.blind_states.Boss == 'Defeated' then
                --    G.GAME.round_resets.blind_states.Small = 'Upcoming'
                --    G.GAME.round_resets.blind_states.Big = 'Upcoming'
                --    G.GAME.round_resets.blind_states.Boss = 'Upcoming'
                --    G.GAME.blind_on_deck = 'Small'
                --    G.GAME.round_resets.blind_choices.Boss = get_new_boss()
                --    G.GAME.round_resets.boss_rerolled = false
                --end
                play_sound('cancel')
                G.blind_select = UIBox{
                    definition = create_UIBox_blind_select(),
                    config = {align="bmi", offset = {x=0,y=G.ROOM.T.y + 29},major = G.hand, bond = 'Weak'}
                }
                G.blind_select.alignment.offset.y = 0.8-(G.hand.T.y - G.jokers.T.y) + G.blind_select.T.h
                G.ROOM.jiggle = G.ROOM.jiggle + 3
                G.blind_select.alignment.offset.x = 0
                G.CONTROLLER.lock_input = false
                for i = 1, #G.GAME.tags do
                    G.GAME.tags[i]:apply_to_run({type = 'immediate'})
                end
                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
        }))  ; return true end}))
    end
end

function Game:update_round_eval(dt)
    if self.buttons then self.buttons:remove(); self.buttons = nil end
    if self.shop and not G.GAME.USING_CODE then self.shop:remove(); self.shop = nil end

    if not G.STATE_COMPLETE then
        stop_use()
        G.STATE_COMPLETE = true
        G.E_MANAGER:add_event(Event({
            trigger = 'immediate',
            func = function()
                G.GAME.facing_blind = nil
                save_run()
                ease_background_colour_blind(G.STATES.ROUND_EVAL)
                if G.GAME.events.ev_cry_choco6 and G.round_eval then return true end
                G.round_eval = UIBox{
                    definition = create_UIBox_round_evaluation(),
                    config = {align="bm", offset = {x=0,y=G.ROOM.T.y + 19},major = G.hand, bond = 'Weak'}
                }
                G.round_eval.alignment.offset.x = 0
                G.E_MANAGER:add_event(Event({
                    trigger = 'immediate',
                    func = function()
                        if G.round_eval.alignment.offset.y ~= -7.8 then
                            G.round_eval.alignment.offset.y = -7.8
                        else
                            if math.abs(G.round_eval.T.y - G.round_eval.VT.y) < 3 then
                                    G.ROOM.jiggle = G.ROOM.jiggle + 3
                                    play_sound('cardFan2')
                                    delay(0.1)
                                    G.FUNCS.evaluate_round()
                                    return true
                            end
                        end
                    end}))
                return true
            end
        }))  
    end
end

function Game:update_arcana_pack(dt)
    if self.buttons then self.buttons:remove(); self.buttons = nil end
    if self.shop then G.shop.alignment.offset.y = G.ROOM.T.y+11 end

    if not G.STATE_COMPLETE then
        G.STATE_COMPLETE = true
        G.CONTROLLER.interrupt.focus = true
        G.E_MANAGER:add_event(Event({
            trigger = 'immediate',
            func = function()
                G.booster_pack_sparkles = Particles(1, 1, 0,0, {
                    timer = 0.015,
                    scale = 0.2,
                    initialize = true,
                    lifespan = 1,
                    speed = 1.1,
                    padding = -1,
                    attach = G.ROOM_ATTACH,
                    colours = {G.C.WHITE, lighten(G.C.PURPLE, 0.4), lighten(G.C.PURPLE, 0.2), lighten(G.C.GOLD, 0.2)},
                    fill = true
                })
                G.booster_pack_sparkles.fade_alpha = 1
                G.booster_pack_sparkles:fade(1, 0)
                G.booster_pack = UIBox{
                    definition = create_UIBox_arcana_pack(),
                    config = {align="tmi", offset = {x=0,y=G.ROOM.T.y + 9},major = G.hand, bond = 'Weak'}
                }
                G.booster_pack.alignment.offset.y = -2.2
                        G.ROOM.jiggle = G.ROOM.jiggle + 3
                ease_background_colour_blind(G.STATES.TAROT_PACK)
                G.E_MANAGER:add_event(Event({
                    trigger = 'immediate',
                    func = function()
                        G.FUNCS.draw_from_deck_to_hand()

                        G.E_MANAGER:add_event(Event({
                            trigger = 'after',
                            delay = 0.5,
                            func = function()
                                G.CONTROLLER:recall_cardarea_focus('pack_cards')
                                return true
                            end}))
                        return true
                    end
                }))  
                return true
            end
        }))  
    end
end

function Game:update_spectral_pack(dt)
    if self.buttons then self.buttons:remove(); self.buttons = nil end
    if self.shop then G.shop.alignment.offset.y = G.ROOM.T.y+11 end

    if not G.STATE_COMPLETE then
        G.STATE_COMPLETE = true
        G.CONTROLLER.interrupt.focus = true
        G.E_MANAGER:add_event(Event({
            trigger = 'immediate',
            func = function()
                G.booster_pack_sparkles = Particles(1, 1, 0,0, {
                    timer = 0.015,
                    scale = 0.1,
                    initialize = true,
                    lifespan = 3,
                    speed = 0.2,
                    padding = -1,
                    attach = G.ROOM_ATTACH,
                    colours = {G.C.WHITE, lighten(G.C.GOLD, 0.2)},
                    fill = true
                })
                G.booster_pack_sparkles.fade_alpha = 1
                G.booster_pack_sparkles:fade(1, 0)
                G.booster_pack = UIBox{
                    definition = create_UIBox_spectral_pack(),
                    config = {align="tmi", offset = {x=0,y=G.ROOM.T.y + 9},major = G.hand, bond = 'Weak'}
                }
                G.booster_pack.alignment.offset.y = -2.2
                        G.ROOM.jiggle = G.ROOM.jiggle + 3
                ease_background_colour_blind(G.STATES.SPECTRAL_PACK)
                G.E_MANAGER:add_event(Event({
                    trigger = 'immediate',
                    func = function()
                        G.FUNCS.draw_from_deck_to_hand()

                        G.E_MANAGER:add_event(Event({
                            trigger = 'after',
                            delay = 0.5,
                            func = function()
                                G.CONTROLLER:recall_cardarea_focus('pack_cards')
                                return true
                            end}))
                        return true
                    end
                }))  
                return true
            end
        }))  
    end
end

function Game:update_standard_pack(dt)
    if self.buttons then self.buttons:remove(); self.buttons = nil end
    if self.shop then G.shop.alignment.offset.y = G.ROOM.T.y+11 end

    if not G.STATE_COMPLETE then
        G.STATE_COMPLETE = true
        G.CONTROLLER.interrupt.focus = true
        G.E_MANAGER:add_event(Event({
            trigger = 'immediate',
            func = function()
                G.booster_pack_sparkles = Particles(1, 1, 0,0, {
                    timer = 0.015,
                    scale = 0.3,
                    initialize = true,
                    lifespan = 3,
                    speed = 0.2,
                    padding = -1,
                    attach = G.ROOM_ATTACH,
                    colours = {G.C.BLACK, G.C.RED},
                    fill = true
                })
                G.booster_pack_sparkles.fade_alpha = 1
                G.booster_pack_sparkles:fade(1, 0)
                G.booster_pack = UIBox{
                    definition = create_UIBox_standard_pack(),
                    config = {align="tmi", offset = {x=0,y=G.ROOM.T.y + 9},major = G.hand, bond = 'Weak'}
                }
                G.booster_pack.alignment.offset.y = -2.2
                        G.ROOM.jiggle = G.ROOM.jiggle + 3
                ease_background_colour_blind(G.STATES.STANDARD_PACK)
                G.E_MANAGER:add_event(Event({
                    trigger = 'immediate',
                    func = function()
                        G.E_MANAGER:add_event(Event({
                            trigger = 'after',
                            delay = 0.5,
                            func = function()
                                G.CONTROLLER:recall_cardarea_focus('pack_cards')
                                return true
                            end}))
                        return true
                    end
                }))  
                return true
            end
        }))  
    end
end

function Game:update_buffoon_pack(dt)
    if self.buttons then self.buttons:remove(); self.buttons = nil end
    if self.shop then G.shop.alignment.offset.y = G.ROOM.T.y+11 end

    if not G.STATE_COMPLETE then
        G.STATE_COMPLETE = true
        G.CONTROLLER.interrupt.focus = true
        G.E_MANAGER:add_event(Event({
            trigger = 'immediate',
            func = function()
                G.booster_pack = UIBox{
                    definition = create_UIBox_buffoon_pack(),
                    config = {align="tmi", offset = {x=0,y=G.ROOM.T.y + 9},major = G.hand, bond = 'Weak'}
                }
                G.booster_pack.alignment.offset.y = -2.2
                        G.ROOM.jiggle = G.ROOM.jiggle + 3
                ease_background_colour_blind(G.STATES.BUFFOON_PACK)
                G.E_MANAGER:add_event(Event({
                    trigger = 'immediate',
                    func = function()
                        G.E_MANAGER:add_event(Event({
                            trigger = 'after',
                            delay = 0.5,
                            func = function()
                                G.CONTROLLER:recall_cardarea_focus('pack_cards')
                                return true
                            end}))
                        return true
                    end
                }))  
                return true
            end
        }))  
    end
end

function Game:update_celestial_pack(dt)
    if self.buttons then self.buttons:remove(); self.buttons = nil end
    if self.shop then G.shop.alignment.offset.y = G.ROOM.T.y+11 end

    if not G.STATE_COMPLETE then
        G.STATE_COMPLETE = true
        G.CONTROLLER.interrupt.focus = true
        G.E_MANAGER:add_event(Event({
            trigger = 'immediate',
            func = function()
                ease_background_colour_blind(G.STATES.PLANET_PACK)
                G.booster_pack_stars = Particles(1, 1, 0,0, {
                    timer = 0.07,
                    scale = 0.1,
                    initialize = true,
                    lifespan = 15,
                    speed = 0.1,
                    padding = -4,
                    attach = G.ROOM_ATTACH,
                    colours = {G.C.WHITE, HEX('a7d6e0'), HEX('fddca0')},
                    fill = true
                })
                G.booster_pack_meteors = Particles(1, 1, 0,0, {
                    timer = 2,
                    scale = 0.05,
                    lifespan = 1.5,
                    speed = 4,
                    attach = G.ROOM_ATTACH,
                    colours = {G.C.WHITE},
                    fill = true
                })
                G.booster_pack = UIBox{
                    definition = create_UIBox_celestial_pack(), 
                    config = {
                        align="tmi",
                        offset = {x=0,y=G.ROOM.T.y + 9},
                        major = G.hand,
                        bond = 'Weak'
                    }
                }
                G.booster_pack.alignment.offset.y = -2.2
                G.ROOM.jiggle = G.ROOM.jiggle + 3 
                G.E_MANAGER:add_event(Event({
                    func = function()
                        G.CONTROLLER:recall_cardarea_focus('pack_cards')
                        return true
                    end}))
                return true
            end
        }))  
    end
end

function Game:update_game_over(dt)
    if not G.STATE_COMPLETE then
        remove_save()

        if G.GAME.round_resets.ante <= G.GAME.win_ante then
            if not G.GAME.seeded and not G.GAME.challenge then
                inc_career_stat('c_losses', 1)
                set_deck_loss()
                set_joker_loss()
            end
        end

        play_sound('negative', 0.5, 0.7)
        play_sound('whoosh2', 0.9, 0.7)

        G.SETTINGS.paused = true
        G.FUNCS.overlay_menu{
            definition = create_UIBox_game_over(),
            config = {no_esc = true}
        }
        G.ROOM.jiggle = G.ROOM.jiggle + 3
        
        if G.GAME.round_resets.ante <= G.GAME.win_ante then --Only add Jimbo to say a quip if the game over happens when the run is lost
            local Jimbo = nil
            G.E_MANAGER:add_event(Event({
                trigger = 'after',
                delay = 2.5,
                blocking = false,
                func = (function()
                    if G.OVERLAY_MENU and G.OVERLAY_MENU:get_UIE_by_ID('jimbo_spot') then 
                        Jimbo = Card_Character({x = 0, y = 5})
                        local spot = G.OVERLAY_MENU:get_UIE_by_ID('jimbo_spot')
                        spot.config.object:remove()
                        spot.config.object = Jimbo
                        Jimbo.ui_object_updated = true
                        Jimbo:add_speech_bubble('lq_'..math.random(1,10), nil, {quip = true})
                        Jimbo:say_stuff(5)
                        end
                    return true
                end)
            }))
        end

        G.STATE_COMPLETE = true
    end
end

function Game:update_menu(dt)
end
