balatro-mods/Cryptid/lib/gameset.lua

1811 lines
50 KiB
Lua

-- gameset.lua: functions for gameset UI and logic
-- Future changes I want to make to this:
-- - Sort cards in the Cryptid additions tab in collection order
-- - Give thematic sets a button to view content from just their set
-- - Edition decks and similar display their editions in the gameset config UI
-------------------------
------ MODS LIST --------
-------------------------
-- If you plan on adding any new cross-mod content with one of these mods within the Cryptid source,
-- please add the name here so it displays properly in the Disabled message.
-- do it in the format MOD_ID = "MOD_NAME"
Cryptid.cross_mod_names = {
CardSleeves = "Card Sleeves",
Cryptid = "Cryptid",
jen = "Jen's Almanac",
sdm0sstuff = "SDM_0's Stuff",
magic_the_jokering = "Magic the Jokering",
}
-------------------------
---- TUTORIAL SYSTEM ----
-------------------------
local gu = Game.update
function Game:update(dt)
gu(self, dt)
if not G.PROFILES[G.SETTINGS.profile].cry_intro_complete then
G.FUNCS.cry_intro_controller()
end
end
G.FUNCS.cry_intro_controller = function()
if Jen then
G.PROFILES[G.SETTINGS.profile].cry_intro_complete = true
G.PROFILES[G.SETTINGS.profile].cry_gameset = "madness"
end
G.PROFILES[G.SETTINGS.profile].cry_intro_progress = G.PROFILES[G.SETTINGS.profile].cry_intro_progress
or {
state = "start",
completed = {},
}
if not G.SETTINGS.paused and not G.PROFILES[G.SETTINGS.profile].cry_intro_complete then
if G.STATE == G.STATES.MENU and not G.PROFILES[G.SETTINGS.profile].cry_intro_progress.completed.start then
G.PROFILES[G.SETTINGS.profile].cry_intro_progress.section = "start"
G.FUNCS.cry_intro_part("start")
G.PROFILES[G.SETTINGS.profile].cry_intro_progress.completed.start = true
G:save_progress()
end
end
end
function create_UIBox_character_button_with_sprite(args)
local button = args.button or "NONE"
local func = args.func or nil
local colour = args.colour or G.C.RED
local update_func = args.update_func or nil
local sprite = args.sprite or nil
local t = --{n=G.UIT.ROOT, config = {align = "cm", padding = 0.1, colour = G.C.CLEAR}, nodes={
{
n = G.UIT.C,
config = {
align = "tm",
minw = 2.5,
padding = 0.2,
minh = 1.2,
r = 0.1,
hover = true,
colour = colour,
button = func,
func = update_func,
shadow = true,
maxw = args.maxw,
id = args.id,
},
nodes = {
{
n = G.UIT.R,
config = { align = "cm", padding = 0 },
nodes = {
{
n = G.UIT.T,
config = {
text = button,
scale = 0.55,
colour = G.C.UI.TEXT_LIGHT,
focus_args = { button = "x", orientation = "bm" },
func = "set_button_pip",
},
},
},
},
{
n = G.UIT.R,
config = { align = "cm", padding = 0 },
nodes = {
{ n = G.UIT.O, config = { object = sprite } },
},
},
},
} --,
--}}
return t
end
G.FUNCS.cry_intro_part = function(_part)
local step = 1
G.SETTINGS.paused = true
if _part == "start" then
G.gateway = Sprite(
G.ROOM_ATTACH.T.x + G.ROOM_ATTACH.T.w / 2 - 1,
G.ROOM_ATTACH.T.y + G.ROOM_ATTACH.T.h / 2 - 4,
G.CARD_W * 1.5,
G.CARD_H * 1.5,
G.ASSET_ATLAS["cry_atlasnotjokers"],
{ x = 2, y = 0 }
)
G.gateway.states.visible = false
G.gateway.states.collide.can = true
G.gateway.states.focus.can = false
G.gateway.states.hover.can = true
G.gateway.states.drag.can = false
G.gateway.hover = Node.hover
G.yawetag = Sprite(
G.ROOM_ATTACH.T.x + G.ROOM_ATTACH.T.w / 2 - 1,
G.ROOM_ATTACH.T.y + G.ROOM_ATTACH.T.h / 2 - 4,
G.CARD_W * 1.5,
G.CARD_H * 1.5,
G.ASSET_ATLAS["cry_atlasnotjokers"],
{ x = 6, y = 5 }
)
G.yawetag.states.visible = false
G.yawetag.states.collide.can = true
G.yawetag.states.focus.can = false
G.yawetag.states.hover.can = true
G.yawetag.states.drag.can = false
G.yawetag.hover = Node.hover
step = cry_intro_info({
text_key = "cry_intro_1",
attach = { major = G.ROOM_ATTACH, type = "cm", offset = { x = 0, y = 0 } },
step = step,
})
step = cry_intro_info({
text_key = "cry_intro_2",
attach = { major = G.ROOM_ATTACH, type = "cm", offset = { x = 0, y = -3 } },
step = step,
})
step = cry_intro_info({
text_key = "cry_intro_3",
attach = { major = G.ROOM_ATTACH, type = "cm", offset = { x = 0, y = -3 } },
step = step,
highlight = {
G.gateway,
G.yawetag,
},
on_start = function()
G.gateway.states.visible = true
G.gateway:set_alignment({ major = G.ROOM_ATTACH, type = "cm", offset = { x = -2.5, y = -3 } })
G.yawetag.states.visible = true
G.yawetag:set_alignment({ major = G.ROOM_ATTACH, type = "cm", offset = { x = 2.5, y = -3 } })
end,
})
step = cry_intro_info({
text_key = "cry_intro_4",
attach = { major = G.ROOM_ATTACH, type = "cm", offset = { x = 0, y = -3 } },
step = step,
highlight = {
G.gateway,
G.yawetag,
},
})
local modestSprite = Sprite(0, 0, 1, 1, G.ASSET_ATLAS["cry_gameset"], { x = 0, y = 0 })
modestSprite:define_draw_steps({
{ shader = "dissolve", shadow_height = 0.05 },
{ shader = "dissolve" },
})
local mainlineSprite = Sprite(0, 0, 1, 1, G.ASSET_ATLAS["cry_gameset"], { x = 1, y = 0 })
mainlineSprite:define_draw_steps({
{ shader = "dissolve", shadow_height = 0.05 },
{ shader = "dissolve" },
})
local madnessSprite = Sprite(0, 0, 1, 1, G.ASSET_ATLAS["cry_gameset"], { x = 2, y = 0 })
madnessSprite:define_draw_steps({
{ shader = "dissolve", shadow_height = 0.05 },
{ shader = "dissolve" },
})
--TODO: localize
G.modestBtn = create_UIBox_character_button_with_sprite({
sprite = modestSprite,
button = "Modest",
id = "modest",
func = "cry_modest",
colour = G.C.GREEN,
maxw = 3,
})
G.mainlineBtn = create_UIBox_character_button_with_sprite({
sprite = mainlineSprite,
button = "Mainline",
id = "mainline",
func = "cry_mainline",
colour = G.C.RED,
maxw = 3,
})
G.madnessBtn = create_UIBox_character_button_with_sprite({
sprite = madnessSprite,
button = "Madness",
id = "madness",
func = "cry_madness",
colour = G.C.CRY_EXOTIC,
maxw = 3,
})
local gamesetUI = create_UIBox_generic_options({
infotip = false,
contents = {
G.modestBtn,
G.mainlineBtn,
G.madnessBtn,
},
back_label = "Confirm",
back_colour = G.C.BLUE,
back_func = "cry_gameset_confirm",
})
G.E_MANAGER:add_event(Event({
trigger = "after",
blocking = false,
blockable = false,
func = function()
G.madnessBtn.config.colour = G.C.CRY_EXOTIC
return true
end,
}))
gamesetUI.nodes[2] = nil
gamesetUI.config.colour = G.C.CLEAR
G.gamesetUI = UIBox({
definition = gamesetUI,
config = { major = G.ROOM_ATTACH, type = "cm", offset = { x = 0, y = 2.5 } },
})
G.gamesetUI.states.visible = false
step = cry_intro_info({
text_key = "cry_intro_5",
attach = { major = G.ROOM_ATTACH, type = "cm", offset = { x = 0, y = -3 } },
step = step,
highlight = {
G.gateway,
G.yawetag,
G.gamesetUI,
},
on_start = function()
--the scaling should be eased later...
G.gamesetUI.states.visible = true
G.gateway:set_alignment({ major = G.ROOM_ATTACH, type = "cm", offset = { x = -4.5, y = 2.2 } })
G.gateway.T.w = G.gateway.T.w * 3
G.gateway.T.h = G.gateway.T.h * 3
G.yawetag:set_alignment({ major = G.ROOM_ATTACH, type = "cm", offset = { x = 4.5, y = 2.2 } })
G.yawetag.T.w = G.yawetag.T.w * 3
G.yawetag.T.h = G.yawetag.T.h * 3
end,
no_button = true,
})
end
if _part == "modest" or _part == "mainline" or _part == "madness" then
local desc_length = { --number of times Jolly Joker speaks for each gameset
modest = 2,
mainline = 3,
madness = 3,
}
G.E_MANAGER:clear_queue("tutorial")
if G.OVERLAY_TUTORIAL.content then
G.OVERLAY_TUTORIAL.content:remove()
end
G.OVERLAY_TUTORIAL.Jimbo:remove_button()
G.OVERLAY_TUTORIAL.Jimbo:remove_speech_bubble()
G.OVERLAY_TUTORIAL.step = nil
for i = 1, desc_length[_part] do
step = cry_intro_info({
text_key = "cry_" .. _part .. "_" .. i,
attach = { major = G.ROOM_ATTACH, type = "cm", offset = { x = 0, y = -3 } },
step = step,
highlight = {
G.gamesetUI:get_UIE_by_ID(_part),
},
})
end
step = cry_intro_info({
no_button = true,
attach = { major = G.ROOM_ATTACH, type = "cm", offset = { x = 0, y = -3 } },
step = step,
highlight = {
G.gateway,
G.yawetag,
G.gamesetUI,
},
})
end
end
G.FUNCS.cry_modest = function(e)
G.modestBtn.config.colour = G.C.CRY_SELECTED
G.mainlineBtn.config.colour = G.C.RED
G.madnessBtn.config.colour = G.C.CRY_EXOTIC
G.FUNCS.cry_intro_part("modest")
G.selectedGameset = "modest"
end
G.FUNCS.cry_mainline = function(e)
G.modestBtn.config.colour = G.C.GREEN
G.mainlineBtn.config.colour = G.C.CRY_SELECTED
G.madnessBtn.config.colour = G.C.CRY_EXOTIC
G.FUNCS.cry_intro_part("mainline")
G.selectedGameset = "mainline"
end
G.FUNCS.cry_madness = function(e)
G.modestBtn.config.colour = G.C.GREEN
G.mainlineBtn.config.colour = G.C.RED
G.madnessBtn.config.colour = G.C.CRY_SELECTED
G.FUNCS.cry_intro_part("madness")
G.selectedGameset = "madness"
end
G.FUNCS.cry_gameset_confirm = function(e)
if G.selectedGameset then
G.PROFILES[G.SETTINGS.profile].cry_intro_complete = true
G.PROFILES[G.SETTINGS.profile].cry_gameset = G.selectedGameset
G.SETTINGS.paused = false
G.gamesetUI:remove()
G.gateway:remove()
G.yawetag:remove()
G.E_MANAGER:clear_queue("tutorial")
G.OVERLAY_TUTORIAL.Jimbo:remove()
if G.OVERLAY_TUTORIAL.content then
G.OVERLAY_TUTORIAL.content:remove()
end
G.OVERLAY_TUTORIAL:remove()
G.OVERLAY_TUTORIAL = nil
if G.selectedGameset == "madness" then
--Unlock All by default in madness
G.PROFILES[G.SETTINGS.profile].all_unlocked = true
for k, v in pairs(G.P_CENTERS) do
if not v.demo and not v.wip then
v.alerted = true
v.discovered = true
v.unlocked = true
end
end
for k, v in pairs(G.P_BLINDS) do
if not v.demo and not v.wip then
v.alerted = true
v.discovered = true
v.unlocked = true
end
end
for k, v in pairs(G.P_TAGS) do
if not v.demo and not v.wip then
v.alerted = true
v.discovered = true
v.unlocked = true
end
end
set_profile_progress()
set_discover_tallies()
G:save_progress()
G.FILE_HANDLER.force = true
end
end
end
function cry_intro_info(args)
local overlay_colour = { 0.32, 0.36, 0.41, 0 }
ease_value(overlay_colour, 4, 0.6, nil, "REAL", true, 0.4)
G.OVERLAY_TUTORIAL = G.OVERLAY_TUTORIAL
or UIBox({
definition = {
n = G.UIT.ROOT,
config = { align = "cm", padding = 32.05, r = 0.1, colour = overlay_colour, emboss = 0.05 },
nodes = {},
},
config = {
align = "cm",
offset = { x = 0, y = 3.2 },
major = G.ROOM_ATTACH,
bond = "Weak",
},
})
G.OVERLAY_TUTORIAL.step = G.OVERLAY_TUTORIAL.step or 1
G.OVERLAY_TUTORIAL.step_complete = false
local row_dollars_chips = G.HUD and G.HUD:get_UIE_by_ID("row_dollars_chips") or G.ROOM_ATTACH
local align = args.align or "tm"
local step = args.step or 1
local attach = args.attach or { major = row_dollars_chips, type = "tm", offset = { x = 0, y = -0.5 } }
local pos = args.pos or { x = attach.major.T.x + attach.major.T.w / 2, y = attach.major.T.y + attach.major.T.h / 2 }
local button = args.button or { button = localize("b_next"), func = "tut_next" }
args.highlight = args.highlight or {}
G.E_MANAGER:add_event(
Event({
trigger = "after",
delay = 0.3,
func = function()
if G.OVERLAY_TUTORIAL and G.OVERLAY_TUTORIAL.step == step and not G.OVERLAY_TUTORIAL.step_complete then
if args.on_start then
args.on_start()
end
G.CONTROLLER.interrupt.focus = true
G.OVERLAY_TUTORIAL.Jimbo = G.OVERLAY_TUTORIAL.Jimbo or Card_Character(pos)
if type(args.highlight) == "function" then
args.highlight = args.highlight()
end
args.highlight[#args.highlight + 1] = G.OVERLAY_TUTORIAL.Jimbo
if args.text_key then
G.OVERLAY_TUTORIAL.Jimbo:add_speech_bubble(args.text_key, align, args.loc_vars)
end
G.OVERLAY_TUTORIAL.Jimbo:set_alignment(attach)
if args.hard_set then
G.OVERLAY_TUTORIAL.Jimbo:hard_set_VT()
end
G.OVERLAY_TUTORIAL.button_listen = nil
if G.OVERLAY_TUTORIAL.content then
G.OVERLAY_TUTORIAL.content:remove()
end
if args.content then
G.OVERLAY_TUTORIAL.content = UIBox({
definition = args.content(),
config = {
align = args.content_config and args.content_config.align or "cm",
offset = args.content_config and args.content_config.offset or { x = 0, y = 0 },
major = args.content_config and args.content_config.major or G.OVERLAY_TUTORIAL.Jimbo,
bond = "Weak",
},
})
args.highlight[#args.highlight + 1] = G.OVERLAY_TUTORIAL.content
end
if args.button_listen then
G.OVERLAY_TUTORIAL.button_listen = args.button_listen
end
if not args.no_button then
G.OVERLAY_TUTORIAL.Jimbo:add_button(
button.button,
button.func,
button.colour,
button.update_func,
true
)
end
G.OVERLAY_TUTORIAL.Jimbo:say_stuff(2 * #(G.localization.misc.tutorial[args.text_key] or {}) + 1)
if args.snap_to then
G.E_MANAGER:add_event(
Event({
trigger = "immediate",
blocking = false,
blockable = false,
func = function()
if
G.OVERLAY_TUTORIAL
and G.OVERLAY_TUTORIAL.Jimbo
and not G.OVERLAY_TUTORIAL.Jimbo.talking
then
local _snap_to = args.snap_to()
if _snap_to then
G.CONTROLLER.interrupt.focus = false
G.CONTROLLER:snap_to({ node = args.snap_to() })
end
return true
end
end,
}),
"tutorial"
)
end
if args.highlight then
G.OVERLAY_TUTORIAL.highlights = args.highlight
end
G.OVERLAY_TUTORIAL.step_complete = true
end
return not G.OVERLAY_TUTORIAL or G.OVERLAY_TUTORIAL.step > step or G.OVERLAY_TUTORIAL.skip_steps
end,
}),
"tutorial"
)
return step + 1
end
-- Profile stuff: all profiles start with M to separate from vanilla
function G.UIDEF.profile_select()
G.focused_profile = G.focused_profile or G.SETTINGS.profile or (Cryptid.profile_prefix .. "1")
local t = create_UIBox_generic_options({
padding = 0,
contents = {
{
n = G.UIT.R,
config = { align = "cm", padding = 0, draw_layer = 1, minw = 4 },
nodes = {
create_tabs({
tabs = {
{
label = Cryptid.profile_prefix .. "1",
chosen = G.focused_profile == (Cryptid.profile_prefix .. "1"),
tab_definition_function = G.UIDEF.profile_option,
tab_definition_function_args = Cryptid.profile_prefix .. "1",
},
{
label = Cryptid.profile_prefix .. "2",
chosen = G.focused_profile == (Cryptid.profile_prefix .. "2"),
tab_definition_function = G.UIDEF.profile_option,
tab_definition_function_args = Cryptid.profile_prefix .. "2",
},
{
label = Cryptid.profile_prefix .. "3",
chosen = G.focused_profile == (Cryptid.profile_prefix .. "3"),
tab_definition_function = G.UIDEF.profile_option,
tab_definition_function_args = Cryptid.profile_prefix .. "3",
},
},
snap_to_nav = true,
}),
},
},
},
})
return t
end
------------------------
---- GAMESET SYSTEM ----
------------------------
-- Gets gameset sprite of current profile
function gameset_sprite(scale, profile, force_gameset)
gameset = force_gameset
or G.PROFILES[profile or G.SETTINGS.profile].cry_gameset_overrides and "modified"
or G.PROFILES[profile or G.SETTINGS.profile].cry_gameset
scale = scale or 1
local sprite = Sprite(
0,
0,
scale,
scale,
G.ASSET_ATLAS["cry_gameset"],
{ x = (gameset == "modified" and 3 or gameset == "madness" and 2 or gameset == "modest" and 0 or 1), y = 0 }
)
sprite:define_draw_steps({
{ shader = "dissolve", shadow_height = 0.09 },
{ shader = "dissolve" },
})
sprite.states.collide.can = true
sprite.states.drag.can = true
return sprite
end
-- designed to work on any object type
function cry_get_gameset(card, center)
if Jen then
return "madness"
end
if not center then
if not card then
return G.PROFILES[G.SETTINGS.profile].cry_gameset or "mainline"
end
center = card.config and card.config.center or card.effect and card.effect.center or card
end
if card.force_gameset then
return card.force_gameset
end
if center.force_gameset then
return center.force_gameset
end
if center.fake_card then
return G.PROFILES[G.SETTINGS.profile].cry_gameset or "mainline"
end
if not center.key then
if center.tag and center.tag.key then --dumb fix for tags
center = center.tag
else
print("Could not find key for center: " .. tprint(center))
return G.PROFILES[G.SETTINGS.profile].cry_gameset or "mainline"
end
end
local gameset = G.PROFILES[G.SETTINGS.profile].cry_gameset or "mainline"
if Cryptid_config.experimental and center.extra_gamesets then
for i = 1, #center.extra_gamesets do
if center.extra_gamesets[i] == "experimental_" .. gameset then
gameset = "experimental_" .. gameset
break
elseif center.extra_gamesets[i] == "experimental" then
gameset = "experimental"
break
end
end
end
if
G.PROFILES[G.SETTINGS.profile].cry_gameset_overrides
and G.PROFILES[G.SETTINGS.profile].cry_gameset_overrides[center.key]
then
return G.PROFILES[G.SETTINGS.profile].cry_gameset_overrides[center.key]
end
return gameset
end
-- set_ability accounts for gamesets
function Card:get_gameset(center)
return cry_get_gameset(self, center)
end
local csa = Card.set_ability
function Card:set_ability(center, y, z)
if not center.config then
center.config = {} --crashproofing
end
csa(self, center, y, z)
if center.gameset_config and center.gameset_config[self:get_gameset(center)] then
for k, v in pairs(center.gameset_config[self:get_gameset(center)]) do
if k ~= "disabled" and k ~= "center" then
if k == "cost" then
self.base_cost = v
else
self.ability[k] = v
end
end
end
if center.gameset_config[self:get_gameset(center)].disabled then
self.cry_disabled = true
end
if center.gameset_config[self:get_gameset(center)].center and not self.gameset_select then
for k, v in pairs(center.gameset_config[self:get_gameset(center)].center) do
center[k] = v
self[k] = v
if k == "rarity" then
center:set_rarity(v)
else
self.config.center[k] = v
end
end
end
end
end
--open gameset config UI when clicking on a card in the Cryptid collection
--disable this functionality for Jen's Almanac
if not Jen then
local ccl = Card.click
function Card:click()
ccl(self)
if G.your_collection then
for k, v in pairs(G.your_collection) do
if self.area == v and G.ACTIVE_MOD_UI and G.ACTIVE_MOD_UI.id == "Cryptid" then
if not self.config.center or self.config.center and self.config.center.set == "Default" then
--make a fake center
local old_force_gameset = self.config.center and self.config.center.force_gameset
if self.seal then
self.config.center = SMODS.Seal.obj_table[self.seal]
self.config.center.set = "Seal"
end
for k, v in pairs(SMODS.Stickers) do
if self.ability[k] then
self.config.center = SMODS.Sticker.obj_table[k]
self.config.center.set = "Sticker"
end
end
if self.config.center then
self.config.center.force_gameset = old_force_gameset
end
end
if self.gameset_select then
Card.cry_set_gameset(self, self.config.center, self.config.center.force_gameset)
cry_update_obj_registry()
end
cry_gameset_config_UI(self.config.center)
end
end
end
end
end
-- gameset config UI
function cry_gameset_config_UI(center)
if not center then
center = G.viewedContentSet
end
G.SETTINGS.paused = true
G.your_collection = {}
G.your_collection[1] = CardArea(
G.ROOM.T.x + 0.2 * G.ROOM.T.w / 2,
G.ROOM.T.h,
5.3 * G.CARD_W,
1.03 * G.CARD_H,
{ card_limit = 5, type = "title", highlight_limit = 0, collection = true }
)
local deck_tables = {
n = G.UIT.R,
config = { align = "cm", padding = 0, no_fill = true },
nodes = {
{ n = G.UIT.O, config = { object = G.your_collection[1] } },
},
}
local gamesets = { "disabled", "modest", "mainline", "madness" }
if center.extra_gamesets then
for i = 1, #center.extra_gamesets do
gamesets[#gamesets + 1] = center.extra_gamesets[i]
end
end
if center.set == "Content Set" then
gamesets = { "disabled", G.PROFILES[G.SETTINGS.profile].cry_gameset }
end
for i = 1, #gamesets do
if
not (
center.gameset_config
and center.gameset_config[gamesets[i]]
and center.gameset_config[gamesets[i]].disabled
)
then
local _center = cry_deep_copy(center)
_center.force_gameset = gamesets[i]
local card = create_generic_card(_center)
card.gameset_select = true
G.your_collection[1]:emplace(card)
--[[if not is_back then
local card = Card(
G.your_collection[1].T.x + G.your_collection[1].T.w / 2,
G.your_collection[1].T.y,
G.CARD_W,
G.CARD_H,
G.P_CARDS.empty,
_center
)
card:start_materialize()
card.gameset_select = true
G.your_collection[1]:emplace(card)
else
local fake_center = {
set = "Back",
force_gameset = gamesets[i],
pos = center.pos,
atlas = center.atlas,
key = center.key,
config = {}
}
local card = Card(G.ROOM.T.x + 0.2*G.ROOM.T.w/2,G.ROOM.T.h, G.CARD_W, G.CARD_H, G.P_CARDS.empty, fake_center)
card:start_materialize()
card.gameset_select = true
G.your_collection[1]:emplace(card)
end--]]
end
end
INIT_COLLECTION_CARD_ALERTS()
local args = {
infotip = localize("cry_gameset_explanation"),
back_func = G.cry_prev_collec,
snap_back = true,
contents = {
{
n = G.UIT.R,
config = { align = "cm", minw = 2.5, padding = 0.1, r = 0.1, colour = G.C.BLACK, emboss = 0.05 },
nodes = { deck_tables },
},
},
}
if center.set == "Content Set" then
G.viewedContentSet = center
args.back2 = true
args.back2_func = "your_collection_current_set"
args.back2_label = localize("cry_view_set_contents")
args.back2_colour = G.C.CRY_SELECTED
end
local t = create_UIBox_generic_options(args)
G.FUNCS.overlay_menu({
definition = t,
})
end
function G.FUNCS.cry_gameset_config_UI()
G.cry_prev_collec = "your_collection_content_sets"
cry_gameset_config_UI()
end
local collection_shtuff = {
"blinds",
"jokers",
-- consumables don't work
-- idk what smods is doing with consumable collection stuff, anyone know what the buttons are doing?
"tarots",
"planets",
"spectrals",
"codes",
"vouchers",
"enhancements",
"decks",
"editions",
"tags",
"seals",
"boosters",
"stickers",
"content_sets",
}
-- sure this is cool and all but it doesn't keep page yet so it's pretty useless
-- would need to regex patch that
for i, v in ipairs(collection_shtuff) do
local ref = G.FUNCS["your_collection_" .. v]
G.FUNCS["your_collection_" .. v] = function(e)
G.cry_prev_collec = "your_collection_" .. v
ref(e)
end
end
G.cry_prev_collec = "your_collection_jokers"
-- change the rarity sticker's color for gameset selection on an item
local gtc = get_type_colour
function get_type_colour(center, card)
local color = gtc(center, card)
if center.set == "Back" or center.set == "Tag" or center.set == "Blind" then
color = G.C.CRY_SELECTED
end
if card.gameset_select then
if center.force_gameset == "modest" then
color = G.C.GREEN
elseif center.force_gameset == "mainline" then
color = G.C.RED
elseif center.force_gameset == "madness" then
color = G.C.CRY_EXOTIC
elseif center.force_gameset ~= "disabled" then
color = G.C.CRY_ASCENDANT
end
end
if
cry_get_gameset(card, center) == "disabled"
or (center.cry_disabled and (not card.gameset_select or center.cry_disabled.type ~= "manual"))
then
color = mix_colours(G.C.RED, G.C.GREY, 0.7)
end
return color
end
function Card:cry_set_gameset(center, gameset)
if
G.PROFILES[G.SETTINGS.profile].cry_gameset == gameset
and not G.PROFILES[G.SETTINGS.profile].cry_gameset_overrides
then
return
end
if not G.PROFILES[G.SETTINGS.profile].cry_gameset_overrides then
G.PROFILES[G.SETTINGS.profile].cry_gameset_overrides = {}
end
G.PROFILES[G.SETTINGS.profile].cry_gameset_overrides[center.key] = gameset
if G.PROFILES[G.SETTINGS.profile].cry_gameset == gameset then
G.PROFILES[G.SETTINGS.profile].cry_gameset_overrides[center.key] = nil
end
local empty = true
for _, _ in pairs(G.PROFILES[G.SETTINGS.profile].cry_gameset_overrides) do
empty = false
break
end
if empty then
G.PROFILES[G.SETTINGS.profile].cry_gameset_overrides = nil
end
G:save_progress()
end
function G.FUNCS.reset_gameset_config()
G.PROFILES[G.SETTINGS.profile].cry_gameset_overrides = nil
cry_update_obj_registry()
G:save_progress()
end
function cry_card_enabled(key, iter)
if not iter then
iter = 0
end --iter is used to prevent infinite loops from freezing on startup
if iter > 10 then
print("Warning: Circular dependency with " .. key)
return true
end
local card = cry_get_center(key)
if
not card
or cry_get_gameset(card) == "disabled"
or card.gameset_config
and card.gameset_config[cry_get_gameset(card)]
and card.gameset_config[cry_get_gameset(card)].disabled
then
return { type = "manual" }
end
if card.dependencies then
if card.dependencies.items then
for i = 1, #card.dependencies.items do
if cry_card_enabled(card.dependencies.items[i], iter + 1) ~= true then
return { type = "card_dependency", key = card.dependencies.items[i] }
end
end
end
if card.dependencies.mods then
for i = 1, #card.dependencies.mods do
if not (SMODS.Mods[card.dependencies.mods[i]] or {}).can_load then
return { type = "mod_dependency", key = card.dependencies.mods[i] }
end
end
end
end
if card.conflicts then
if card.conflicts.mods then
for i = 1, #card.conflicts.mods do
if (SMODS.Mods[card.conflicts.mods[i]] or {}).can_load then
return { type = "mod_conflict", key = card.conflicts.mods[i] }
end
end
end
end
return true
end
function cry_get_center(key, m)
if not m then
-- check for non game objects
if SMODS.Seals.obj_table and SMODS.Seals.obj_table[key] then
return SMODS.Seals.obj_table[key]
end
if SMODS.Stickers.obj_table and SMODS.Stickers.obj_table[key] then
return SMODS.Stickers.obj_table[key]
end
m = SMODS.GameObject
if m.subclasses then
for k, v in pairs(m.subclasses) do
local c = cry_get_center(key, v)
if c then
return c
end
end
end
end
return m.obj_table and m.obj_table[key]
end
------------------------------
---- CARD ENABLING SYSTEM ----
------------------------------
SMODS.GameObject._disable = function(self, reason)
if not self.cry_disabled then
self.cry_disabled = reason or { type = "manual" } --used to display more information that can be used later
end
end
SMODS.GameObject.enable = function(self)
if self.cry_disabled then
self.cry_disabled = nil
end
end
-- Note: For custom pools, these only support Center.pools, not ObjectType.cards
-- That could cause issues with mod compat in the future
-- Potential improvement: automatic pool detection from gamesets?
SMODS.Center._disable = function(self, reason)
if not self.cry_disabled then
self.cry_disabled = reason or { type = "manual" } --used to display more information that can be used later
SMODS.remove_pool(G.P_CENTER_POOLS[self.set], self.key)
for k, v in pairs(self.pools or {}) do
SMODS.ObjectTypes[k]:delete_card(self)
end
G.P_CENTERS[self.key] = nil
end
end
SMODS.Center.enable = function(self)
if self.cry_disabled then
self.cry_disabled = nil
SMODS.insert_pool(G.P_CENTER_POOLS[self.set], self)
G.P_CENTERS[self.key] = self
for k, v in pairs(self.pools or {}) do
SMODS.ObjectTypes[k]:inject_card(self)
end
end
end
SMODS.Joker.enable = function(self)
if self.cry_disabled then
SMODS.Center.enable(self)
SMODS.insert_pool(G.P_JOKER_RARITY_POOLS[self.rarity], self)
local vanilla_rarities = { ["Common"] = 1, ["Uncommon"] = 2, ["Rare"] = 3, ["Legendary"] = 4 }
if vanilla_rarities[self.rarity] then
SMODS.insert_pool(G.P_JOKER_RARITY_POOLS[vanilla_rarities[self.rarity]], self)
end
end
end
SMODS.Joker._disable = function(self, reason)
if not self.cry_disabled then
SMODS.Center._disable(self, reason)
SMODS.remove_pool(G.P_JOKER_RARITY_POOLS[self.rarity], self.key)
local vanilla_rarities = { ["Common"] = 1, ["Uncommon"] = 2, ["Rare"] = 3, ["Legendary"] = 4 }
if vanilla_rarities[self.rarity] then
SMODS.remove_pool(G.P_JOKER_RARITY_POOLS[vanilla_rarities[self.rarity]], self.key)
end
end
end
SMODS.Joker.set_rarity = function(self, rarity)
SMODS.remove_pool(G.P_JOKER_RARITY_POOLS[self.rarity], self.key)
self.rarity = rarity
SMODS.insert_pool(G.P_JOKER_RARITY_POOLS[self.rarity], self)
local vanilla_rarities = { ["Common"] = 1, ["Uncommon"] = 2, ["Rare"] = 3, ["Legendary"] = 4 }
if vanilla_rarities[self.rarity] then
SMODS.insert_pool(G.P_JOKER_RARITY_POOLS[vanilla_rarities[self.rarity]], self)
end
end
SMODS.Consumable.enable = function(self)
if self.cry_disabled then
SMODS.Center.enable(self)
SMODS.insert_pool(G.P_CENTER_POOLS["Consumeables"], self)
end
end
SMODS.Consumable._disable = function(self, reason)
if not self.cry_disabled then
SMODS.Center._disable(self, reason)
SMODS.remove_pool(G.P_CENTER_POOLS["Consumeables"], self.key)
end
end
SMODS.Tag._disable = function(self, reason)
if not self.cry_disabled then
self.cry_disabled = reason or { type = "manual" } --used to display more information that can be used later
SMODS.remove_pool(G.P_CENTER_POOLS[self.set], self.key)
G.P_TAGS[self.key] = nil
end
end
SMODS.Tag.enable = function(self)
if self.cry_disabled then
self.cry_disabled = nil
SMODS.insert_pool(G.P_CENTER_POOLS[self.set], self)
G.P_TAGS[self.key] = self
end
end
SMODS.Blind._disable = function(self, reason)
if not self.cry_disabled then
self.cry_disabled = reason or { type = "manual" } --used to display more information that can be used later
G.P_BLINDS[self.key] = nil
end
end
SMODS.Blind.enable = function(self)
if self.cry_disabled then
self.cry_disabled = nil
G.P_BLINDS[self.key] = self
end
end
--Removing seals from the center table causes issues
SMODS.Seal._disable = function(self, reason)
if not self.cry_disabled then
self.cry_disabled = reason or { type = "manual" } --used to display more information that can be used later
SMODS.remove_pool(G.P_CENTER_POOLS[self.set], self.key)
end
end
SMODS.Seal.enable = function(self)
if self.cry_disabled then
self.cry_disabled = nil
SMODS.insert_pool(G.P_CENTER_POOLS[self.set], self)
end
end
--Removing editions from the center table causes issues, so instead we make them unable to spawn naturally
SMODS.Edition._disable = function(self, reason)
if not self.cry_disabled then
self.cry_disabled = reason or { type = "manual" } --used to display more information that can be used later
SMODS.remove_pool(G.P_CENTER_POOLS[self.set], self.key)
self.cry_get_weight = self.get_weight
self.get_weight = function()
return 0
end
end
end
SMODS.Edition.enable = function(self)
if self.cry_disabled then
self.cry_disabled = nil
SMODS.insert_pool(G.P_CENTER_POOLS[self.set], self)
self.get_weight = self.cry_get_weight
self.cry_get_weight = nil
end
end
function cry_update_obj_registry(m, force_enable)
if not m then
m = SMODS.GameObject
if m.subclasses then
for k, v in pairs(m.subclasses) do
cry_update_obj_registry(v, force_enable)
end
end
end
if m.obj_table then
for k, v in pairs(m.obj_table) do
if v.mod and v.mod.id == "Cryptid" then
local en = force_enable or cry_card_enabled(k)
if en == true then
if v.cry_disabled then
v:enable()
end
else
if not v.cry_disabled then
v:_disable(en)
end
end
end
end
end
end
function cry_index_items(func, m)
if not m then
m = SMODS.GameObject
if m.subclasses then
for k, v in pairs(m.subclasses) do
cry_index_items(func, v)
end
end
end
if m.obj_table then
for k, v in pairs(m.obj_table) do
if v.mod and v.mod.id == "Cryptid" then
func(v)
end
end
end
end
local init_item_prototypes_ref = Game.init_item_prototypes
function Game:init_item_prototypes()
cry_update_obj_registry(nil, true) --force enable, to prevent issues with profile reloading
init_item_prototypes_ref(self)
cry_update_obj_registry()
end
------------------------
----- CONTENT SETS -----
------------------------
-- Content sets are used to group cards together in the settings menu, to bulk enable/disable things
-- These include CSL content sets, as well as others which are categorical (nostalgic items, epic jokers, etc.)
-- Because of this, they are referred to as Thematic Sets in-game
SMODS.ContentSet = SMODS.Center:extend({
set = "Content Set",
pos = { x = 0, y = 0 },
config = {},
class_prefix = "set",
required_params = {
"key",
},
inject = function(self)
if not G.P_CENTER_POOLS[self.set] then
G.P_CENTER_POOLS[self.set] = {}
end
SMODS.Center.inject(self)
if not self.cry_order then
self.cry_order = 0
end
end,
})
G.P_CENTER_POOLS["Content Set"] = {}
-- For now, I made larger sets appear earlier. This can be tweaked later...
SMODS.ContentSet({
key = "m",
atlas = "atlasepic",
pos = { x = 3, y = 1 }, --m
cry_order = -22,
})
SMODS.ContentSet({
key = "epic",
atlas = "atlasepic",
pos = { x = 2, y = 1 }, --Canvas
cry_order = -32,
})
SMODS.ContentSet({
key = "code",
atlas = "code",
pos = { x = 0, y = 0 }, --://CRASH
cry_order = -39,
})
SMODS.ContentSet({
key = "exotic",
atlas = "atlasexotic",
pos = { x = 0, y = 1 }, --Iterum
soul_pos = { x = 1, y = 1, extra = { x = 2, y = 1 } },
cry_order = -20,
})
SMODS.ContentSet({
key = "blind",
atlas = "blinds",
pos = { x = 0, y = 4 }, --The Joke
cry_blind = true,
cry_order = -26,
})
SMODS.ContentSet({
key = "deck",
atlas = "atlasdeck",
pos = { x = 4, y = 5 }, --Critical Deck
cry_order = -23,
})
SMODS.ContentSet({
key = "spooky",
atlas = "atlasspooky",
pos = { x = 1, y = 0 }, --Chocolate Dice
cry_order = -14,
})
SMODS.ContentSet({
key = "cursed",
atlas = "atlasspooky",
pos = { x = 3, y = 0 }, --Ghost
cry_order = -6,
})
SMODS.ContentSet({
key = "timer",
atlas = "blinds",
pos = { x = 0, y = 1 }, --The Clock
cry_blind = true,
cry_order = -2,
})
SMODS.ContentSet({
key = "misc",
atlas = "cry_misc",
pos = { x = 2, y = 0 }, --Echo Card
cry_order = -22,
})
SMODS.ContentSet({
key = "misc_joker",
atlas = "atlasone",
pos = { x = 2, y = 3 }, --Nice
cry_order = -111,
})
SMODS.ContentSet({
key = "planet",
atlas = "atlasnotjokers",
pos = { x = 4, y = 2 }, --Planet.lua
cry_order = -8,
})
SMODS.ContentSet({
key = "spectral",
atlas = "atlasnotjokers",
pos = { x = 1, y = 1 }, --Replica
cry_order = -12,
})
SMODS.ContentSet({
key = "tag",
atlas = "tag_cry",
pos = { x = 0, y = 2 }, --Cat Tag
cry_tag = true,
cry_order = -30,
})
SMODS.ContentSet({
key = "tier3",
atlas = "atlasvoucher",
pos = { x = 5, y = 2 }, --Asteroglyph
cry_order = -18,
})
SMODS.ContentSet({
key = "voucher",
atlas = "atlasvoucher",
pos = { x = 1, y = 2 }, --Tag Printer
cry_order = -15,
})
SMODS.ContentSet({
key = "poker_hand_stuff",
atlas = "atlasthree",
pos = { x = 7, y = 1 }, --The Fuck!? (Clusterfuck's XMult Joker)
cry_order = -16,
})
-- these are mostly copy/paste from vanilla code
G.FUNCS.your_collection_content_sets = function(e)
G.cry_prev_collec = "your_collection_content_sets"
G.SETTINGS.paused = true
G.FUNCS.overlay_menu({
definition = create_UIBox_your_collection_content_sets(),
})
end
G.FUNCS.your_collection_current_set = function(e)
G.cry_prev_collec = "your_collection_current_set"
G.SETTINGS.paused = true
G.FUNCS.overlay_menu({
definition = create_UIBox_your_collection_current_set(),
})
end
function create_UIBox_your_collection_content_sets()
local deck_tables = {}
G.your_collection = {}
for j = 1, 3 do
G.your_collection[j] = CardArea(
G.ROOM.T.x + 0.2 * G.ROOM.T.w / 2,
G.ROOM.T.h,
5 * G.CARD_W,
0.95 * G.CARD_H,
{ card_limit = 5, type = "title", highlight_limit = 0, collection = true }
)
table.insert(deck_tables, {
n = G.UIT.R,
config = { align = "cm", padding = 0.07, no_fill = true },
nodes = {
{ n = G.UIT.O, config = { object = G.your_collection[j] } },
},
})
end
local joker_pool = {}
for k, v in pairs(SMODS.ContentSet.obj_table) do
if v.set == "Content Set" then
table.insert(joker_pool, v)
end
end
table.sort(joker_pool, function(a, b)
return a.cry_order < b.cry_order
end)
local joker_options = {}
for i = 1, math.ceil(#joker_pool / (5 * #G.your_collection)) do
table.insert(
joker_options,
localize("k_page")
.. " "
.. tostring(i)
.. "/"
.. tostring(math.ceil(#joker_pool / (5 * #G.your_collection)))
)
end
for i = 1, 5 do
for j = 1, #G.your_collection do
local center = joker_pool[i + (j - 1) * 5]
if not center then
break
end
local card = create_generic_card(
center,
G.your_collection[j].T.x + G.your_collection[j].T.w / 2,
G.your_collection[j].T.y
)
G.your_collection[j]:emplace(card)
end
end
INIT_COLLECTION_CARD_ALERTS()
local t = create_UIBox_generic_options({
back_func = G.ACTIVE_MOD_UI and "openModUI_" .. G.ACTIVE_MOD_UI.id or "your_collection",
contents = {
{ n = G.UIT.R, config = { align = "cm", r = 0.1, colour = G.C.BLACK, emboss = 0.05 }, nodes = deck_tables },
{
n = G.UIT.R,
config = { align = "cm" },
nodes = {
create_option_cycle({
options = joker_options,
w = 4.5,
cycle_shoulders = true,
opt_callback = "your_collection_content_set_page",
current_option = 1,
colour = G.C.RED,
no_pips = true,
focus_args = { snap_to = true, nav = "wide" },
}),
},
},
},
})
return t
end
function create_UIBox_your_collection_current_set()
local deck_tables = {}
G.your_collection = {}
for j = 1, 3 do
G.your_collection[j] = CardArea(
G.ROOM.T.x + 0.2 * G.ROOM.T.w / 2,
G.ROOM.T.h,
5 * G.CARD_W,
0.95 * G.CARD_H,
{ card_limit = 5, type = "title", highlight_limit = 0, collection = true }
)
table.insert(deck_tables, {
n = G.UIT.R,
config = { align = "cm", padding = 0.07, no_fill = true },
nodes = {
{ n = G.UIT.O, config = { object = G.your_collection[j] } },
},
})
end
joker_pool = {}
local function is_in_set(card)
if card.dependencies and card.dependencies.items then
for i = 1, #card.dependencies.items do
if card.dependencies.items[i] == G.viewedContentSet.key then
joker_pool[#joker_pool + 1] = card
return true
end
end
end
end
cry_index_items(is_in_set)
table.sort(joker_pool, function(a, b)
return a.cry_order < b.cry_order
end)
local joker_options = {}
for i = 1, math.ceil(#joker_pool / (5 * #G.your_collection)) do
table.insert(
joker_options,
localize("k_page")
.. " "
.. tostring(i)
.. "/"
.. tostring(math.ceil(#joker_pool / (5 * #G.your_collection)))
)
end
for i = 1, 5 do
for j = 1, #G.your_collection do
local center = joker_pool[i + (j - 1) * 5]
if not center then
break
end
local card = create_generic_card(
center,
G.your_collection[j].T.x + G.your_collection[j].T.w / 2,
G.your_collection[j].T.y
)
G.your_collection[j]:emplace(card)
end
end
INIT_COLLECTION_CARD_ALERTS()
local t = create_UIBox_generic_options({
back_func = "cry_gameset_config_UI",
contents = {
{ n = G.UIT.R, config = { align = "cm", r = 0.1, colour = G.C.BLACK, emboss = 0.05 }, nodes = deck_tables },
{
n = G.UIT.R,
config = { align = "cm" },
nodes = {
create_option_cycle({
options = joker_options,
w = 4.5,
cycle_shoulders = true,
opt_callback = "your_collection_current_set_page",
current_option = 1,
colour = G.C.RED,
no_pips = true,
focus_args = { snap_to = true, nav = "wide" },
}),
},
},
},
})
return t
end
G.FUNCS.your_collection_content_set_page = function(args)
if not args or not args.cycle_config then
return
end
for j = 1, #G.your_collection do
for i = #G.your_collection[j].cards, 1, -1 do
local c = G.your_collection[j]:remove_card(G.your_collection[j].cards[i])
c:remove()
c = nil
end
end
local joker_pool = {}
for k, v in pairs(SMODS.ContentSet.obj_table) do
if v.set == "Content Set" then
table.insert(joker_pool, v)
end
end
table.sort(joker_pool, function(a, b)
return a.cry_order < b.cry_order
end)
for i = 1, 5 do
for j = 1, #G.your_collection do
local center =
joker_pool[i + (j - 1) * 5 + (5 * #G.your_collection * (args.cycle_config.current_option - 1))]
if not center then
break
end
local card = create_generic_card(
center,
G.your_collection[j].T.x + G.your_collection[j].T.w / 2,
G.your_collection[j].T.y
)
G.your_collection[j]:emplace(card)
end
end
INIT_COLLECTION_CARD_ALERTS()
end
G.FUNCS.your_collection_current_set_page = function(args)
if not args or not args.cycle_config then
return
end
for j = 1, #G.your_collection do
for i = #G.your_collection[j].cards, 1, -1 do
local c = G.your_collection[j]:remove_card(G.your_collection[j].cards[i])
c:remove()
c = nil
end
end
joker_pool = {}
local function is_in_set(card)
if card.dependencies and card.dependencies.items then
for i = 1, #card.dependencies.items do
if card.dependencies.items[i] == G.viewedContentSet.key then
joker_pool[#joker_pool + 1] = card
return true
end
end
end
end
cry_index_items(is_in_set)
table.sort(joker_pool, function(a, b)
return a.cry_order < b.cry_order
end)
for i = 1, 5 do
for j = 1, #G.your_collection do
local center =
joker_pool[i + (j - 1) * 5 + (5 * #G.your_collection * (args.cycle_config.current_option - 1))]
if not center then
break
end
local card = create_generic_card(
center,
G.your_collection[j].T.x + G.your_collection[j].T.w / 2,
G.your_collection[j].T.y
)
G.your_collection[j]:emplace(card)
end
end
INIT_COLLECTION_CARD_ALERTS()
end
------------------------------
---- GENERIC COLLECTIONS -----
------------------------------
function create_generic_card(center, x, y)
--todo: make gameset stickers play nicely with resized sprites
local is_blind = center.set == "Blind" or center.cry_blind
local is_tag = center.set == "Tag" or center.cry_tag
local card = Card(
x or G.ROOM.T.x + 0.2 * G.ROOM.T.w / 2,
y or G.ROOM.T.h,
is_blind and 0.7 * G.CARD_W or is_tag and 0.42 * G.CARD_W or G.CARD_W,
is_blind and 0.7 * G.CARD_W or is_tag and 0.42 * G.CARD_W or G.CARD_H,
nil,
center.set ~= "Seal" and center.set ~= "Sticker" and center or G.P_CENTERS.c_base
)
--todo: make this work when the edition is disabled (although it's a good failsafe that it doesn't?)
if center.set == "Edition" then
card:set_edition(center.key, true, true)
end
if safe_get(center, "config", "cry_antimatter") then
card:set_edition("e_negative", true, true)
return card
end
if safe_get(center, "config", "cry_force_edition") then
card:set_edition({ [center.config.cry_force_edition] = true }, true, true)
end
if center.set == "Seal" then
card:set_seal(center.key, true, true)
card.config.center = cry_deep_copy(card.config.center)
card.config.center.force_gameset = center.force_gameset
card.config.center.key = center.key
end
if safe_get(center, "config", "cry_force_seal") then
card:set_seal(center.config.cry_force_seal, true, true)
end
if center.set == "Sticker" then
center:apply(card, true)
card.config.center = cry_deep_copy(card.config.center)
card.config.center.force_gameset = center.force_gameset
card.config.center.key = center.key
end
if safe_get(center, "config", "cry_force_sticker") then
SMODS.Stickers[center.config.cry_force_sticker]:apply(card, true)
end
return card
end
-- Hooks for all collection types
local smcp = SMODS.collection_pool
SMODS.collection_pool = function(m)
if G.ACTIVE_MOD_UI and G.ACTIVE_MOD_UI.id == "Cryptid" then
-- use SMODS pools instead of vanilla pools, so disabled cards appear
if m[1] and m[1].set and m[1].set == "Seal" then
m = {}
for k, v in pairs(SMODS.Seal.obj_table) do
if v.mod and v.mod.id == "Cryptid" then
table.insert(m, v)
end
end
elseif m[1] and m[1].set and m[1].set == "Sticker" then
m = {}
for k, v in pairs(SMODS.Sticker.obj_table) do
if v.mod and v.mod.id == "Cryptid" then
table.insert(m, v)
end
end
elseif m[1] and m[1].set and G.P_CENTER_POOLS[m[1].set] == m then
local set = m[1].set
m = {}
for k, v in pairs(SMODS.Center.obj_table) do
if v.set == set and v.mod and v.mod.id == "Cryptid" then
table.insert(m, v)
end
end
end
-- Fix blind issues
for k, v in pairs(m) do
if v.set == "Blind" and v.mod and v.mod.id == "Cryptid" then
v.config = {}
end
end
table.sort(m, function(a, b)
return a.cry_order < b.cry_order
end)
end
return smcp(m)
end
-- Make Cryptid show all collection boxes (kinda silly)
local mct = modsCollectionTally
function modsCollectionTally(pool, set)
local t = mct(pool, set)
if G.ACTIVE_MOD_UI and G.ACTIVE_MOD_UI.id == "Cryptid" then
local obj_tally = { tally = 0, of = 0 }
--infer pool
local _set = set or safe_get(pool, 1, "set")
--check for general consumables
local consumable = false
if _set and safe_get(pool, 1, "consumeable") then
for i = 1, #pool do
if safe_get(pool, i, "set") ~= _set then
consumable = true
break
end
end
end
if _set then
if _set == "Seal" then
pool = SMODS.Seal.obj_table
set = _set
elseif G.P_CENTER_POOLS[_set] then
pool = SMODS.Center.obj_table
set = _set
end
end
for _, v in pairs(pool) do
if v.mod and G.ACTIVE_MOD_UI.id == v.mod.id and not v.no_collection then
if consumable then
if safe_get(v, "consumeable") then
obj_tally.of = obj_tally.of + 1
if cry_card_enabled(v.key) == true then
obj_tally.tally = obj_tally.tally + 1
end
end
elseif set then
if v.set and v.set == set then
obj_tally.of = obj_tally.of + 1
if cry_card_enabled(v.key) == true then
obj_tally.tally = obj_tally.tally + 1
end
end
else
obj_tally.of = obj_tally.of + 1
if cry_card_enabled(v.key) == true then
obj_tally.tally = obj_tally.tally + 1
end
end
end
end
return obj_tally
end
return t
end
-- Make non-center collections show all cards as centers
local uibk = create_UIBox_your_collection_decks
function create_UIBox_your_collection_decks()
if G.ACTIVE_MOD_UI and G.ACTIVE_MOD_UI.id == "Cryptid" then
local generic_collection_pool = {}
for k, v in pairs(SMODS.Center.obj_table) do
if v.set == "Back" and v.mod and v.mod.id == "Cryptid" then
table.insert(generic_collection_pool, v)
end
end
return SMODS.card_collection_UIBox(generic_collection_pool, { 5, 5, 5 }, {
modify_card = function(card, center, i, j)
if center.config.cry_antimatter then
card:set_edition("e_negative", true, true)
return card
end
if center.config.cry_force_edition then
card:set_edition({ [center.config.cry_force_edition] = true }, true, true)
end
if center.config.cry_force_seal then
card:set_seal(center.config.cry_force_seal, true, true)
end
if center.config.cry_force_sticker then
SMODS.Stickers[center.config.cry_force_sticker]:apply(card, true)
end
end,
})
else
return uibk()
end
end
local uitag = create_UIBox_your_collection_tags
function create_UIBox_your_collection_tags()
if G.ACTIVE_MOD_UI and G.ACTIVE_MOD_UI.id == "Cryptid" then
local generic_collection_pool = {}
for k, v in pairs(SMODS.Tag.obj_table) do
if v.set == "Tag" and v.mod and v.mod.id == "Cryptid" then
table.insert(generic_collection_pool, v)
end
end
return SMODS.card_collection_UIBox(generic_collection_pool, { 6, 6, 6, 6 }, {
card_scale = 0.42,
h_mod = 0.3,
w_mod = 0.55,
area_type = "title_2",
modify_card = function(card, center, i, j)
card.T.h = card.T.w
end,
})
else
return uitag()
end
end
local uibl = create_UIBox_your_collection_blinds
function create_UIBox_your_collection_blinds()
if G.ACTIVE_MOD_UI and G.ACTIVE_MOD_UI.id == "Cryptid" then
local generic_collection_pool = {}
for k, v in pairs(SMODS.Blind.obj_table) do
if v.set == "Blind" and v.mod and v.mod.id == "Cryptid" then
table.insert(generic_collection_pool, v)
end
end
return SMODS.card_collection_UIBox(generic_collection_pool, { 5, 5, 5, 5, 5 }, {
card_scale = 0.70,
h_mod = 0.45,
w_mod = 0.70,
area_type = "title_2",
modify_card = function(card, center, i, j)
card.T.h = card.T.w
end,
})
else
return uibl()
end
end
local uisl = create_UIBox_your_collection_seals
function create_UIBox_your_collection_seals()
if G.ACTIVE_MOD_UI and G.ACTIVE_MOD_UI.id == "Cryptid" then
return SMODS.card_collection_UIBox(G.P_CENTER_POOLS.Seal, { 5, 5 }, {
snap_back = true,
infotip = localize("ml_edition_seal_enhancement_explanation"),
hide_single_page = true,
collapse_single_page = true,
center = "c_base",
h_mod = 1.03,
modify_card = function(card, center)
card:set_seal(center.key, true)
-- Make disabled UI appear
card.config.center = cry_deep_copy(card.config.center)
card.config.center.key = center.key
end,
})
else
return uisl()
end
end
local uist = create_UIBox_your_collection_stickers
function create_UIBox_your_collection_stickers()
if G.ACTIVE_MOD_UI and G.ACTIVE_MOD_UI.id == "Cryptid" then
return SMODS.card_collection_UIBox(SMODS.Stickers, { 5, 5 }, {
snap_back = true,
hide_single_page = true,
collapse_single_page = true,
center = "c_base",
h_mod = 1.03,
back_func = "your_collection_other_gameobjects",
modify_card = function(card, center)
card.ignore_pinned = true
center:apply(card, true)
-- Make disabled UI appear
card.config.center = cry_deep_copy(card.config.center)
card.config.center.key = center.key
end,
})
else
return uist()
end
end
--hacky fix to get animated atlases visible for centers
local smai = SMODS.Atlas.inject
SMODS.Atlas.inject = function(self)
smai(self)
if self.atlas_table ~= "ASSET_ATLAS" then
G.ASSET_ATLAS[self.key_noloc or self.key] = G[self.atlas_table][self.key_noloc or self.key]
end
end