SMODS.Sound({key = "enlightened", path = "enlightened.ogg"}) SMODS.Sound({key = "warning_heartbeat", path = "warning_heartbeat.ogg"}) for i = 1, 8 do SMODS.Sound({key = "gore" .. i, path = "gore" .. i .. ".ogg"}) end SMODS.Sound({ key = "music_attuned", path = "music_attuned.ogg", volume = 1, select_music_track = function() for _, v in pairs(SMODS.find_card("j_jane_saint")) do if v.ability.extra.is_attuned then return 201 end end return -1 / 0 end, }) SMODS.Sound({ key = "music_attuned_sinister", path = "music_attuned_sinister.ogg", volume = 1, select_music_track = function() if not Jane.sinister then return -1 / 0 end for _, v in pairs(SMODS.find_card("j_jane_saint")) do if v.ability.extra.is_attuned then return 202 end end return -1 / 0 end, }) for _, v in pairs({ "artificer", "hunter", "gourmand", "monk", "rivulet", "rot", "saint", "spearmaster", "survivor", }) do SMODS.Atlas { key = "jane" .. v, px = 71, py = 95, path = Jane.config.texture_pack .. "/j_jane_" .. v .. ".png", } end local epic = Jane.cry and "cry_epic" or 3 local exotic = Jane.cry and "cry_exotic" or 4 SMODS.Rarity { key = "junk", default_weight = 1e-9, loc_txt = {name = "Junk"}, badge_colour = G.C.JOKER_GREY, } local monk_limit = 25 SMODS.Joker { key = "monk", atlas = "janemonk", loc_txt = { name = "The Monk", text = { "{C:attention}Retrigger {}scored", "cards {C:attention}#1# time#2# {}if", "hand contains {C:attention}#3#", "or fewer card#4#", }, }, config = {extra = {retriggers = 2, requirement = 4}}, pos = {x = 0, y = 0}, soul_pos = {x = 1, y = 0}, cost = 20, rarity = 4, blueprint_compat = true, loc_vars = function(_, _, card) local extra = card.ability.extra local retriggers = extra.retriggers local requirement = extra.requirement return { vars = { retriggers, retriggers == 1 and "" or "s", requirement, requirement == 1 and "" or "s", }, } end, calculate = function(_, card, context) if not context.repetition or context.cardarea ~= G.play or not context.other_card or #G.play.cards > card.ability.extra.requirement then return end local min = math.min(card.ability.extra.retriggers, monk_limit) card.ability.extra.retriggers = min return { card = card, repetitions = min, colour = G.C.ORANGE, message = localize("k_again_ex"), }, true end, } SMODS.Joker { key = "survivor", atlas = "janesurvivor", loc_txt = { name = "The Survivor", text = { "All cards held in", "hand also {C:attention}score" .. (Jane.cry and " {}and" or ""), Jane.cry and "considered as the" or nil, Jane.cry and "{C:attention}first {}played card" or nil, }, }, pos = {x = 0, y = 0}, soul_pos = {x = 1, y = 0}, cost = 20, rarity = 4, } local hunter = {5, 4, 3, 2, 1} SMODS.Joker { key = "hunter", atlas = "janehunter", loc_txt = { name = "The Hunter", text = { "{E:1}Succumbs to the {X:black,C:white,E:1}Rot{},", (Jane.cry and "creating an {C:spectral}Empowered" or "creating a {C:dark_edition}Negative"), (Jane.cry and "{C:spectral}Tag" or "{C:spectral}Soul") .. " {}after #1#", }, }, config = {extra = {rounds_left = hunter[1]}}, pos = {x = 0, y = 0}, eternal_compat = false, blueprint_compat = false, perishable_compat = false, soul_pos = {x = 1, y = 0}, cost = Jane.cry and 15 or 8, rarity = Jane.cry and epic or 3, loc_vars = function(_, info_queue, card) local function rounds(amount) return " round" .. ((math.abs(amount) > 1 or math.abs(amount) == 0) and "s" or "") end info_queue[#info_queue + 1] = G.P_CENTERS.j_jane_rot info_queue[#info_queue + 1] = Jane.cry and G.P_CENTERS.c_cry_empowered or G.P_CENTERS.c_soul local rounds_left = card.ability.extra.rounds_left local sold = rounds_left - hunter[5] return { vars = { rounds_left .. rounds(rounds_left) .. (rounds_left <= 0 and "...?" or ""), sold <= 0 and "" or " after " .. sold .. rounds(sold), sold <= 0 and " into" or "", sold <= 0 and "" or "into ", }, } end, update = function(_, card, _) if card.added_to_deck and card.children.center and card.children.floating_sprite then for k, v in ipairs(hunter) do if card.ability.extra.rounds_left <= v then card.children.center:set_sprite_pos({x = 0, y = k - 1}) card.children.floating_sprite:set_sprite_pos({x = 1, y = k - 1}) else break end end end end, calculate = function(_, card, context) local function spawn_rot() card:flip() card:juice_up(2, 0.8) card.getting_sliced = true Jane.card_status_text(card, "Dead!", nil, 0.05 * card.T.h, G.C.BLACK, 2, 0, 0, nil, "bm", "jane_gore6") Jane.q(function() local card2 = create_card("Joker", G.jokers, nil, nil, nil, nil, "j_jane_rot", "hunter_rot_death") card2:add_to_deck() G.jokers:emplace(card2) card:set_eternal(nil) card2:set_eternal(true) play_sound("jane_gore5") end) Jane.q(function() card:start_dissolve() end, 1) end local function die() Jane.q(function() Jane.empowered() end, 0.1) spawn_rot() end if context.blueprint or context.individual or context.repetition or context.retrigger_joker or not context.end_of_round then return end card.ability.extra.rounds_left = card.ability.extra.rounds_left - 1 local rl = card.ability.extra.rounds_left Jane.card_status_text(card, tostring(card.ability.extra.rounds_left), nil, nil, G.C.RED, nil, nil, nil, nil, nil, "generic1") if rl > hunter[2] then card:juice_up(0.6, 0.1) elseif rl > hunter[3] then if rl == hunter[2] then Jane.play_sound("jane_gore1") end card:juice_up(0.6, 0.1) elseif rl > hunter[4] then if rl == hunter[3] then Jane.play_sound("jane_gore3") end card:juice_up(0.6, 0.1) elseif rl > hunter[5] then if rl == hunter[4] then Jane.play_sound("jane_gore8") end card:juice_up(0.6, 0.1) Jane.play_sound("jane_warning_heartbeat") elseif rl > 0 then if rl == hunter[5] then Jane.play_sound("jane_gore4") end card:juice_up(1.8, 0.3) Jane.play_sound("jane_warning_heartbeat") else card:juice_up(2, 0.8) Jane.play_sound("jane_warning_heartbeat") Jane.q(die, 0) end end, } SMODS.Joker { key = "gourmand", atlas = "janegourmand", loc_txt = { name = "The Gourmand", text = {"All cards are {C:dark_edition}Jumbo"}, }, pos = {x = 0, y = 0}, soul_pos = {x = 1, y = 0}, blueprint_compat = false, cost = 20, rarity = 4, loc_vars = function(_, info_queue) info_queue[#info_queue + 1] = G.P_CENTERS.e_jane_jumbo end, } local function add_to_consumable_ability_by(n) local f = SMODS.Mods.Roland.qol[1] local function new(v) return type(v) == "number" and v + n or type(v) == "table" and f(v):map(new):table() or v end ---@param card Card return function(card) local ability = card.ability or {} local function go(key) ---@type { [string]: number }|number local value = ability[key] --print(key) if not value then return end if type(value) == "number" then ability[key] = value + n return end if type(value) ~= "table" then return end local new_value = f(value):map(new):table() f(new_value):each(function(v, k) ability[k] = v end) ability[key] = new_value end local center_key = (card.config or {}).center_key if center_key and center_key:sub(1, 2) == "c_" then f {"extra", "consumeable"}:each(go) end end end local orig_set_ability = Card.set_ability ---@diagnostic disable-next-line: duplicate-set-field function Card:set_ability(center, initial, delay_sprites) orig_set_ability(self, center, initial, delay_sprites) if next(SMODS.find_card("j_jane_rivulet")) and self.gc and self:gc().key ~= "c_base" and string.sub(self:gc().key, 1, 2) == "c_" then if Jane.cry or not ((SMODS.Mods.Roland or {}).qol or {})[1] then local mod = 1 for _, v in pairs(SMODS.find_card("j_jane_rivulet")) do mod = mod * v.ability.modifier end Jane.misprintize(self, {min = mod, max = mod}, nil, true) else local mod = 0 for _, v in pairs(SMODS.find_card("j_jane_rivulet")) do mod = mod + v.ability.modifier end add_to_consumable_ability_by(mod)(self) end end end SMODS.Joker { key = "artificer", atlas = "janeartificer", loc_txt = { name = "The Artificer", text = { "Use to {C:red}destroy", "selected {C:attention}playing cards", not Jane.cry and "{C:red,E:1}Self-destructs" or nil, not Jane.cry and "after {C:attention}#1# #2#" or nil, }, }, pos = {x = 0, y = 0}, soul_pos = {x = 1, y = 0}, config = {extra = {uses = 2}}, eternal_compat = false, blueprint_compat = false, cost = Jane.cry and 50 or 7, rarity = Jane.cry and exotic or 3, loc_vars = function(_, _, card) card.ability = card.ability or {} card.ability.extra = card.ability.extra or {} card.ability.extra.uses = card.ability.extra.uses or 2 local uses = card.ability.extra.uses return {vars = {uses, uses == 1 and "use" or "uses"}} end, Bakery_use_button_text = function(_, _) return "DESTROY" end, Bakery_can_use = function(_, card) return not card.debuff and Jane.can_use() and next(G.hand.highlighted) end, Bakery_use_joker = function(_, card) for _, v in pairs(SMODS.find_card("j_jane_oxy")) do Jane.oxy(v, G.hand.highlighted) end for _, v in pairs(G.hand.highlighted) do v:start_dissolve() end if Jane.cry then return end card.ability.extra.uses = card.ability.extra.uses - 1 local _ = card.ability.extra.uses <= 0 and card:start_dissolve() local _ = card.ability.extra.uses == 1 and juice_card_until(card, function() return card.area == G.jokers end, true) end, } local spearmaster_limit = 25 SMODS.Joker { key = "spearmaster", atlas = "janespearmaster", loc_txt = { name = "The Spearmaster", text = { "You can choose {C:attention}any", "number of cards", "in {C:attention}Booster Packs", "{C:attention}Booster Packs{} have", "{C:green}+#1#{} additional cards", }, }, config = {extra = {choices = 1}}, loc_vars = function(_, _, card) return {vars = {card.ability.extra.choices}} end, calculate = function(_, card, _) card.ability.extra.choices = math.min(card.ability.extra.choices, spearmaster_limit) end, pos = {x = 0, y = 0}, soul_pos = {x = 1, y = 0}, blueprint_compat = false, cost = Jane.cry and 12 or 20, rarity = Jane.cry and epic or 4, Bakery_can_use = function(_, card) if card.debuff or not Jane.can_use() or not ((G.pack_cards or {}).cards or {})[1] then return false end local ret = false for _, v in pairs(G.pack_cards.cards) do if v.jane_spearmaster then return false elseif ((v.ability or {}).consumeable or {}).hand_type then ret = true end end return ret end, Bakery_use_button_text = function() return "USE ALL" end, Bakery_use_joker = function(self, card) if not self:Bakery_can_use(card) then return end local c = G.pack_cards.cards for i = #c, 1, -1 do if ((c[i].ability or {}).consumeable or {}).hand_type then c[i].jane_spearmaster = true c[i]:use_consumeable() SMODS.calculate_context {using_consumeable = true, consumeable = c[i], area = c[i].from_area} local normal = c[i].area ~= G.pack_cards c[i]:start_dissolve() if not normal then G.GAME.pack_choices = G.GAME.pack_choices - 1 local _ = G.GAME.pack_choices <= 0 and G.FUNCS.end_consumeable() end end end end, } local orig_open = Card.open ---@diagnostic disable-next-line: duplicate-set-field function Card:open() local orig = self.ability.extra or 1 local spearmasters = SMODS.find_card("j_jane_spearmaster") if next(spearmasters) then for _, v in pairs(spearmasters) do orig = orig + v.ability.extra.choices end self.config.choose = math.floor(orig) self.ability.extra = math.floor(orig) end orig_open(self) Jane.q(function() if next(spearmasters) then G.GAME.pack_choices = math.floor(self.ability.extra) end end, 0.5, "REAL") end SMODS.Joker { key = "rivulet", atlas = "janerivulet", loc_txt = { name = "The Rivulet", text = { "Values on {C:attention}consumables", "are {C:attention}" .. (Jane.cry and "multiplied" or "added") .. "{} by {C:attention}#1#" .. (Jane.cry and "" or "{} when"), (Jane.cry and "when " or "") .. "they are created", "{C:inactive}(If possible)", }, }, config = {modifier = Jane.cry and 2 or 1}, pos = {x = 0, y = 0}, soul_pos = {x = 1, y = 0}, blueprint_compat = false, cost = 8, rarity = 3, loc_vars = function(_, _, center) return {vars = {center.ability.modifier}} end, } local orig_draw = Card.draw function Card:draw(layer) local cen = self.gc and self:gc() if self.children.floating_sprite and cen.sinis then if Jane.sinister and not self.shows_sinister then self.shows_sinister = true self.children.floating_sprite:set_sprite_pos(cen.sinis) elseif not Jane.sinister and self.shows_sinister then self.shows_sinister = nil self.children.floating_sprite:set_sprite_pos(cen.soul_pos) end if self.shows_sinister then self:juice_up(0, math.random()) end end if cen and self.facing == "front" and self.config and (self.added_to_deck or (self.area and self.area == G.hand)) and not self.edition and (self.area == G.consumeables or cen.set ~= "Booster") and next(SMODS.find_card("j_jane_gourmand")) then self:set_edition("e_jane_jumbo") end orig_draw(self, layer) end local orig_debuff = Card.set_debuff function Card:set_debuff(should_debuff) if should_debuff and ((self.config or {}).center or {}).debuff_immune then Jane.card_status_text(self, "Immune", nil, 0.05 * self.T.h, G.C.RED, nil, 0.6, nil, nil, "bm", "cancel", 1, 0.9) return false else orig_debuff(self, should_debuff) end end SMODS.Joker { key = "saint", atlas = "janesaint", loc_txt = { name = {"{}", "#1#{C:jane_RGB,s:0.8}#2#", "{C:jane_RGB,s:1.6}#3#"}, text = { "{C:attention}Use {}to toggle itself or", "other Jokers to its", "left's {X:legendary,C:white}Eternal{} sticker", "{C:attention}#4#{}#5#{X:black,C:jane_RGB}#6#{C:spectral}#7#", "{C:inactive}#8#{C:attention}#9#{C:inactive}#10#", Jane.cry and "{C:inactive}(Gateway has no downside)" or nil, }, }, config = {extra = {karma = 0, max_karma = Jane.cry and 20 or 3}}, pos = {x = 0, y = 0}, soul_pos = {x = 1, y = 0}, cost = 20, rarity = 4, blueprint_compat = true, loc_vars = function(_, info_queue, card) info_queue[#info_queue + 1] = Jane.cry and G.P_CENTERS.c_cry_gateway or G.P_CENTERS.c_ankh local extra = card.ability.extra local karma = extra.karma local max_karma = extra.max_karma local attuned = karma >= max_karma return { vars = { attuned and "" or "The Saint", attuned and "The" or "", attuned and "Attuned" or "", attuned and "" or "Attune ", attuned and "alongside its " or "after ", attuned and "Edition" or max_karma, attuned and "" or (Jane.cry and " Gateways" or " Ankhs"), attuned and "" or "[", attuned and "" or karma, attuned and "(Cannot be debuffed)" or " / " .. max_karma .. "]", }, } end, update = function(_, card, _) local extra = card.ability.extra card.debuff_immune = extra.is_attuned if card.children.floating_sprite then card.children.floating_sprite:set_sprite_pos({x = extra.is_attuned and 2 or 1, y = 0}) end end, calculate = function(_, card, context) local extra = card.ability.extra local max_karma = extra.max_karma extra.is_attuned = extra.is_attuned and extra.karma >= max_karma G.GAME.spectral_rate = math.max(G.GAME.spectral_rate, extra.is_attuned and 20 or 2) local function ascend() if extra.is_attuning then return end extra.is_attuning = true Jane.card_status_text( card, "!!!", nil, 0.05 * card.T.h, G.C.DARK_EDITION, 0.6, 0.6, 2, 2, "bm", "jane_enlightened" ) Jane.q(function() card:flip() play_sound("card1") end, 0.1) Jane.q(function() card:flip() card:juice_up(1, 1) play_sound("card1") extra.is_attuned = true end, 1) end if extra.is_attuned then card.debuff = false if card.ability then card.ability.perishable = false card.ability.perish_tally = 1e9 end elseif extra.karma >= max_karma then ascend() end if not (not context.blueprint and (not context.retrigger_joker_check and not context.retrigger_joker) and context.using_consumeable and context.consumeable) then return end local key = context.consumeable:gc().key if Jane.cry and key ~= "c_cry_gateway" or not Jane.cry and key ~= "c_ankh" then return end local quota = context.consumeable.getEvalQty and context.consumeable:getEvalQty() or 1 extra.karma = extra.karma + quota card_eval_status_text( card, "extra", nil, nil, nil, {message = "+" .. quota .. " Karma", colour = G.C.PALE_GREEN} ) card_eval_status_text( card, "extra", nil, nil, nil, {message = extra.karma .. " / " .. max_karma, colour = G.C.GREEN} ) if extra.karma < max_karma then return end ascend() end, Bakery_can_use = Jane.can_use, Bakery_use_joker = function(_, card) for joker_index = 1, math.max(card.rank - 1, 1) do local joker = G.jokers.cards[joker_index] joker:set_eternal(not joker.ability.eternal) if joker.Roland_frozen_ability then joker.Roland_frozen_ability.eternal = joker.ability.eternal end if not card.ability.extra.is_attuned or joker.ability.eternal then joker:juice_up() goto continue end local edition = 1 for ii, vv in ipairs(joker.edition and G.P_CENTER_POOLS.Edition or {}) do if vv.key == joker.edition.key then edition = ii break end end local next = edition < #G.P_CENTER_POOLS.Edition and edition + 1 or 1 joker:set_edition(G.P_CENTER_POOLS.Edition[next].key) ::continue:: end end, } if Cryptid and Cryptid.aliases then Cryptid.aliases["saint"] = "j_jane_saint" Cryptid.aliases["the saint"] = "j_jane_saint" end SMODS.Joker { key = "rot", atlas = "janerot", loc_txt = { name = "The Rot", text = { Jane.cry and "{C:attention}Duplicates itself{} at the" or "{C:inactive,E:1}Does nothing", Jane.cry and "end of {C:attention}every ante" or nil, }, }, pos = {x = 0, y = 0}, soul_pos = {x = 1, y = 0}, blueprint_compat = true, cost = 1, rarity = "jane_junk", in_pool = function(_, _) for _, v in pairs(SMODS.find_card("j_jane_honey")) do if tonumber(v.ability.extra.level) == #Jane.rarity_ids - 1 then return true end end return not not next(SMODS.find_card("j_jane_rot")) end, calculate = Jane.cry and function(_, card, context) local function has_room() return G.jokers.config.card_count < G.jokers.config.card_limit end local function spawn() if card.cloned then return end local rot = copy_card(card) rot.cloned = true rot:add_to_deck() G.jokers:emplace(rot) Jane.card_status_text(rot, "...", nil, 0.05 * card.T.h, G.C.BLACK, 3, 0, 0, nil, "bm") end if has_room() and not card.cloned and Jane.is_end_of_ante(context, card) then Jane.q(spawn, 0.5) else card.cloned = false end end or nil, }