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 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", loc_txt = {name = "Junk"}, badge_colour = G.C.JOKER_GREY, } 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 return { message = localize("k_again_ex"), repetitions = card.ability.extra.retriggers, colour = G.C.ORANGE, card = card }, true end } SMODS.Joker { key = "survivor", atlas = "janesurvivor", loc_txt = { name = "The Survivor", text = { "All cards held in hand", "{C:attention}contribute to scoring {}and", "are all considered as", "the {C:attention}first played card", } }, pos = {x = 0, y = 0}, soul_pos = {x = 1, y = 0}, cost = 20, rarity = 4, } local hunter = {7, 5, 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, soul_pos = {x = 1, y = 0}, cost = Cryptid and 20 or 8, rarity = Cryptid and 4 or 3, loc_vars = function(_, _, card) local function rounds(amount) return " round" .. ((math.abs(amount) > 1 or math.abs(amount) == 0) and "s" or "") end local rounds_left = card.ability.extra.rounds_left local sold = rounds_left - hunter[2] 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) 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") return true end) end local function die() spawn_rot() Jane.q(function() Jane.empowered() return true end, 0.1) Jane.q(function() card:start_dissolve() return true end, 1) return true end if context.blueprint then return end if context.selling_self and card.ability.extra.rounds_left <= hunter[2] 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() 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 return true end) return true 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") G.E_MANAGER:add_event(Event({trigger = "after", func = die})) 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(G.hand.highlighted) do v:start_dissolve() end end, } 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", } }, loc_vars = function(_, _, center) return {vars = {center.ability.extra.extrachoices}} end, config = {extra = {extrachoices = 1}}, 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.extrachoices end self.config.choose = math.floor(orig) self.ability.extra = math.floor(orig) end orig_open(self) G.E_MANAGER:add_event(Event({ delay = 0.5, timer = "REAL", func = function() if next(spearmasters) then G.GAME.pack_choices = math.floor(self.ability.extra) end return true end })) 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 function attunement() local function polygloss(tbl) local sum = 0 for _, v in pairs(tbl) do if (v.edition or {}).key == "e_jane_polygloss" then sum = sum + 1 end end return sum end if Cryptid then return 1.001 end local cards = polygloss(G.playing_cards) + polygloss(G.jokers.cards) + polygloss(G.consumeables.cards) local base = 1.01 local round = 100 local expo = cards * 2 local error_correction = 1e-10 return math.floor(base ^ expo * round + error_correction) / round end SMODS.Joker { key = "saint", atlas = "janesaint", loc_txt = { name = "The Saint{C:jane_RGB}#1#", text = { "{C:spectral}#2# {}will {C:attention}not destroy Jokers", "{C:jane_RGB}#3#{}#4#{X:black,C:jane_RGB,s:1.5}#5#{C:spectral}#6#{C:chips}#7#{}#8#{C:mult}#9#", "{C:inactive,s:1.25}#10#{C:attention,s:1.25}#11#{C:inactive,s:1.25}#12#{C:inactive}#13#{C:jane_RGB}#14#{C:inactive}#15#", } }, 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(_, _, card) local extra = card.ability.extra local karma = extra.karma local max_karma = extra.max_karma local attuned = karma >= max_karma return {vars = { attuned and " (Attuned)" or "", Cryptid and "Ankh and Gateway" or "Ankh", attuned and "" or "Attune ", attuned and "" or "after using ", attuned and (Cryptid and "^^" or "^") .. attunement() or max_karma, attuned and "" or (Cryptid and " Gateways" or " Ankh or Soul Cards"), 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" .. (Cryptid and "" or ", scales with ") or "", attuned and (Cryptid and "" or "polygloss") or "", attuned and ")" or "", }} end, update = function(_, card, _) 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.karma >= max_karma if extra.karma >= max_karma then if card.ability then card.ability.perishable = false card.ability.perish_tally = 1e9 end card.debuff = false if not context.joker_main then return end local attune = attunement() if attune == 1 then return end return { card = card, colour = G.C.jane_RGB, sound = "talisman_eeechip", message = "^^" .. attune .. " Chips & Mult", [Cryptid and "EEchip_mod" or "Echip_mod"] = attune, [Cryptid and "EEmult_mod" or "Emult_mod"] = attune, }, true 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 -- TODO: Make ankh not destroy jokers 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 Jane.card_status_text( card, "!!!", nil, 0.05 * card.T.h, G.C.DARK_EDITION, 0.6, 0.6, 2, 2, "bm", "jane_enlightened" ) G.E_MANAGER:add_event(Event({ delay = 0.1, func = function() card:flip() play_sound("card1") return true end })) G.E_MANAGER:add_event(Event({ delay = 1, func = function() card:flip() card:juice_up(1, 1) play_sound("card1") extra.is_attuned = true return true end })) 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 (_, _) 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 is_end_of_ante() return not context.individual and not context.repetition and not card.debuff and context.end_of_round and not context.blueprint and G.GAME.blind.boss and not (G.GAME.blind.config and G.GAME.blind.config.bonus) end local function spawn() 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 is_end_of_ante() then spawn() else card.cloned = false end end }