--TIP!!! for coding exotics, make sure you know which layer corresponds to which value!
--The Normal pos correponds to the background. use this for the layer that goes all the way in the back!
--The soul_pos = {blahblahblah, extra = {blahblahblah}} correspomds to the other two layers. the value in the extra table is for the layer that goes in the middle, and the other value is the one that goes all the way in the front
local gateway = {
	dependencies = {
		items = {
			"set_cry_exotic",
		},
	},
	object_type = "Consumable",
	set = "Spectral",
	name = "cry-Gateway",
	key = "gateway",
	pos = { x = 0, y = 0 },
	cost = 4,
	atlas = "atlasnotjokers",
	order = 90,
	hidden = true, --default soul_set and soul_rate of 0.3% in spectral packs is used
	can_use = function(self, card)
		--Don't allow use if everything is eternal and there is no room
		return #Cryptid.advanced_find_joker(nil, nil, nil, { "eternal" }, true, "j") < G.jokers.config.card_limit
	end,
	use = function(self, card, area, copier)
		local deletable_jokers = {}
		for k, v in pairs(G.jokers.cards) do
			if not SMODS.is_eternal(v) then
				deletable_jokers[#deletable_jokers + 1] = v
			end
		end
		local _first_dissolve = nil
		G.E_MANAGER:add_event(Event({
			trigger = "before",
			delay = 0.75,
			func = function()
				for k, v in pairs(deletable_jokers) do
					if v.config.center.rarity == "cry_exotic" then
						check_for_unlock({ type = "what_have_you_done" })
					end
					v:start_dissolve(nil, _first_dissolve)
					_first_dissolve = true
				end
				return true
			end,
		}))
		G.E_MANAGER:add_event(Event({
			trigger = "after",
			delay = 0.4,
			func = function()
				play_sound("timpani")
				local card = create_card("Joker", G.jokers, nil, "cry_exotic", nil, nil, nil, "cry_gateway")
				card:add_to_deck()
				G.jokers:emplace(card)
				card:juice_up(0.3, 0.5)
				return true
			end,
		}))
		delay(0.6)
	end,
	demicoloncompat = true,
	force_use = function(self, card, area)
		self:use(card, area)
	end,
}
local iterum = {
	dependencies = {
		items = {
			"c_cry_gateway",
			"set_cry_exotic",
		},
	},
	object_type = "Joker",
	name = "cry-Iterum",
	key = "iterum",
	config = {
		extra = {
			x_mult = 2,
			repetitions = 1,
		},
		immutable = {
			max_repetitions = 40,
		},
	},
	pos = { x = 0, y = 1 },
	rarity = "cry_exotic",
	order = 500,
	cost = 50,
	blueprint_compat = true,
	demicoloncompat = true,
	atlas = "atlasexotic",
	soul_pos = { x = 1, y = 1, extra = { x = 2, y = 1 } },
	loc_vars = function(self, info_queue, center)
		return {
			vars = {
				number_format(center.ability.extra.x_mult),
				math.min(center.ability.immutable.max_repetitions, center.ability.extra.repetitions),
				center.ability.immutable.max_repetitions,
			},
		}
	end,
	calculate = function(self, card, context)
		if context.repetition then
			if context.cardarea == G.play then
				return {
					message = localize("k_again_ex"),
					repetitions = to_number(
						math.min(card.ability.immutable.max_repetitions, card.ability.extra.repetitions)
					),
					card = card,
				}
			end
		elseif context.individual then
			if context.cardarea == G.play then
				return {
					x_mult = card.ability.extra.x_mult,
					colour = G.C.RED,
					card = card,
				}
			end
		end
		if context.forcetrigger then
			return {
				x_mult = card.ability.extra.x_mult,
				colour = G.C.RED,
				card = card,
			}
		end
	end,
	cry_credits = {
		idea = { "Math", "Project666" },
		art = { "Ein13" },
		code = { "Math" },
	},
}
local universum = {
	dependencies = {
		items = {
			"c_cry_gateway",
			"set_cry_exotic",
		},
	},
	object_type = "Joker",
	name = "cry-Universum",
	key = "universum",
	config = { extra = 2 },
	pos = { x = 3, y = 3 },
	rarity = "cry_exotic",
	cost = 50,
	order = 501,
	blueprint_compat = true,
	atlas = "atlasexotic",
	soul_pos = { x = 4, y = 3, extra = { x = 5, y = 3 } },
	loc_vars = function(self, info_queue, center)
		return { vars = { number_format(center.ability.extra) } }
	end,
	calculate = function(self, card, context)
		if context.cry_universum then
			return {
				mod = lenient_bignum(card.ability.extra),
				colour = G.C.DARK_EDITION,
				message = localize("k_upgrade_ex"),
			}
		end
	end,
	cry_credits = {
		idea = { "Ein13" },
		art = { "Ein13", "hydro" },
	},
	init = function(self)
		--Universum Patches
		local uht = update_hand_text
		function update_hand_text(config, vals)
			if next(find_joker("cry-Universum")) and not Talisman.config_file.disable_anims then
				G.E_MANAGER:add_event(Event({ --This is the Hand name text for the poker hand
					trigger = "before",
					blockable = not config.immediate,
					delay = config.delay or 0.8,
					func = function()
						local col = G.C.GREEN
						if vals.chips and G.GAME.current_round.current_hand.chips ~= vals.chips then
							local delta = vals.chips
							if is_number(vals.chips) and is_number(G.GAME.current_round.current_hand.chips) then
								delta = "X" .. number_format(vals.chips / G.GAME.current_round.current_hand.chips)
							end
							G.GAME.current_round.current_hand.chips = vals.chips
							G.hand_text_area.chips:update(0)
							if vals.StatusText then
								attention_text({
									text = delta,
									scale = 0.8,
									hold = 1,
									cover = G.hand_text_area.chips.parent,
									cover_colour = mix_colours(G.C.CHIPS, col, 0.1),
									emboss = 0.05,
									align = "cm",
									cover_align = "cr",
								})
							end
						end
						if vals.mult and G.GAME.current_round.current_hand.mult ~= vals.mult then
							local delta = vals.mult
							if is_number(vals.mult) and is_number(G.GAME.current_round.current_hand.mult) then
								delta = "X" .. number_format(vals.mult / G.GAME.current_round.current_hand.mult)
							end
							G.GAME.current_round.current_hand.mult = vals.mult
							G.hand_text_area.mult:update(0)
							if vals.StatusText then
								attention_text({
									text = delta,
									scale = 0.8,
									hold = 1,
									cover = G.hand_text_area.mult.parent,
									cover_colour = mix_colours(G.C.MULT, col, 0.1),
									emboss = 0.05,
									align = "cm",
									cover_align = "cl",
								})
							end
							if not G.TAROT_INTERRUPT then
								G.hand_text_area.mult:juice_up()
							end
						end
						if vals.handname and G.GAME.current_round.current_hand.handname ~= vals.handname then
							G.GAME.current_round.current_hand.handname = vals.handname
							if not config.nopulse then
								G.hand_text_area.handname.config.object:pulse(0.2)
							end
						end
						if vals.chip_total then
							G.GAME.current_round.current_hand.chip_total = vals.chip_total
							G.hand_text_area.chip_total.config.object:pulse(0.5)
						end
						if
							vals.level
							and G.GAME.current_round.current_hand.hand_level
								~= " " .. localize("k_lvl") .. tostring(vals.level)
						then
							if vals.level == "" then
								G.GAME.current_round.current_hand.hand_level = vals.level
							else
								G.GAME.current_round.current_hand.hand_level = " "
									.. localize("k_lvl")
									.. tostring(vals.level)
								if is_number(vals.level) then
									G.hand_text_area.hand_level.config.colour =
										G.C.HAND_LEVELS[to_number(math.min(vals.level, 7))]
								else
									G.hand_text_area.hand_level.config.colour = G.C.HAND_LEVELS[1]
								end
								G.hand_text_area.hand_level:juice_up()
							end
						end
						if config.sound and not config.modded then
							play_sound(config.sound, config.pitch or 1, config.volume or 1)
						end
						if config.modded then
							if
								G.HUD_blind
								and G.HUD_blind.get_UIE_by_ID
								and G.HUD_blind:get_UIE_by_ID("HUD_blind_debuff_1")
								and G.HUD_blind:get_UIE_by_ID("HUD_blind_debuff_2")
							then
								G.HUD_blind:get_UIE_by_ID("HUD_blind_debuff_1"):juice_up(0.3, 0)
								G.HUD_blind:get_UIE_by_ID("HUD_blind_debuff_2"):juice_up(0.3, 0)
							end
							G.GAME.blind:juice_up()
							G.E_MANAGER:add_event(Event({
								trigger = "after",
								delay = 0.06 * G.SETTINGS.GAMESPEED,
								blockable = false,
								blocking = false,
								func = function()
									play_sound("tarot2", 0.76, 0.4)
									return true
								end,
							}))
							play_sound("tarot2", 1, 0.4)
						end -- hi
						return true
					end,
				}))
			else
				uht(config, vals)
			end
		end
	end,
}
local exponentia = {
	dependencies = {
		items = {
			"c_cry_gateway",
			"set_cry_exotic",
		},
	},
	object_type = "Joker",
	name = "cry-Exponentia",
	key = "exponentia",
	config = { extra = { Emult = 1, Emult_mod = 0.03 } },
	pos = { x = 0, y = 0 },
	rarity = "cry_exotic",
	cost = 50,
	blueprint_compat = true,
	perishable_compat = false,
	demicoloncompat = true,
	atlas = "atlasexotic",
	order = 503,
	soul_pos = { x = 2, y = 0, extra = { x = 1, y = 0 } },
	calculate = function(self, card, context)
		if context.joker_main and (to_big(card.ability.extra.Emult) > to_big(1)) then
			return {
				message = localize({
					type = "variable",
					key = "a_powmult",
					vars = {
						number_format(card.ability.extra.Emult),
					},
				}),
				Emult_mod = lenient_bignum(card.ability.extra.Emult),
				colour = G.C.DARK_EDITION,
			}
		end
		if context.forcetrigger then
			SMODS.scale_card(card, {
				ref_table = card.ability.extra,
				ref_value = "Emult",
				scalar_value = "Emult_mod",
				message_key = "a_powmult",
				message_colour = G.C.DARK_EDITION,
			})
			return {
				Emult_mod = lenient_bignum(card.ability.extra.Emult),
			}
		end
	end,
	loc_vars = function(self, info_queue, center)
		return {
			vars = {
				number_format(center.ability.extra.Emult_mod),
				number_format(center.ability.extra.Emult),
			},
		}
	end,
	cry_credits = {
		idea = { "Enemui" },
		art = { "Lil Mr. Slipstream" },
		art = { "George the Rat" },
		code = { "Math" },
	},
	init = function(self)
		-- Hook for scaling
		local scie = SMODS.calculate_individual_effect
		function SMODS.calculate_individual_effect(effect, scored_card, key, amount, from_edition)
			local ret = scie(effect, scored_card, key, amount, from_edition)
			if
				(
					key == "x_mult"
					or key == "xmult"
					or key == "Xmult"
					or key == "x_mult_mod"
					or key == "xmult_mod"
					or key == "Xmult_mod"
				)
				and amount ~= 1
				and mult
			then
				for _, v in pairs(find_joker("cry-Exponentia")) do
					local old = v.ability.extra.Emult
					SMODS.scale_card(v, {
						ref_table = v.ability.extra,
						ref_value = "Emult",
						scalar_value = "Emult_mod",
						message_key = "a_powmult",
						message_colour = G.C.DARK_EDITION,
					})
				end
			end
			return ret
		end
	end,
}
local speculo = {
	dependencies = {
		items = {
			"c_cry_gateway",
			"set_cry_exotic",
		},
	},
	object_type = "Joker",
	name = "cry-Speculo",
	key = "speculo",
	pos = { x = 3, y = 1 },
	rarity = "cry_exotic",
	cost = 50,
	blueprint_compat = true,
	demicoloncompat = true,
	immutable = true,
	atlas = "atlasexotic",
	order = 504,
	soul_pos = { x = 4, y = 1, extra = { x = 5, y = 1 } },
	loc_vars = function(self, info_queue, center)
		if not center.edition or (center.edition and not center.edition.negative) then
			info_queue[#info_queue + 1] = G.P_CENTERS.e_negative
		end
	end,
	calculate = function(self, card, context)
		if context.ending_shop or context.forcetrigger then
			local eligibleJokers = {}
			for i = 1, #G.jokers.cards do
				if G.jokers.cards[i].ability.name ~= card.ability.name and G.jokers.cards[i].ability.set == "Joker" then
					eligibleJokers[#eligibleJokers + 1] = G.jokers.cards[i]
				end
			end
			if #eligibleJokers > 0 then
				G.E_MANAGER:add_event(Event({
					func = function()
						local card = copy_card(pseudorandom_element(eligibleJokers, pseudoseed("cry_speculo")), nil)
						card:set_edition({ negative = true }, true)
						card:add_to_deck()
						G.jokers:emplace(card)
						return true
					end,
				}))
				card_eval_status_text(
					context.blueprint_card or card,
					"extra",
					nil,
					nil,
					nil,
					{ message = localize("k_duplicated_ex") }
				)
				return nil, true
			end
			return
		end
	end,
	cry_credits = {
		idea = { "Mystic" },
		art = { "Mystic" },
		code = { "Math" },
	},
}
local redeo = {
	dependencies = {
		items = {
			"c_cry_gateway",
			"set_cry_exotic",
		},
	},
	object_type = "Joker",
	name = "cry-Redeo",
	key = "redeo",
	config = { extra = { ante_reduction = 1, money_req = 10, money_remaining = 0, money_mod = 10 } },
	loc_vars = function(self, info_queue, center)
		return {
			vars = {
				number_format(center.ability.extra.ante_reduction),
				number_format(center.ability.extra.money_req),
				number_format(center.ability.extra.money_remaining),
				number_format(center.ability.extra.money_mod),
			},
		}
	end,
	pos = { x = 3, y = 0 },
	rarity = "cry_exotic",
	cost = 50,
	order = 506,
	atlas = "atlasexotic",
	soul_pos = { x = 4, y = 0, extra = { x = 5, y = 0 } },
	demicoloncompat = true,
	calculate = function(self, card, context)
		if context.cry_ease_dollars and to_big(context.cry_ease_dollars) < to_big(0) and not context.blueprint then
			card.ability.extra.money_remaining =
				lenient_bignum(to_big(card.ability.extra.money_remaining) - context.cry_ease_dollars)
			local ante_mod = 0
			while to_big(card.ability.extra.money_remaining) >= to_big(card.ability.extra.money_req) do
				card.ability.extra.money_remaining =
					lenient_bignum(to_big(card.ability.extra.money_remaining) - card.ability.extra.money_req)
				card.ability.extra.money_req =
					lenient_bignum(to_big(card.ability.extra.money_req) + card.ability.extra.money_mod)
				card.ability.extra.money_mod = lenient_bignum(math.ceil(to_big(card.ability.extra.money_mod) * 1.06))
				ante_mod = lenient_bignum(ante_mod - to_big(card.ability.extra.ante_reduction))
			end
			if ante_mod < 0 then
				ease_ante(ante_mod)
			end
			return nil, true
		end
		if context.forcetrigger then
			ease_ante(card.ability.extra.ante_reduction)
		end
	end,
	cry_credits = {
		idea = { "Enemui" },
		art = { "Jevonn", "Darren_The_Frog" },
		code = { "Math", "jenwalter666" },
	},
	init = function(self)
		local ed = ease_dollars
		function ease_dollars(mod, x)
			ed(mod, x)
			for i = 1, #G.jokers.cards do
				local effects = G.jokers.cards[i]:calculate_joker({ cry_ease_dollars = mod })
			end
		end
	end,
}
local tenebris = {
	dependencies = {
		items = {
			"c_cry_gateway",
			"set_cry_exotic",
		},
	},
	object_type = "Joker",
	name = "cry-Tenebris",
	key = "tenebris",
	pos = { x = 3, y = 2 },
	soul_pos = { x = 4, y = 2, extra = { x = 5, y = 2 } },
	config = {
		extra = {
			slots = 25,
			money = 25,
		},
		immutable = {
			max_slots = 100,
		},
	},
	rarity = "cry_exotic",
	cost = 50,
	order = 507,
	atlas = "atlasexotic",
	demicoloncompat = true,
	calc_dollar_bonus = function(self, card)
		return lenient_bignum(card.ability.extra.money)
	end,
	loc_vars = function(self, info_queue, center)
		return {
			vars = {
				number_format(math.min(center.ability.immutable.max_slots, center.ability.extra.slots)),
				number_format(center.ability.extra.money),
			},
		}
	end,
	calculate = function(self, card, context)
		if context.forcetrigger then
			return {
				dollars = lenient_bignum(card.ability.extra.money),
				card = card,
			}
		end
	end,
	add_to_deck = function(self, card, from_debuff)
		G.jokers.config.card_limit = lenient_bignum(
			G.jokers.config.card_limit + math.min(card.ability.immutable.max_slots, to_big(card.ability.extra.slots))
		)
	end,
	remove_from_deck = function(self, card, from_debuff)
		G.jokers.config.card_limit = lenient_bignum(
			G.jokers.config.card_limit - math.min(card.ability.immutable.max_slots, to_big(card.ability.extra.slots))
		)
	end,
	cry_credits = {
		idea = { "Gold" },
		art = { "Mystic" },
		code = { "jenwalter666" },
	},
}
local effarcire = {
	dependencies = {
		items = {
			"c_cry_gateway",
			"set_cry_exotic",
		},
	},
	object_type = "Joker",
	name = "cry-Effarcire",
	key = "effarcire",
	config = {},
	immutable = true,
	pos = { x = 0, y = 0 },
	soul_pos = { x = 1, y = 0, extra = { x = 2, y = 0 } },
	cost = 50,
	order = 505,
	atlas = "effarcire",
	rarity = "cry_exotic",
	demicoloncompat = true,
	calculate = function(self, card, context)
		if not context.blueprint and not context.retrigger_joker or context.forcetrigger then
			if context.first_hand_drawn or context.forcetrigger and not G.GAME.effarcire_buffer then
				G.GAME.effarcire_buffer = true
				G.E_MANAGER:add_event(Event({
					func = function()
						G.FUNCS.draw_from_deck_to_hand(#G.deck.cards)
						G.E_MANAGER:add_event(Event({
							func = function()
								G.GAME.effarcire_buffer = nil
								save_run()
								return true
							end,
						}))
						return true
					end,
				}))
			elseif G.hand.config.card_limit < 1 then
				G.hand.config.card_limit = 1
			end
		end
	end,
	cry_credits = {
		idea = { "Frix" },
		art = { "AlexZGreat", "Catformer" },
		code = { "jenwalter666" },
	},
}
local effarcire_sprite = {
	object_type = "Atlas",
	key = "effarcire",
	path = "goofy.png",
	px = 71,
	py = 95,
}
local crustulum = {
	dependencies = {
		items = {
			"c_cry_gateway",
			"set_cry_exotic",
		},
	},
	object_type = "Joker",
	name = "cry-crustulum",
	key = "crustulum",
	config = {
		extra = {
			chips = 0,
			chip_mod = 4,
		},
	},
	pos = { x = 0, y = 2 },
	soul_pos = { x = 2, y = 2, extra = { x = 1, y = 2 } },
	rarity = "cry_exotic",
	cost = 50,
	order = 508,
	atlas = "atlasexotic",
	blueprint_compat = true,
	perishable_compat = false,
	demicoloncompat = true,
	loc_vars = function(self, info_queue, center)
		return {
			vars = {
				number_format(center.ability.extra.chips),
				number_format(center.ability.extra.chip_mod),
			},
		}
	end,
	calculate = function(self, card, context)
		if context.reroll_shop and not context.blueprint then
			SMODS.scale_card(card, {
				ref_table = card.ability.extra,
				ref_value = "chips",
				scalar_value = "chip_mod",
				message_colour = G.C.CHIPS,
			})
			return nil, true
		end
		if context.joker_main and to_big(card.ability.extra.chips) > to_big(0) then
			return {
				message = localize({
					type = "variable",
					key = "a_chips",
					vars = { number_format(card.ability.extra.chips) },
				}),
				chip_mod = lenient_bignum(card.ability.extra.chips),
			}
		end
		if context.forcetrigger then
			SMODS.scale_card(card, {
				ref_table = card.ability.extra,
				ref_value = "chips",
				scalar_value = "chip_mod",
				message_colour = G.C.CHIPS,
			})
			return {
				chip_mod = lenient_bignum(card.ability.extra.chips),
			}
		end
	end,
	add_to_deck = function(self, card, from_debuff)
		--This makes the reroll immediately after obtaining free because the game doesn't do that for some reason
		G.GAME.current_round.free_rerolls = G.GAME.current_round.free_rerolls + 1
		calculate_reroll_cost(true)
	end,
	remove_from_deck = function(self, card, from_debuff)
		calculate_reroll_cost(true)
	end,
	cry_credits = {
		idea = { "AlexZGreat" },
		art = { "lolxddj" },
		code = { "Jevonn" },
	},
}
--todo: make the Emult always prime
local primus = {
	dependencies = {
		items = {
			"c_cry_gateway",
			"set_cry_exotic",
		},
	},
	object_type = "Joker",
	name = "cry-primus",
	key = "primus",
	config = {
		extra = {
			Emult = 1.01,
			Emult_mod = 0.17,
		},
	},
	pos = { x = 0, y = 4 },
	rarity = "cry_exotic",
	cost = 53,
	order = 510,
	blueprint_compat = true,
	perishable_compat = false,
	demicoloncompat = true,
	atlas = "atlasexotic",
	soul_pos = { x = 2, y = 4, extra = { x = 1, y = 4 } },
	calculate = function(self, card, context)
		local check = true
		if context.cardarea == G.jokers and context.before and not context.blueprint then
			if context.scoring_hand then
				for k, v in ipairs(context.full_hand) do
					if
						v:get_id() == 4
						or v:get_id() == 6
						or v:get_id() == 8
						or v:get_id() == 9
						or v:get_id() == 10
						or v:get_id() == 11
						or v:get_id() == 12
						or v:get_id() == 13
					then
						check = false
					end
				end
			end
			if check then
				SMODS.scale_card(card, {
					ref_table = card.ability.extra,
					ref_value = "Emult",
					scalar_value = "Emult_mod",
					message_colour = G.C.DARK_EDITION,
				})
				card.children.floating_sprite:set_sprite_pos({ x = 8, y = 6 })
			end
		end
		if context.joker_main and (to_big(card.ability.extra.Emult) > to_big(1)) then
			card.children.floating_sprite:set_sprite_pos({ x = 8, y = 6 })
			return {
				message = localize({
					type = "variable",
					key = "a_powmult",
					vars = {
						number_format(card.ability.extra.Emult),
					},
				}),
				Emult_mod = lenient_bignum(card.ability.extra.Emult),
				colour = G.C.DARK_EDITION,
			}
		end
		if context.end_of_round then
			card.children.floating_sprite:set_sprite_pos({ x = 2, y = 4 })
		end
		if context.forcetrigger then
			SMODS.scale_card(card, {
				ref_table = card.ability.extra,
				ref_value = "Emult",
				scalar_value = "Emult_mod",
				message_colour = G.C.DARK_EDITION,
			})
			return {
				Emult_mod = lenient_bignum(card.ability.extra.Emult),
				colour = G.C.DARK_EDITION,
			}
		end
	end,
	loc_vars = function(self, info_queue, center)
		return {
			vars = {
				number_format(center.ability.extra.Emult_mod),
				number_format(center.ability.extra.Emult),
			},
		}
	end,
	cry_credits = {
		idea = { "Jevonn" },
		art = { "George the Rat" },
		code = { "Jevonn" },
	},
}
local scalae = {
	dependencies = {
		items = {
			"c_cry_gateway",
			"set_cry_exotic",
		},
	},
	object_type = "Joker",
	name = "cry-Scalae",
	key = "Scalae",
	pos = { x = 3, y = 4 },
	soul_pos = { x = 5, y = 4, extra = { x = 4, y = 4 } },
	immutable = false,
	rarity = "cry_exotic",
	cost = 50,
	atlas = "atlasexotic",
	order = 311,
	config = { extra = { scale = 1, scale_mod = 1 } },
	demicoloncompat = true,
	calculate = function(self, card, context)
		if
			(context.end_of_round and not context.individual and not context.repetition and not context.blueprint)
			or context.forcetrigger
		then
			SMODS.scale_card(card, {
				ref_table = card.ability.extra,
				ref_value = "scale",
				scalar_value = "scale_mod",
				message_colour = G.C.DARK_EDITION,
			})
		end
	end,
	calc_scaling = function(self, card, other, current_scaling, current_scalar, args)
		-- checks if the scaled joker is also a scalae
		-- if so, return nothing
		if other.config.center.key == self.key then
			return
		end

		-- store original scaling rate
		if not other.ability.cry_scaling_info then
			other.ability.cry_scaling_info = {
				[args.scalar_value] = current_scalar,
			}
		elseif not other.ability.cry_scaling_info[args.scalar_value] then
			other.ability.cry_scaling_info[args.scalar_value] = current_scalar
		end

		-- joker scaling stuff
		local original_scalar = other.ability.cry_scaling_info[args.scalar_value]
		local new_scale = lenient_bignum(
			to_big(original_scalar)
				* (
					(
						1
						+ (
							(to_big(current_scaling) / to_big(original_scalar))
							^ (to_big(1) / to_big(card.ability.extra.scale))
						)
					) ^ to_big(card.ability.extra.scale)
				)
		)
		args.scalar_table[args.scalar_value] = new_scale

		return {
			message = localize("k_upgrade_ex"),
		}
	end,

	loc_vars = function(self, info_queue, card)
		local example = { 2, 3, 4 }
		-- this is literally just straight up wrong atm, scalae doesn't work like this
		for i = 1, #example do
			example[i] = to_big(example[i]) ^ (card.ability.extra.scale + 1)
		end
		return {
			vars = {
				number_format(card.ability.extra.scale + 1),
				number_format(card.ability.extra.scale_mod),
				example[1],
				example[2],
				example[3],
			},
		}
	end,
	cry_credits = {
		idea = { "Mathguy" },
		art = { "Mathguy" },
		code = { "Mathguy" },
	},
}
local stella_mortis = {
	dependencies = {
		items = {
			"c_cry_gateway",
			"set_cry_exotic",
		},
	},
	object_type = "Joker",
	name = "cry-Stella Mortis",
	key = "stella_mortis",
	config = {
		extra = {
			Emult = 1,
			Emult_mod = 0.4,
		},
	},
	pos = { x = 3, y = 5 },
	rarity = "cry_exotic",
	cost = 50,
	order = 502,
	blueprint_compat = true,
	perishable_compat = false,
	demicoloncompat = true,
	atlas = "atlasexotic",
	soul_pos = { x = 5, y = 5, extra = { x = 4, y = 5 } },
	calculate = function(self, card, context)
		if (context.ending_shop and not context.blueprint) or context.forcetrigger then
			local destructable_planet = {}
			local quota = 1
			for i = 1, #G.consumeables.cards do
				if
					G.consumeables.cards[i].ability.set == "Planet"
					and not G.consumeables.cards[i].getting_sliced
					and not SMODS.is_eternal(G.consumeables.cards[i])
				then
					destructable_planet[#destructable_planet + 1] = G.consumeables.cards[i]
				end
			end
			local planet_to_destroy = #destructable_planet > 0
					and pseudorandom_element(destructable_planet, pseudoseed("stella_mortis"))
				or nil

			if planet_to_destroy then
				if Incantation then
					quota = planet_to_destroy:getEvalQty()
				end
				if Overflow then
					quaota = planet_to_destroy.ability.immutable and planet_to_destroy.ability.immutable.overflow_amount
				end
				planet_to_destroy.getting_sliced = true
				SMODS.scale_card(card, {
					ref_table = card.ability.extra,
					ref_value = "Emult",
					scalar_value = "Emult_mod",
					operation = function(ref_table, ref_value, initial, change)
						ref_table[ref_value] = initial + change * quota
					end,
					message_key = "a_powmult",
				})
				G.E_MANAGER:add_event(Event({
					func = function()
						(context.blueprint_card or card):juice_up(0.8, 0.8)
						planet_to_destroy:start_dissolve({ G.C.RED }, nil, 1.6)
						return true
					end,
				}))
				planet_to_destroy.dissolve = 0 --timing issues related to crossmod stuff
				return nil, true
			end
		end
		if (context.joker_main and (to_big(card.ability.extra.Emult) > to_big(1))) or context.forcetrigger then
			return {
				message = localize({
					type = "variable",
					key = "a_powmult",
					vars = {
						number_format(card.ability.extra.Emult),
					},
				}),
				Emult_mod = lenient_bignum(card.ability.extra.Emult),
				colour = G.C.DARK_EDITION,
			}
		end
	end,
	loc_vars = function(self, info_queue, center)
		return {
			vars = {
				number_format(center.ability.extra.Emult_mod),
				number_format(center.ability.extra.Emult),
			},
		}
	end,
	cry_credits = {
		idea = { "SMG9000" },
		art = { "SMG9000", "George the Rat", "patchy", "lolxDdj" },
		code = { "SMG9000" },
	},
}
local circulus_pistoris = {
	dependencies = {
		items = {
			"c_cry_gateway",
			"set_cry_exotic",
		},
	},
	object_type = "Joker",
	name = "cry-Circulus Pistoris",
	key = "circulus_pistoris",
	config = {
		extra = {
			Emult = math.pi,
			Echips = math.pi,
			hands_remaining = 3,
		},
	},
	pos = { x = 0, y = 3 },
	rarity = "cry_exotic",
	cost = 10 * math.pi,
	order = 509,
	blueprint_compat = true,
	demicoloncompat = true,
	immutable = true,
	atlas = "atlasexotic",
	soul_pos = { x = 2, y = 3, extra = { x = 1, y = 3 } },
	loc_vars = function(self, info_queue, center)
		return {
			vars = {
				Cryptid.safe_get(center, "edition", "cry_oversat") and "tau" or "pi",
				center.ability.extra.hands_remaining,
			},
		}
	end,
	calculate = function(self, card, context)
		if
			(
				context.joker_main
				and (
					G.GAME.current_round.hands_left >= card.ability.extra.hands_remaining
					and G.GAME.current_round.hands_left < card.ability.extra.hands_remaining + 1
				)
			) or context.forcetrigger
		then
			local pi = math.pi
			if Cryptid.safe_get(card, "edition", "cry_oversat") then
				pi = 2 * pi
			end
			return {
				Echip_mod = pi,
				Emult_mod = pi,
				message = localize({
					type = "variable",
					key = "a_powmultchips",
					vars = { (Cryptid.safe_get(card, "edition", "cry_oversat") and "tau" or "pi") },
				}),
				colour = { 0.8, 0.45, 0.85, 1 }, --plasma colors
			}
		end
	end,
	cry_credits = {
		idea = { "SMG9000", "Math" }, --not sure if there's more ppl I'm missing
		art = { "HexaCryonic", "ori" },
		code = { "SMG9000", "Math" },
	},
}
local aequilibrium = {
	dependencies = {
		items = {
			"c_cry_gateway",
			"set_cry_exotic",
		},
	},
	object_type = "Joker",
	name = "Ace Aequilibrium",
	key = "equilib",
	config = {
		extra = {
			jokers = 2,
			card = nil,
		},
	},
	rarity = "cry_exotic",
	pos = { x = 7, y = 0 },
	soul_pos = { x = 6, y = 0, extra = { x = 8, y = 0 } },
	atlas = "atlasexotic",
	cost = 50,
	order = 512,
	blueprint_compat = true,
	eternal_compat = true,
	perishable_compat = true,
	demicoloncompat = true,
	immutable = true,
	loc_vars = function(self, info_queue, center)
		if not center.edition or (center.edition and not center.edition.negative) then
			info_queue[#info_queue + 1] = G.P_CENTERS.e_negative
		end
		local joker_generated = "???"
		if G.GAME.aequilibriumkey and G.GAME.aequilibriumkey > 1 then
			joker_generated = localize({
				type = "name_text",
				set = "Joker",
				key = G.P_CENTER_POOLS["Joker"][math.floor(G.GAME.aequilibriumkey or 1) - 1].key,
			})
		end
		return { vars = { math.floor(math.min(25, center.ability.extra.jokers)), joker_generated } }
	end,
	calculate = function(self, card, context)
		if
			(context.cardarea == G.jokers and context.before and not context.retrigger_joker) or context.forcetrigger
		then
			for i = 1, math.floor(math.min(25, card.ability.extra.jokers)) do
				local newcard = create_card("Joker", G.jokers, nil, nil, nil, nil, nil)
				newcard:add_to_deck()
				G.jokers:emplace(newcard)
				newcard:set_edition({ negative = true }, true)
			end
			return nil, true
		end
	end,
	cry_credits = {
		idea = { "Elial2" },
		art = { "Elial2", "unexian", "hydro" },
		code = { "Elial2" },
	},
}
local facile = {
	dependencies = {
		items = {
			"c_cry_gateway",
			"set_cry_exotic",
		},
	},
	object_type = "Joker",
	name = "cry-facile",
	key = "facile",
	config = {
		extra = {
			Emult = 3,
			check = 10,
		},
		immutable = {
			check2 = 0,
		},
	},
	pos = { x = 6, y = 2 },
	soul_pos = { x = 8, y = 2, extra = { x = 7, y = 2 } },
	rarity = "cry_exotic",
	cost = 50,
	order = 513,
	blueprint_compat = true,
	demicoloncompat = true,
	atlas = "atlasexotic",
	loc_vars = function(self, info_queue, center)
		return {
			vars = {
				number_format(center.ability.extra.Emult),
				number_format(center.ability.extra.check),
			},
		}
	end,
	calculate = function(self, card, context)
		if context.individual then
			if context.cardarea == G.play then
				card.ability.immutable.check2 = lenient_bignum(card.ability.immutable.check2 + 1)
			end
		end
		if context.joker_main and (to_big(card.ability.extra.Emult) > to_big(1)) then
			if to_big(card.ability.immutable.check2) <= to_big(card.ability.extra.check) then
				card.ability.immutable.check2 = 0
				return {
					message = localize({
						type = "variable",
						key = "a_powmult",
						vars = { number_format(card.ability.extra.Emult) },
					}),
					Emult_mod = lenient_bignum(card.ability.extra.Emult),
					colour = G.C.DARK_EDITION,
				}
			else
				card.ability.immutable.check2 = 0
			end
		end
		if context.forcetrigger then
			return {
				message = localize({
					type = "variable",
					key = "a_powmult",
					vars = { number_format(card.ability.extra.Emult) },
				}),
				Emult_mod = lenient_bignum(card.ability.extra.Emult),
				colour = G.C.DARK_EDITION,
			}
		end
	end,
	cry_credits = {
		idea = { "Enemui" },
		art = { "Kailen", "hydro" },
		code = { "Jevonn" },
	},
}
local gemino = {
	dependencies = {
		items = {
			"c_cry_gateway",
			"set_cry_exotic",
		},
	},
	object_type = "Joker",
	name = "cry-Gemino",
	key = "gemino",
	pos = { x = 6, y = 1 },
	soul_pos = { x = 8, y = 1, extra = { x = 7, y = 1 } },
	immutable = true,
	cry_credits = {
		jolly = {
			"Jolly Open Winner",
			"Requiacity",
		},
		art = { "unexian" },
		code = { "Math" },
	},
	rarity = "cry_exotic",
	blueprint_compat = true,
	demicoloncompat = true,
	cost = 50,
	order = 515,
	atlas = "atlasexotic",
	loc_vars = function(self, info_queue, card)
		card.ability.blueprint_compat_ui = card.ability.blueprint_compat_ui or ""
		card.ability.blueprint_compat_check = nil
		return {
			main_end = (card.area and card.area == G.jokers) and {
				{
					n = G.UIT.C,
					config = { align = "bm", minh = 0.4 },
					nodes = {
						{
							n = G.UIT.C,
							config = {
								ref_table = card,
								align = "m",
								colour = G.C.JOKER_GREY,
								r = 0.05,
								padding = 0.06,
								func = "blueprint_compat",
							},
							nodes = {
								{
									n = G.UIT.T,
									config = {
										ref_table = card.ability,
										ref_value = "blueprint_compat_ui",
										colour = G.C.UI.TEXT_LIGHT,
										scale = 0.32 * 0.8,
									},
								},
							},
						},
					},
				},
			} or nil,
		}
	end,
	update = function(self, card, front)
		if G.STAGE == G.STAGES.RUN then
			other_joker = G.jokers.cards[1]
			if other_joker and other_joker ~= card and not (Card.no(other_joker, "immutable", true)) then
				card.ability.blueprint_compat = "compatible"
			else
				card.ability.blueprint_compat = "incompatible"
			end
		end
	end,
	calculate = function(self, card2, context)
		if (context.end_of_round and not context.repetition and not context.individual) or context.forcetrigger then
			local check = false
			local card = G.jokers.cards[1]
			if not Card.no(G.jokers.cards[1], "immutable", true) then
				Cryptid.manipulate(G.jokers.cards[1], { value = 2 })
				check = true
			end
			if check then
				card_eval_status_text(
					context.blueprint_card or card2,
					"extra",
					nil,
					nil,
					nil,
					{ message = localize("k_upgrade_ex"), colour = G.C.GREEN }
				)
			end
			return nil, true
		end
	end,
}
local energia = {
	dependencies = {
		items = {
			"c_cry_gateway",
			"set_cry_exotic",
		},
	},
	object_type = "Joker",
	name = "cry-Energia",
	key = "energia",
	pos = { x = 6, y = 3 },
	soul_pos = { x = 8, y = 3, extra = { x = 7, y = 3 } },
	blueprint_compat = true,
	perishable_compat = false,
	demicoloncompat = true,
	order = 514,
	config = {
		extra = { tags = 1, tag_mod = 1 },
		immutable = { max_tags = 40 },
	},
	loc_vars = function(self, info_queue, center)
		return {
			vars = {
				math.min(center.ability.extra.tags, center.ability.immutable.max_tags),
				center.ability.extra.tag_mod,
			},
		}
	end,
	rarity = "cry_exotic",
	cost = 50,
	atlas = "atlasexotic",
	calculate = function(self, card, context)
		if context.tag_added and not context.tag_added.from_energia then
			-- Don't add tags if there are more then 40 (lag)
			local added_tags =
				math.max(math.min(card.ability.immutable.max_tags - #G.GAME.tags, card.ability.extra.tags), 0)
			print(added_tags)
			if added_tags > 0 then
				for i = 1, added_tags do
					local ab = copy_table(context.tag_added.ability)
					local new_tag = Tag(context.tag_added.key)
					new_tag.from_energia = true
					add_tag(new_tag)
					new_tag.from_energia = nil
					new_tag.ability = ab
				end
			end
			SMODS.scale_card(card, {
				ref_table = card.ability.extra,
				ref_value = "tags",
				scalar_value = "tag_mod",
				scaling_message = {
					message = localize({
						type = "variable",
						key = card.ability.extra.tags == 1 and "a_tag" or "a_tags",
						vars = { added_tags },
					})[1],
					colour = G.C.DARK_EDITION,
				},
			})
		elseif context.forcetrigger then
			SMODS.scale_card(card, {
				ref_table = card.ability.extra,
				ref_value = "tags",
				scalar_value = "tag_mod",
				no_message = true,
			})
		end
	end,
	cry_credits = {
		idea = { "jenwalter666" },
		art = { "unexian" },
		code = { "Math" },
	},
}
--why is this an exotic???
local verisimile = {
	dependencies = {
		items = {
			"c_cry_gateway",
			"set_cry_exotic",
		},
	},
	object_type = "Joker",
	name = "cry-verisimile",
	key = "verisimile",
	pos = { x = 6, y = 5 },
	soul_pos = { x = 8, y = 5, extra = { x = 7, y = 5 } },
	config = { extra = { xmult = 1 } },
	rarity = "cry_exotic",
	cost = 50,
	order = 516,

	-- "i'm not making this compatible" - nova
	-- "well i am" - invalid, writing this comment
	demicoloncompat = true,
	blueprint_compat = true,

	atlas = "atlasexotic",
	loc_vars = function(self, info_queue, center)
		return { vars = { number_format(center.ability.extra.xmult) } }
	end,
	calculate = function(self, card, context)
		if context.pseudorandom_result and context.result and not context.blueprint then
			-- implementation that doesn't use SMODS.scale_card; use if scale_card causes weird or unexpected behavior
			--[[
			card.ability.extra.xmult = lenient_bignum(card.ability.extra.xmult + context.denominator)
			return {
                message = localize({
                    type = "variable",
                    key = "a_xmult",
                    vars = { number_format(card.ability.extra.xmult) },
                })
			}
			]]

			SMODS.scale_card(card, {
				-- this should not affect the probability in the context table
				block_overrides = {
					scalar = true,
				},

				ref_table = card.ability.extra,
				ref_value = "xmult",
				scalar_table = context,
				scalar_value = "denominator",
				scaling_message = {},
			})

			return {
				message = localize({
					type = "variable",
					key = "a_xmult",
					vars = { number_format(card.ability.extra.xmult) },
				}),
			}
		-- forcetriggers won't scale non verisimile, because how much would you scale it by
		elseif context.joker_main or context.forcetrigger then
			return {
				xmult = lenient_bignum(card.ability.extra.xmult),
			}
		end
	end,
	cry_credits = {
		idea = { "Enemui" },
		code = { "Jevonn", "invalidOS" },
	},
}
local duplicare = {
	dependencies = {
		items = {
			"c_cry_gateway",
			"set_cry_exotic",
		},
	},
	object_type = "Joker",
	name = "cry-duplicare",
	key = "duplicare",
	config = { extra = { Xmult = 1, Xmult_mod = 1 } },
	pos = { x = 0, y = 6 },
	soul_pos = { x = 2, y = 6, extra = { x = 1, y = 6 } },
	rarity = "cry_exotic",
	cost = 50,
	order = 517,
	blueprint_compat = true,
	demicoloncompat = true,
	atlas = "atlasexotic",
	loc_vars = function(self, info_queue, center)
		return {
			vars = {
				number_format(center.ability.extra.Xmult),
				number_format(center.ability.extra.Xmult_mod),
			},
		}
	end,
	calculate = function(self, card, context)
		if
			not context.blueprint
			and (
				(
					context.post_trigger
					and context.other_joker ~= card
					and Cryptid.isNonRollProbabilityContext(context.other_context)
				) or (context.individual and context.cardarea == G.play)
			)
		then
			SMODS.scale_card(card, {
				ref_table = card.ability.extra,
				ref_value = "Xmult",
				scalar_value = "Xmult_mod",
			})
		end
		if (context.joker_main and (to_big(card.ability.extra.Xmult) > to_big(1))) or context.forcetrigger then
			if context.forcetrigger then
				SMODS.scale_card(card, {
					ref_table = card.ability.extra,
					ref_value = "Xmult",
					scalar_value = "Xmult_mod",
					no_message = true,
				})
			end
			return {
				message = localize({
					type = "variable",
					key = "a_xmult",
					vars = {
						number_format(card.ability.extra.Xmult),
					},
				}),
				Xmult_mod = lenient_bignum(card.ability.extra.Xmult),
				colour = G.C.MULT,
			}
		end
	end,
	cry_credits = {
		idea = { "Enemui" },
		art = { "Shellular" },
		code = { "elial2" },
	},
}
-- to be honest, this needs a refactor because
-- rescribed jokers are forgotten on save reload
-- they are not saved in a good way right now
-- status text is not handled properly
local rescribere = {
	object_type = "Joker",
	name = "cry-Rescribere",
	key = "rescribere",
	pos = { x = 0, y = 1 },
	soul_pos = { x = 1, y = 1, extra = { x = 2, y = 1 } },
	blueprint_compat = false,
	perishable_compat = false,
	rarity = "cry_exotic",
	cost = 50,
	order = 69420,
	atlas = "placeholders",
	calculate = function(self, card, context)
		local eligibleJokers = {}
		for i = 1, #G.jokers.cards do
			if G.jokers.cards[i].ability.name ~= card.ability.name then
				eligibleJokers[#eligibleJokers + 1] = G.jokers.cards[i]
			end
		end

		for i = 1, #eligibleJokers do
			if
				context.selling_card
				and context.card.ability.name ~= card.ability.name
				and context.card ~= eligibleJokers[i]
			then
				local oldfunc = eligibleJokers[i].calculate_joker

				eligibleJokers[i].ability.rescribere_jokers = eligibleJokers[i].ability.rescribere_jokers or {}
				eligibleJokers[i].ability.rescribere_jokers[#eligibleJokers[i].ability.rescribere_jokers + 1] =
					context.card

				eligibleJokers[i].calculate_joker = function(cardd, contextt)
					local totalret = oldfunc(cardd, contextt)

					v = eligibleJokers[i].ability.rescribere_jokers[#eligibleJokers[i].ability.rescribere_jokers]

					local ret = v:calculate_joker(contextt)
					if ret and type(ret) == "table" then
						totalret = totalret or { message = "Copying", card = eligibleJokers[i] }
						for _i, _v in pairs(ret) do
							if not totalret[_i] then
								totalret[_i] = ret[_i] or _v
								--print(totalret[_i] .. "--------------")
							else
								if type(totalret[_i]) == "number" then
									totalret[_i] = totalret[_i] + ret[_i]
								end
							end
						end
						totalret.card = eligibleJokers[i]
					end
					return totalret
				end
			end
		end
	end,
}
local formidiulosus = {
	dependencies = {
		items = {
			"c_cry_gateway",
			"set_cry_exotic",
			"set_cry_spooky",
		},
	},
	object_type = "Joker",
	name = "cry-Formidiulosus",
	key = "formidiulosus",
	pos = { x = 6, y = 4 },
	soul_pos = { x = 8, y = 4, extra = { x = 7, y = 4 } },
	blueprint_compat = true,
	demicoloncompat = true,
	config = {
		extra = {
			Emult_mod = 0.01,
			Emult = 1,
		},
		immutable = {
			num_candies = 3,
		},
	},
	loc_vars = function(self, info_queue, center)
		return {
			vars = {
				center.ability.immutable.num_candies,
				center.ability.extra.Emult_mod,
				center.ability.extra.Emult,
			},
		}
	end,
	rarity = "cry_exotic",
	cost = 50,
	order = 518,
	atlas = "atlasexotic",
	no_dbl = true,
	update = function(self, card, front)
		card.ability.extra.Emult = lenient_bignum(
			1 + (card.ability.extra.Emult_mod * #Cryptid.advanced_find_joker(nil, "cry_candy", nil, nil, true))
		)
	end,
	calculate = function(self, card, context)
		if
			(context.buying_card or context.cry_creating_card)
			and context.card.ability.set == "Joker"
			and context.card.config.center.rarity == "cry_cursed"
			and not context.blueprint
			and not (context.card == card)
		then
			G.E_MANAGER:add_event(Event({
				func = function()
					context.card:start_dissolve()
					card_eval_status_text(card, "extra", nil, nil, nil, {
						message = localize("k_nope_ex"),
						colour = G.C.BLACK,
					})
					return true
				end,
			}))
		end
		if context.ending_shop then
			for i = 1, card.ability.immutable.num_candies do
				local card = create_card("Joker", G.jokers, nil, "cry_candy", nil, nil, nil, "cry_trick_candy")
				card:set_edition({ negative = true }, true)
				card:add_to_deck()
				G.jokers:emplace(card)
			end
		end
		if context.cardarea == G.jokers and (to_big(card.ability.extra.Emult) > to_big(1)) and context.joker_main then
			return {
				message = localize({
					type = "variable",
					key = "a_powmult",
					vars = {
						number_format(card.ability.extra.Emult),
					},
				}),
				Emult_mod = lenient_bignum(card.ability.extra.Emult),
				colour = G.C.DARK_EDITION,
			}
		end
		if context.forcetrigger then
			for i = 1, card.ability.immutable.num_candies do
				local card = create_card("Joker", G.jokers, nil, "cry_candy", nil, nil, nil, "cry_trick_candy")
				card:set_edition({ negative = true }, true)
				card:add_to_deck()
				G.jokers:emplace(card)
			end
			return {
				message = localize({
					type = "variable",
					key = "a_powmult",
					vars = {
						number_format(card.ability.extra.Emult),
					},
				}),
				Emult_mod = lenient_bignum(card.ability.extra.Emult),
				colour = G.C.DARK_EDITION,
			}
		end
	end,
	cry_credits = {
		idea = { "HexaCryonic", "Kailen" },
		art = { "Foegro", "hydro" },
		code = { "Foegro" },
	},
}
local caeruleum = {
	dependencies = {
		items = {
			"c_cry_gateway",
			"set_cry_exotic",
		},
	},
	object_type = "Joker",
	name = "cry-Caeruleum",
	key = "caeruleum",

	config = {},

	init = function(self)
		local scie = SMODS.calculate_individual_effect
		function SMODS.calculate_individual_effect(effect, scored_card, key, amount, from_edition, ...)
			local card = effect.card or scored_card
			local caeruleum_messages = {}

			if Cryptid.safe_get(card, "ability", "cry_caeruleum") then
				for i = 1, #G.jokers.cards do
					if G.jokers.cards[i] == card then
						for _, b in ipairs(card.ability.cry_caeruleum) do
							local caeruleum = G.jokers.cards[i + (b and 1 or -1)]
							local was_key_changed, new_key, op = Cryptid.caeruleum_new_key(key)

							-- change the key!
							if was_key_changed then
								key = new_key

								-- no _mod returns because i hate them
								effect.remove_default_message = (key:sub(-4) == "_mod")

								-- create a new message for caeruleum to display
								local chipsMessageKeys = {
									"a_chips",
									"a_xchips",
									"a_powchips",
								}

								-- these get run through card_eval_status_text AFTER the normal calculate_individual_effect runs
								caeruleum_messages[#caeruleum_messages + 1] = {
									caeruleum,
									"extra",
									nil,
									percent,
									nil,
									{
										message = localize({
											type = "variable",
											key = chipsMessageKeys[op],
											vars = {
												number_format(amount),
											},
										}),
										focus = caeruleum,
										sound = "chips1",
									},
								}
							end
						end
					end
				end
			end

			-- run normal function
			local ret = scie(effect, scored_card, key, amount, from_edition, ...)

			-- display caeruleum messages
			if #caeruleum_messages > 0 then
				for _, msg in ipairs(caeruleum_messages) do
					card_eval_status_text(unpack(msg))
				end
			end

			-- return result
			return ret
		end
	end,

	pos = { x = 3, y = 6 },
	rarity = "cry_exotic",
	order = 519,
	cost = 50,
	blueprint_compat = false,
	demicoloncompat = false,
	atlas = "atlasexotic",
	soul_pos = { x = 5, y = 6, extra = { x = 4, y = 6 } },
	loc_vars = function(self, info_queue, center)
		return {
			vars = {},
		}
	end,
	calculate = function(self, card, context)
		-- used to "mark" jokers to be affected by caeruleum
		if context.before and context.cardarea == G.jokers then
			local left_joker = nil
			local right_joker = nil

			for i = 1, #G.jokers.cards do
				if G.jokers.cards[i] == card then
					left_joker = G.jokers.cards[i - 1]
					right_joker = G.jokers.cards[i + 1]
				end
			end

			-- allows caeruleum to stack
			-- boolean value is true if the joker was to the left of caeruleum (so caeruleum is to the right of it)
			if left_joker and left_joker.config.center.key ~= "j_cry_caeruleum" then
				left_joker.ability.cry_caeruleum = left_joker.ability.cry_caeruleum or {}
				left_joker.ability.cry_caeruleum[#left_joker.ability.cry_caeruleum + 1] = true
			end

			if right_joker and right_joker.config.center.key ~= "j_cry_caeruleum" then
				right_joker.ability.cry_caeruleum = right_joker.ability.cry_caeruleum or {}
				right_joker.ability.cry_caeruleum[#right_joker.ability.cry_caeruleum + 1] = false
			end
		end

		if context.after and context.cardarea == G.jokers then
			-- reset this on every joker just to avoid weird bugs
			for i = 1, #G.jokers.cards do
				G.jokers.cards[i].ability.cry_caeruleum = nil
			end
		end
	end,
	cry_credits = {
		idea = { "HexaCryonic" },
		art = { "Tatteredlurker" },
		code = { "InvalidOS" },
	},
}

local chipsOperators = {
	{
		keys = {
			"eq_chips",
			"Eqchips_mod",
			"EQchips_mod",
			-- TARGET: add =chips modifiers (or succession if you're silly)
		},
		operation = 0,
	},
	{
		keys = {
			"chips",
			"h_chips",
			"chip_mod",
		},
		operation = 1,
	},
	{
		keys = {
			"xchips",
			"x_chips",
			"Xchip_mod",
		},
		operation = 2,
	},
}

local chipsReturnOperators = {
	"chips",
	"xchips",
	"echips",
}

--- Handles Caeruleum's operator increase.
--- @param key string The key being checked.
--- @return boolean was_key_changed Whether the key was actually changed.
--- @return string new_key The new key if it was changed, or old one if it wasn't.
--- @return integer? op The new operator's position in the hyperoperation sequence. `nil` if the key wasn't changed.\n(1 is addition, 2 is multiplication, 3 is exponentiation)
function Cryptid.caeruleum_new_key(key)
	if not SMODS.Calculation_Controls.chips or not key then
		return false, key
	end

	for _, op in ipairs(chipsOperators) do
		for _, key2 in pairs(op.keys) do
			if key == key2 then
				local op2 = math.max(1, math.min(op.operation + 1, 3))
				local new_key = chipsReturnOperators[op2]

				return true, new_key, op2
			end
		end
	end

	return false, key
end

local items = {
	gateway,
	iterum,
	universum,
	exponentia,
	speculo,
	redeo,
	tenebris, -- disabled due to bignum crash, possibly fixed?
	effarcire,
	effarcire_sprite,
	crustulum,
	primus,
	scalae,
	stella_mortis,
	circulus_pistoris,
	aequilibrium,
	facile,
	gemino,
	energia,
	verisimile, -- it's an exotic because it's fucking peak
	--rescribere, [NEEDS REFACTOR]
	duplicare,
	formidiulosus, -- see tenebris
	caeruleum,
}
return {
	name = "Exotic Jokers",
	init = function() end,
	items = items,
}
