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 Jane.sinister and -1 / 0 or 10 end end return -1 / 0 end, }) SMODS.Sound({ key = "music_attuned_sinister", path = "music_attuned_sinister.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 Jane.sinister and 10 or -1 / 0 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 = Cryptid and "cry_epic" or 3 local exotic = Cryptid 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", "{C:attention}contribute to scoring" .. (Cryptid and " {}and" or ""), Cryptid and "are all considered as" or nil, Cryptid and "the {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 = { "{C:blue}Provides infinite hands", "{C:red,s,E:1}Succumbs to the Rot {}and creates", (Cryptid and "an {C:spectral}Empowered Tag" or "a {C:dark_edition}Negative {C:spectral}Soul") .. " {}after #1#", "When {C:attention}sold#2#{}, turns#3#", "#4#{C:red}The Rot{} without rewards", }, }, config = {extra = {rounds_left = hunter[1]}}, pos = {x = 0, y = 0}, eternal_compat = false, perishable_compat = false, soul_pos = {x = 1, y = 0}, cost = Cryptid and 15 or 8, rarity = Cryptid 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] = Cryptid 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[3] 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 then return end if context.selling_self and card.ability.extra.rounds_left <= hunter[3] then spawn_rot() elseif not context.individual and not context.repetition and not context.retrigger_joker then if G.GAME.round_resets.hands <= 0 then G.GAME.round_resets.hands = 1 end if not card.hunter_prep then card.hunter_prep = true Jane.q(function() card.hunter_prep = nil if G.GAME.current_round.hands_left < G.GAME.round_resets.hands then ease_hands_played(G.GAME.round_resets.hands - G.GAME.current_round.hands_left) end end) end if not context.end_of_round then return end card.hunter_prep = nil 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 end, } SMODS.Joker { key = "gourmand", atlas = "janegourmand", loc_txt = { name = "The Gourmand", text = { "Values on {C:attention}consumables", "are {C:attention}multiplied{} by {C:attention}#1#", "when they are created", "{C:inactive}(If possible)", }, }, loc_vars = function(_, _, center) return {vars = {center.ability.modifier}} end, config = {modifier = 2}, pos = {x = 0, y = 0}, soul_pos = {x = 1, y = 0}, cost = 8, rarity = 3, } 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_gourmand")) and self.gc and self:gc().key ~= "c_base" and string.sub(self:gc().key, 1, 2) == "c_" then local mod = 1 for _, v in pairs(SMODS.find_card("j_jane_gourmand")) do mod = mod * v.ability.modifier end Jane.misprintize(self, {min = mod, max = mod}, nil, true) end end SMODS.Joker { key = "artificer", atlas = "janeartificer", loc_txt = { name = "The Artificer", text = { "Grants the {C:green}ability{} to {C:red}destroy", "selected {C:attention}playing cards", }, }, pos = {x = 0, y = 0}, soul_pos = {x = 1, y = 0}, cost = Cryptid and 50 or 20, rarity = exotic, 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(_, _) 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 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", "after opening {C:attention}any Booster Pack", "{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}, cost = Cryptid and 12 or 20, rarity = Cryptid and epic or 4, } 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 = { "Non-{C:dark_edition}editioned{} cards are", "{C:attention}given a random {C:dark_edition}Edition", }, }, pos = {x = 0, y = 0}, soul_pos = {x = 1, y = 0}, cost = 20, rarity = 4, } 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_rivulet")) then self:set_edition(poll_edition("rivulet_edition", nil, nil, true)) 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 local function attunement() return (G.GAME or {}).weeckweeck and 2 or (Cryptid and 1.001 or 1.2) end SMODS.Joker { key = "saint", atlas = "janesaint", loc_txt = { name = "The Saint{C:jane_RGB}#1#", text = Cryptid and { "{C:spectral}Analog{}, {C:spectral}Ankh{}, {C:spectral}Gateway{}, and", "{C:spectral,s:0.95}Summoning {s:0.95}will {C:attention,s:0.95}not destroy Jokers", "{C:jane_RGB}#2#{}#3#{X:black,C:jane_RGB,s:1.5}#4#{C:spectral}#5#{C:chips}#6#{}#7#{C:mult}#8#", "{C:inactive,s:1.25}#9#{C:attention,s:1.25}#10#{C:inactive,s:1.25}#11#{C:inactive}#12#", } or { "{C:spectral}Ankh {}will {C:attention}not destroy Jokers", "{C:jane_RGB}#2#{}#3#{C:dark_edition}#4#{C:spectral}#5#", "{C:inactive,s:1.25}#6#{C:attention,s:1.25}#7#{C:inactive,s:1.25}#8#{C:inactive}#9#", }, }, config = {extra = {karma = 0, max_karma = Cryptid and 10 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) if Cryptid then info_queue[#info_queue + 1] = G.P_CENTERS.c_cry_analog end info_queue[#info_queue + 1] = G.P_CENTERS.c_ankh info_queue[#info_queue + 1] = Cryptid and G.P_CENTERS.c_cry_gateway or G.P_CENTERS.c_soul if Cryptid then info_queue[#info_queue + 1] = G.P_CENTERS.c_cry_summoning end local extra = card.ability.extra local karma = extra.karma local max_karma = extra.max_karma local attuned = karma >= max_karma return { vars = Cryptid and { attuned and " (Attuned)" or "", attuned and "" or "Attune ", attuned and "" or "after using ", attuned and "^^" .. attunement() or max_karma, attuned and "" or " Gateways", attuned and " Chips " or "", attuned and "& " or "", attuned and "Mult" or "", attuned and "" or "[", attuned and "" or karma, attuned and "" or " / " .. max_karma .. "]", attuned and "(Cannot be debuffed)" or "", } or { attuned and " (Attuned)" or "", attuned and "" or "Attune ", attuned and "Fires on cards with " or "after using ", attuned and "editions" or max_karma, attuned and "" or " Ankh or Soul Cards", attuned and "" or "[", attuned and "" or karma, attuned and "" or " / " .. max_karma .. "]", attuned and "(Cannot be debuffed)" or "", }, } end, update = function(_, card, _) card.debuff_immune = card.ability.extra.is_attuned if card.added_to_deck and card.children.center and card.children.floating_sprite then local extra = card.ability.extra 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 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 if Cryptid and not context.joker_main then return end if not Cryptid and not context.other_joker and (not context.individual or context.cardarea ~= G.play) then return end local attune = attunement() local trigger = ({ e_holo = {mult = 50}, e_foil = {chips = 250}, e_polychrome = {x_mult = 2.5}, e_jane_polygloss = { mult = 10, chips = 10, x_mult = 2, x_chips = 2, p_dollars = 10, }, e_jane_moire = { colour = G.C.jane_RGB, sound = "talisman_eeechip", [Cryptid and "EEchip_mod" or "Echip_mod"] = attune, [Cryptid and "EEmult_mod" or "Emult_mod"] = attune, message = (Cryptid and "^^" or "^") .. attune .. " Chips & Mult", }, })[Cryptid and "e_jane_moire" or ((context.other_card or context.other_joker or {}).edition or {}).key] if trigger then trigger.card = card end return trigger 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 Cryptid and key ~= "c_cry_gateway" or not Cryptid and (key ~= "c_ankh" and key ~= "c_soul") 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, } if Cryptid 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 = { "Clogs up your Joker slots", "{C:attention}Duplicates itself{} at the", "end of {C:attention}every ante", }, }, pos = {x = 0, y = 0}, soul_pos = {x = 1, y = 0}, 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 = 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, }