SMODS.Atlas { px = 71, py = 95, key = "janedecks", path = Jane.config.texture_pack .. "/b_jane_decks.png", } local function back(x) local key = x.key local apply = x.apply local calculate = x.calculate x.apply = function(...) if apply and G.GAME.selected_sleeve ~= "sleeve_jane_" .. key then return apply(...) end Jane.q(function() save_run() end) end x.calculate = function(...) if calculate and G.GAME.selected_sleeve ~= "sleeve_jane_" .. key then return calculate(...) end end SMODS.Back(x) local text = x.loc_txt.text local name = x.loc_txt.name:gsub("Deck$", "Sleeve") if not CardSleeves then return end G.localization.descriptions.Sleeve = G.localization.descriptions.Sleeve or {} G.localization.descriptions.Sleeve["sleeve_jane_" .. key .. "_alt"] = x.alt_loc_txt CardSleeves.Sleeve { key = key, pos = x.pos, atlas = "janedecks", loc_txt = {name = name, text = text}, apply = function(self, ...) -- Game becomes genuinely unplayable if this is allowed. -- if self.get_current_deck_key() == "b_jane_omega" and G.GAME.selected_sleeve == "sleeve_jane_omega" then -- if apply then -- apply(self, ...) -- end -- if x.alt_apply then -- x.alt_apply(self, ...) -- end -- return -- end local a = (self.get_current_deck_key() == "b_jane_" .. key and x.alt_apply or apply) if a then a(self, ...) end Jane.q(function() save_run() end) end, calculate = function(self, ...) -- Game becomes genuinely unplayable if this is allowed. -- if self.get_current_deck_key() == "b_jane_omega" and G.GAME.selected_sleeve == "sleeve_jane_omega" then -- if calculate then -- calculate(self, ...) -- end -- if x.alt_calculate then -- x.alt_calculate(self, ...) -- end -- return -- end local c = (self.get_current_deck_key() == "b_jane_" .. key and x.alt_calculate or calculate) if c then return c(self, ...) end end, loc_vars = function(self, ...) local ret = x.loc_vars and x.loc_vars(self, ...) or {} ret.key = self.get_current_deck_key() == "b_jane_" .. key and self.key .. "_alt" or self.key return ret end, } end local eternal_text = Cryptid and "Absolute" or "Eternal" back { key = "nitro", atlas = "janedecks", pos = {x = 1, y = 1}, loc_txt = { name = "Acceleration Deck", text = { Cryptid and "" or "{C:attention}Ante increases twice{} as strong", "After defeating the {C:attention}Boss Blind{},", Cryptid and "set {C:attention}ante {}to the {C:attention}next" or "", Cryptid and "{C:attention}triangle number {}and create" or "", Cryptid and "an {C:spectral,E:1}Empowered Tag" or "create a {C:dark_edition}Negative {C:spectral,E:1}Soul", }, }, alt_loc_txt = { name = "Jolt Sleeve", text = { Cryptid and "{C:attention}Ante number {}scales with {C:attention}square numbers" or "{C:attention}Ante increases twice{} as strong", "After defeating the {C:attention}Small {}or {C:attention}Big Blind{},", Cryptid and "create a {C:spectral,E:1}Empowered Tag" or "create a {C:dark_edition}Negative {C:spectral,E:1}Soul", }, }, loc_vars = function(_, info_queue, _) if info_queue then info_queue[#info_queue + 1] = Cryptid and G.P_TAGS.tag_cry_empowered or G.P_CENTERS.c_soul end return {vars = {}} end, alt_apply = function(_) G.GAME.win_ante = Cryptid and G.GAME.win_ante * G.GAME.win_ante or G.GAME.win_ante * 4 - 1 G.GAME.alt_nitro = true G.GAME.nitro = true end, apply = function(_) G.GAME.win_ante = Cryptid and G.GAME.win_ante * (G.GAME.win_ante + 1) / 2 or G.GAME.win_ante * 2 - 1 G.GAME.nitro = true end, alt_calculate = function(_, _, context) if context.end_of_round and not context.individual and not context.repetition and not context.retrigger_joker then Jane.q(function() Jane.empowered() end) end end, calculate = function(_, _, context) if Jane.is_end_of_ante(context) then Jane.q(function() Jane.empowered() end) end end, } local rain_world_jokers = { "j_jane_monk", "j_jane_survivor", "j_jane_hunter", "j_jane_gourmand", "j_jane_artificer", "j_jane_spearmaster", "j_jane_rivulet", "j_jane_saint", "j_jane_rot", } local is_rain_world_joker = {} for _, v in pairs(rain_world_jokers) do is_rain_world_joker[v] = true end local function add_rain_world_joker() if not G.jokers then return end local unobtained = {} for _, v in pairs(rain_world_jokers) do if not next(SMODS.find_card(v, true)) then unobtained[#unobtained + 1] = v end end local chosen = pseudorandom_element(next(unobtained) and unobtained or rain_world_jokers, pseudoseed("karma_deck")) local card = create_card("Joker", G.jokers, nil, nil, nil, nil, chosen, "karma_deck_next") card:add_to_deck() card:start_materialize() G.jokers:emplace(card) end back { key = "karma", atlas = "janedecks", pos = {x = 3, y = 0}, loc_txt = { name = "Karma Deck", text = { "Start with a {C:legendary}Rain World Joker", "Create another when", "{C:attention}Boss Blind {}is defeated", }, }, alt_loc_txt = { name = "Ascension Sleeve", text = { "Start with all {C:legendary}Rain World Jokers {}instead", "Destroy a random {C:legendary}Rain World Joker {}when", "{C:attention}Boss Blind {}is defeated, or {C:red}lose", }, }, alt_apply = function(_) for _, v in ipairs(rain_world_jokers) do Jane.q(function() local card = create_card("Joker", G.jokers, nil, nil, nil, nil, v, "karma_deck_next") card:add_to_deck() card:start_materialize() G.jokers:emplace(card) play_sound("timpani") end, 0.2) end end, apply = function(_) Jane.q(add_rain_world_joker) end, alt_calculate = function(_, _, context) local function l() if G.STAGE == G.STAGES.RUN then G.STATE = G.STATES.GAME_OVER G.STATE_COMPLETE = false end end if not Jane.is_end_of_ante(context) then return end local destructible_jokers = {} for _, v in pairs(G.jokers.cards) do if is_rain_world_joker[v.config.center.key] and not ((v.ability or {}).eternal or (v.ability or {}).cry_absolute) then destructible_jokers[#destructible_jokers + 1] = v end end if not next(destructible_jokers) then return l() end local chosen = pseudorandom_element(destructible_jokers, pseudoseed("karma_deck")) if chosen then chosen.getting_sliced = true chosen:start_dissolve() end end, calculate = function(_, _, context) if Jane.is_end_of_ante(context) then add_rain_world_joker() end end, } back { key = "mysterious", atlas = "janedecks", pos = {x = 1, y = 0}, loc_txt = { name = "Mysterious Deck", text = { "Jokers, consumables, and", "playing cards are {C:green,E:1}randomized", "when they are added", "to your possession", }, }, alt_loc_txt = { name = "Sleeve?", text = {"{C:attention}Ante order {}is {C:green,E:1}randomized"}, }, alt_apply = function(_) G.GAME.mysterious = true G.GAME.alt_mysterious = {} for i = G.GAME.round_resets.ante + 1, G.GAME.round_resets.ante + G.GAME.win_ante - 1 do G.GAME.alt_mysterious[#G.GAME.alt_mysterious + 1] = {i} end pseudoshuffle(G.GAME.alt_mysterious, pseudoseed("mysterious_deck")) end, apply = function(_) G.GAME.mysterious = true end, alt_calculate = function(_, _, context) if context.setting_blind or context.skip_blind then G.GAME.mysterious_init = true end end, calculate = function(_, _, context) if context.setting_blind or context.skip_blind then G.GAME.mysterious_init = true end end, } local function redeem_omen_globe() G.GAME.used_vouchers.v_omen_globe = true G.GAME.starting_voucher_count = (G.GAME.starting_voucher_count or 0) + 1 Jane.q(function() Card.apply_to_run(nil, G.P_CENTERS.v_omen_globe) end) end back { key = "obsidian", atlas = "janedecks", pos = {x = 2, y = 1}, loc_txt = { name = "Obsidian Deck", text = { "{C:attention}Hidden{} cards {C:inactive}(ex. {C:spectral}Black Hole{C:inactive})", "can {C:attention}appear normally{}", "Start run with {C:tarot}Omen Globe", }, }, alt_loc_txt = { name = "Bedrock Sleeve", text = { "{C:attention}Non-hidden {}cards do", "not {C:attention}normally appear", }, }, loc_vars = function(_, info_queue, _) if info_queue then info_queue[#info_queue + 1] = G.P_CENTERS.v_omen_globe end return {vars = {}} end, alt_apply = function(_) G.GAME.alt_obsidian = true redeem_omen_globe() end, apply = function(_) G.GAME.obsidian = true redeem_omen_globe() end, } local function apply_orrery() Jane.q(function() local orrery = {} G.GAME.orrery = orrery for k, v in pairs(G.GAME.hands) do v.mult = 1 v.chips = 150 orrery[k] = {chips = v.chips, level = v.level, mult = v.mult} end save_run() end) end local function rebalance_orrery() local function small(x) return type(x) == "table" and x:to_number() or x end local function hand(name, chip, mul, lv, notif, snd, vol, pit, de) local config = { delay = de or 0.3, pitch = pit or 0.8, volume = vol or 0.7, sound = type(snd) == "string" and snd or type(snd) == "nil" and "button", } local vals = { level = lv or "?", mult = mul or "?", StatusText = notif, chips = chip or "?", handname = name or "????", } update_hand_text(config, vals) end local orrery = (G.GAME or {}).orrery if not orrery then return end local count = 0 local hands = {} local inequalities = 0 local pools = {chips = 0, level = 0, mult = 0} for k, v in pairs(G.GAME.hands) do if orrery[k] and (orrery[k].mult ~= v.mult or orrery[k].chips ~= v.chips or orrery[k].level ~= v.level) then inequalities = inequalities + 1 end count = count + 1 hands[#hands + 1] = v pools.mult = v.mult + pools.mult pools.chips = v.chips + pools.chips pools.level = v.level + pools.level end if inequalities == 0 then return end pools.chips = pools.chips + inequalities * 150 table.sort(hands, function(x, y) return x.order > y.order end) for i, v in ipairs(hands) do v.mult = math.floor(pools.mult / count) + (small(pools.mult % count) >= i and 1 or 0) v.chips = math.floor(pools.chips / count) + (small(pools.chips % count) >= i and 1 or 0) v.level = math.floor(pools.level / count) + (small(pools.level % count) >= i and 1 or 0) end for k, v in pairs(G.GAME.hands) do orrery[k] = {chips = v.chips, level = v.level, mult = v.mult} end hand(localize("k_all_hands"), math.floor(pools.chips / count), math.floor(pools.mult / count), math.floor(pools.level / count)) delay(1) update_hand_text({sound = "button", volume = 0.7, pitch = 1.1, delay = 0}, {mult = 0, chips = 0, handname = "", level = ""}) end back { key = "orrery", atlas = "janedecks", pos = {x = 0, y = 0}, loc_txt = { name = "Orrery Deck", text = { "{C:attention}Hand stats {}are", "always " .. (Cryptid and "{C:cry_ascendant}" or "{C:attention}") .. "equalized", }, }, alt_loc_txt = { name = "Ephemeris Sleeve", text = { "{C:blue}Hands{}, {C:red}discards{}, and {C:money}money", "are always " .. (Cryptid and "{C:cry_ascendant}" or "{C:attention}") .. "equalized", }, }, apply = function(_) apply_orrery() end, calculate = rebalance_orrery, alt_calculate = function(_, _, context) local function small(x) return type(x) == "table" and x:to_number() or x end if context.setting_blind or context.skip_blind then G.GAME.alt_orrery = true end if not G.GAME.alt_orrery then return end local dollars = G.GAME.dollars local hands = G.GAME.current_round.hands_left local discards = G.GAME.current_round.discards_left local sum = hands + discards + dollars local new_dollars = math.floor(sum / 3) - dollars local new_hands = small(math.floor((sum + 2) / 3)) - hands local new_discards = small(math.floor((sum + 1) / 3)) - discards if new_dollars ~= 0 then ease_dollars(new_dollars, true) end if new_hands ~= 0 then ease_hands_played(new_hands, true) end if new_discards ~= 0 then ease_discard(new_discards, true) end end, } back { key = "tortoise", atlas = "janedecks", pos = {x = 3, y = 1}, loc_txt = { name = "Tortoise Deck", text = { "{C:attention}Ante increases", "{C:attention}half{} as strong", }, }, alt_loc_txt = { name = "Sleepy Sleeve", text = { "{C:attention}Ante {}changes", "are {C:attention}inverted", }, }, alt_apply = function(_) G.GAME.tortoise = true G.GAME.alt_tortoise = true end, apply = function(_) G.GAME.tortoise = true end, } local function apply_weeck() G.GAME.weeck = true Jane.q(function() if G.GAME.selected_sleeve == "sleeve_jane_omega" then return end local new_card = create_card("Joker", G.jokers, nil, nil, nil, nil, "j_wee", "weeck") new_card.ability.cry_absolute = true new_card.ability.eternal = true G.jokers:emplace(new_card) local add = {} for _, v in pairs(G.playing_cards) do if v.base.id == 2 then v.ability.cry_absolute = true v.ability.eternal = true add[#add + 1] = v else v:start_dissolve(nil, true) end end for _, v in pairs(add) do local dupe = copy_card(v) dupe:start_materialize() dupe:add_to_deck() G.hand:emplace(dupe) G.playing_card = (G.playing_card and G.playing_card + 1) or 1 table.insert(G.playing_cards, dupe) end save_run() end) end local function two(x) if type(x) ~= "table" then return end for k, v in pairs(x) do if type(v) == "number" then x[k] = 2 elseif type(v) == "table" then two(v) end end end back { key = "weeck", atlas = "janedecks", pos = {x = 4, y = 1}, loc_txt = { name = "Weeck", text = { "Start with an {C:purple,E:1}" .. eternal_text, "{C:attention}Wee Joker {}and a deck", "containing {C:attention}2 {C:purple,E:1}" .. eternal_text, "{C:attention}2's {}of {C:attention}each suit", }, }, alt_loc_txt = { name = "Weeckweeck", text = { "Every stat and", "card number is {C:attention}2", "{C:inactive}(If possible)", }, }, alt_apply = function(_) local p = G.GAME.starting_params p.hands = 2 p.dollars = 2 p.discards = 2 p.hand_size = 2 G.GAME.skips = 2 p.joker_slots = 2 p.reroll_cost = 2 G.GAME.sunlevel = 2 p.boosters_in_shop = 2 p.consumable_slots = 2 p.vouchers_in_shop = 2 G.GAME.weeckweeck = true for _, v in pairs(G.GAME.hands) do v.mult = 2 v.chips = 2 v.level = 2 end apply_weeck() end, apply = function(_) apply_weeck() end, alt_calculate = function(_) for _, v in pairs(G.hand.cards) do two(v.ability) end for _, v in pairs(G.jokers.cards) do two(v.ability) end for _, v in pairs(G.consumeables.cards) do two(v.ability) end end, } local banned_keys = { sleeve_Seen_Seen = true, sleeve_jane_omega = true, } back { key = "omega", atlas = "janedecks", pos = {x = 5, y = 1}, loc_txt = { name = "Omega Deck", text = { "Applies the {C:legendary,E:1}upsides", "of {C:attention}every Jane deck", }, }, alt_loc_txt = { name = "Epsilon Sleeve", text = { "Applies {X:red,C:white}all{} effects of", "{C:attention}every deck and sleeve", "{X:black,C:red,E:2,s:2}UNPLAYABLE", }, }, alt_apply = function(_, ...) if (Bakery_API or {}).create_charm_area then Bakery_API.create_charm_area() end for _, v in pairs(G.P_CENTERS) do if v.apply and not banned_keys[v.key] and (v.set == "Back" or v.set == "Sleeve") then v:apply(...) end end end, apply = function(_) apply_orrery() G.GAME.used_vouchers.v_omen_globe = true G.GAME.starting_voucher_count = (G.GAME.starting_voucher_count or 0) + 1 Jane.q(function() local wee = create_card("Joker", G.jokers, nil, nil, nil, nil, "j_wee", "weeck") G.jokers:emplace(wee) add_rain_world_joker() G.GAME.tortoise = true G.GAME.obsidian = true G.GAME.mysterious = true save_run() end) end, alt_calculate = function(_, ...) for _, v in pairs(G.P_CENTERS) do if v.calculate and not banned_keys[v.key] and (v.set == "Back" or v.set == "Sleeve") then v:calculate(...) end end end, calculate = function(_, _, context) G.GAME.mysterious = nil if Jane.is_end_of_ante(context) then add_rain_world_joker() Jane.q(function() Jane.empowered() end) end end, } local orig_ante = ease_ante ---@diagnostic disable-next-line: lowercase-global function ease_ante(mod) local function next_number(x) if G.GAME.alt_nitro then local n = math.sqrt(x) + 1 return n * n end local n = (math.sqrt(8 * x + 1) - 1) / 2 return (n + 1) * (n + 2) / 2 end if G.GAME.alt_mysterious then if not next(G.GAME.alt_mysterious) then G.GAME.alt_mysterious = {} for i = G.GAME.round_resets.ante + 1, G.GAME.round_resets.ante + G.GAME.win_ante do G.GAME.alt_mysterious[#G.GAME.alt_mysterious + 1] = {i} end pseudoshuffle(G.GAME.alt_mysterious, pseudoseed("mysterious_deck")) end local target = G.GAME.alt_mysterious[#G.GAME.alt_mysterious][1] G.GAME.alt_mysterious[#G.GAME.alt_mysterious] = nil mod = target - G.GAME.round_resets.ante end if G.GAME.nitro then mod = Cryptid and (G.GAME.round_resets.ante < 0 and -G.GAME.round_resets.ante or math.ceil(next_number(G.GAME.round_resets.ante) - G.GAME.round_resets.ante)) or (mod > 0 and mod * 2 or mod) end if G.GAME.tortoise and mod > 0 then local remainder = 0 if mod % 2 == 1 then G.GAME.tortoise_halved = not G.GAME.tortoise_halved remainder = G.GAME.tortoise_halved and 0 or 1 end mod = math.floor(mod / 2) + remainder end if G.GAME.alt_tortoise then mod = mod * -1 end orig_ante(mod) end local orig_emplace = CardArea.emplace function CardArea:emplace(card, location, stay_flipped) local function randomize(targets, noanim) local function go(i) return function() local c = targets[i] c:set_base(pseudorandom_element(G.P_CARDS)) if pseudorandom(pseudoseed("chancetime")) > 1 / (#G.P_CENTER_POOLS["Enhanced"] + 1) then c:set_ability(pseudorandom_element(G.P_CENTER_POOLS["Enhanced"], pseudoseed("spectral_chance"))) else c:set_ability(G.P_CENTERS["c_base"]) end local edition_rate = 2 c:set_edition(poll_edition("standard_edition" .. G.GAME.round_resets.ante, edition_rate, true)) local seal_rate = 10 local seal_poll = pseudorandom(pseudoseed("stdseal" .. G.GAME.round_resets.ante)) if seal_poll > 1 - 0.02 * seal_rate then local seal_type = pseudorandom(pseudoseed("stdsealtype" .. G.GAME.round_resets.ante)) local seal_list = {} for k, _ in pairs(G.P_SEALS) do table.insert(seal_list, k) end seal_type = math.floor(seal_type * #seal_list) c:set_seal(seal_list[seal_type]) else c:set_seal() end if noanim then c:flip() play_sound("card3", 0.85 + (i - 0.999) / (#G.hand.cards - 0.998) * 0.3, 0.6) end c:juice_up(0.3, 0.3) end end if #targets <= 0 then return end if noanim then for i = 1, #targets do go(i) end else for i = 1, #targets do Jane.q(function() targets[i]:flip() play_sound("card1", 1.15 - (i - 0.999) / (#G.hand.cards - 0.998) * 0.3) targets[i]:juice_up(0.3, 0.3) end, 0.15) Jane.q(function() targets[i]:flip() play_sound("card1", 1.15 - (i - 0.999) / (#G.hand.cards - 0.998) * 0.3) targets[i]:juice_up(0.3, 0.3) end, 0.15) end delay(0.2) for i = 1, #targets do Jane.q(go(i), 0.1) end end end local function rnd(seed, excluded_flags, pool, ignore_pooling, attempts) excluded_flags = excluded_flags or {} local selection = "n/a" local passes = 0 local tries = attempts or 500 local pooling = false if (SMODS.Mods.jane or {}).can_load and (G.GAME or {}).obsidian then for k, v in ipairs(excluded_flags) do if v == "hidden" then table.remove(excluded_flags, k) break end end end while true do passes = 0 pooling = false tries = tries - 1 local sd = pseudoseed(seed or "jane_rnd_mysterious") selection = G.P_CENTERS[pseudorandom_element(pool or G.P_CENTER_POOLS.Consumeables, sd).key] if ignore_pooling then pooling = true else if selection.in_pool and selection:in_pool() then pooling = true elseif not selection.in_pool then pooling = true end end for _, v in pairs(excluded_flags) do if not selection[v] then passes = passes + 1 end end if (pooling and passes >= #excluded_flags) or tries <= 0 then return selection end end end if G.jokers and G.hand and G.deck and G.consumeables and (self == G.jokers or self == G.hand or self == G.deck or self == G.consumeables) and G.GAME.mysterious and card.ability and not card.ability.mysterious_created and not card.created_from_split then card.ability.mysterious_created = true local cen = card.gc and card:gc() if cen then if self == G.jokers then Jane.q(function() if card then if card.added_to_deck then card:remove_from_deck() card.added_to_deck = nil end card:flip() card:juice_up(0.3, 0.3) play_sound("card1", 1, 0.6) end end, 0.75) delay(0.75) Jane.q(function() if card then card:flip() card:juice_up(0.3, 0.3) play_sound("card3", 1, 0.6) card:set_ability(rnd("mysterious_deck_joker", {"no_mysterious"}, G.P_CENTER_POOLS.Joker)) if not card.added_to_deck then card:add_to_deck() end end end, 0.75) elseif self == G.consumeables then Jane.q(function() if card then if card.added_to_deck then card:remove_from_deck() card.added_to_deck = nil end card:flip() card:juice_up(0.3, 0.3) play_sound("card1", 1, 0.6) end end, 0.75) delay(0.75) Jane.q(function() if card then card:flip() card:juice_up(0.3, 0.3) play_sound("card3", 1, 0.6) card:set_ability( rnd("mysterious_deck_consumable", cen.hidden and {} or {"hidden"}, G.P_CENTER_POOLS[cen.set]) ) if not card.added_to_deck then card:add_to_deck() end end end, 0.75) elseif (card.base or {}).value or (card.base or {}).suit then randomize({card}, not G.GAME.mysterious_init) end end Jane.q(function() if card and self then orig_emplace(self, card, location, stay_flipped) end end) else orig_emplace(self, card, location, stay_flipped) end end