diff --git a/lovely/better_calc.toml b/lovely/better_calc.toml index 5239d5b62..fa2c08463 100644 --- a/lovely/better_calc.toml +++ b/lovely/better_calc.toml @@ -245,6 +245,13 @@ for _,k in ipairs(SMODS.Sticker.obj_buffer) do ret[v] = sticker end end +for _,k in ipairs(SMODS.CardModifiers) do + local v = k + local mod = card:calculate_modifier(context, k) + if mod then + ret[k.key] = mod + end +end -- TARGET: evaluate your own repetition effects if card.ability.repetitions and card.ability.repetitions > 0 then @@ -289,6 +296,12 @@ for _,k in ipairs(SMODS.Sticker.obj_buffer) do ret[v] = sticker end end +for _,k in pairs(SMODS.CardModifiers) do + local mod = card:calculate_modifier(context, k.key) + if mod then + ret[k.key] = mod + end +end -- TARGET: evaluate your own general effects """ diff --git a/lovely/playing_card.toml b/lovely/playing_card.toml index 4410ab9e2..79c0b8e7a 100644 --- a/lovely/playing_card.toml +++ b/lovely/playing_card.toml @@ -375,4 +375,4 @@ target = 'card.lua' pattern = '''if next(card) then''' position = 'at' match_indent = true -payload = '''if next(card) and not manual_sprites then''' +payload = '''if next(card) and not manual_sprites then''' \ No newline at end of file diff --git a/lovely/sticker.toml b/lovely/sticker.toml index f251f2cf6..f7c57afd4 100644 --- a/lovely/sticker.toml +++ b/lovely/sticker.toml @@ -17,7 +17,15 @@ for k, v in ipairs(SMODS.Sticker.obj_buffer) do if self.ability[v] and not SMODS.Stickers[v].hide_badge then badges[#badges+1] = v end -end''' +end +for i, v in pairs(SMODS.CardModifiers) do + if self.ability[v.set] and not v.hide_badge then + for _, m in pairs(self.ability[v.set]) do + if i == m.key then badges[#badges+1] = i end + end + end +end +''' # generate_card_ui() [[patches]] @@ -27,9 +35,9 @@ pattern = "if v == 'eternal' then*" match_indent = true position = "before" payload = ''' -local sticker = SMODS.Stickers[v] +local sticker = SMODS.Stickers[v] or SMODS.CardModifiers[v] if sticker then - local t = { key = v, set = 'Other' } + local t = { key = v, set = SMODS.Stickers[v] and 'Other' or sticker.set } local res = {} if sticker.loc_vars and type(sticker.loc_vars) == 'function' then res = sticker:loc_vars(info_queue, card) or {} @@ -98,7 +106,12 @@ match_indent = true payload = ''' for k, v in pairs(SMODS.Stickers) do G.BADGE_COL[k] = v.badge_colour -end''' +end + +for k, v in pairs(SMODS.CardModifiers) do + G.BADGE_COL[k] = v.badge_colour +end +''' ## Remove Pinned effect when in Sticker collections # CardArea:aling_cards diff --git a/lovely/ui.toml b/lovely/ui.toml index 5da6bd5b6..15a3ae0a4 100644 --- a/lovely/ui.toml +++ b/lovely/ui.toml @@ -490,3 +490,17 @@ self.draw_steps[#self.draw_steps+1] = { payload = ''' tilt_shadow = v.tilt_shadow, ''' + +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +match_indent = true +position = "at" +pattern = ''' +elseif _c.set == 'Joker' then +''' +payload = ''' +elseif SMODS.CardModifiers[_c.key] then + localize{type = 'descriptions', key = _c.key, set = _c.set, nodes = desc_nodes, vars = specific_vars or _c.vars} +elseif _c.set == 'Joker' then +''' diff --git a/lsp_def/classes/sticker.lua b/lsp_def/classes/sticker.lua index e83ca1fc3..d45b352b5 100644 --- a/lsp_def/classes/sticker.lua +++ b/lsp_def/classes/sticker.lua @@ -7,7 +7,7 @@ ---@field atlas? string Key to the center's atlas. ---@field pos? table|{x: integer, y: integer} Position of the center's sprite. ---@field order? number Position of the sticker in collections menu. ----@field rate? number Change of this sticker applying onto an eligible card. +---@field rate? number Chance of this sticker applying onto an eligible card. ---@field hide_badge? boolean Sets if the sticker badge shows up on the card. ---@field text_colour? table Colour of the label for the badge. ---@field badge_colour? table HEX color the sticker badge uses. diff --git a/src/card_draw.lua b/src/card_draw.lua index 492742d20..8879fe158 100644 --- a/src/card_draw.lua +++ b/src/card_draw.lua @@ -371,6 +371,31 @@ SMODS.DrawStep { conditions = { vortex = false, facing = 'front' }, } +SMODS.DrawStep { + key = 'modifiers', + order = 41, + func = function(self, layer) + for k, v in pairs(SMODS.CardModifiers) do + if self.ability[v.set] then + for i, m in pairs(self.ability[v.set]) do + if k == m.key then + if v and v.draw and type(v.draw) == 'function' then + v:draw(self, layer) + else + G.shared_stickers[k].role.draw_major = self + G.shared_stickers[k]:draw_shader('dissolve', nil, nil, nil, self.children.center) + if v.draw_shader then + G.shared_stickers[k]:draw_shader(type(v.draw_shader) == "string" and v.draw_shader or 'voucher', nil, self.ARGS.send_to_shader, nil, self.children.center) + end + end + end + end + end + end + end, + conditions = { vortex = false, facing = 'front' }, +} + SMODS.DrawStep { key = 'canvas_text', order = 45, diff --git a/src/game_object.lua b/src/game_object.lua index 9f7242eb4..3b23fc288 100644 --- a/src/game_object.lua +++ b/src/game_object.lua @@ -4001,6 +4001,11 @@ SMODS.UndiscoveredCompat = { text = '^' } + ------------------------------------------------------------------------------------------------- + ----- API CODE GameObject.CardModifiers + ------------------------------------------------------------------------------------------------- + + assert(load(SMODS.NFS.read(SMODS.path..'src/game_objects/card_modifiers.lua'), ('=[SMODS _ "src/game_objects/card_modifiers.lua"]')))() ------------------------------------------------------------------------------------------------- ----- API IMPORT GameObject.DrawStep diff --git a/src/game_objects/card_modifiers.lua b/src/game_objects/card_modifiers.lua new file mode 100644 index 000000000..152492602 --- /dev/null +++ b/src/game_objects/card_modifiers.lua @@ -0,0 +1,139 @@ +SMODS.CardModifiers = {} +SMODS.CardModifier = SMODS.GameObject:extend { + obj_table = SMODS.CardModifiers, + obj_buffer = {}, + set = 'Modifier', + required_params = { + 'key', 'set' + }, + rate = 0, + atlas = 'stickers', + pos = { x = 0, y = 0 }, + badge_colour = HEX 'FFFFFF', + default_compat = true, + compat_exceptions = {}, + sets = { Joker = true }, + needs_enable_flag = true, + process_loc_text = function(self) + G.localization.descriptions[self.set] = G.localization.descriptions[self.set] or {} + SMODS.process_loc_text(G.localization.descriptions[self.set], self.key, self.loc_txt) + SMODS.process_loc_text(G.localization.misc.labels, self.key, self.loc_txt, 'label') + end, + register = function(self) + if self.registered then + sendWarnMessage(('Detected duplicate register call on object %s'):format(self.key), self.set) + return + end + SMODS.CardModifier.super.register(self) + self.order = #self.obj_buffer + end, + inject = function(self) + self.modifier_sprite = SMODS.create_sprite(0, 0, G.CARD_W, G.CARD_H, self.atlas, self.pos) + G.shared_stickers[self.key] = self.modifier_sprite + G.P_CENTER_POOLS[self.set] = G.P_CENTER_POOLS[self.set] or {} + SMODS.insert_pool(G.P_CENTER_POOLS[self.set], self) + end, + apply = function(self, card) + card.ability[self.set] = card.ability[self.set] or {} + for i, v in pairs(card.ability[self.set]) do + if v.key == self.key then return end + end + card.ability[self.set][#card.ability[self.set]+1] = copy_table(self.config) or {} + card.ability[self.set][#card.ability[self.set]].key = self.key + if type(self.on_apply) == "function" then + self:on_apply(card) + end + if #card.ability[self.set] > SMODS.ModifierTypes[self.set].modifier_limit then + if type(SMODS.CardModifiers[card.ability[self.set][1]].on_remove) == "function" then + SMODS.CardModifiers[card.ability[self.set]]:on_remove(card) + end + table.remove(card[self.set], 1) + end + end +} + +function Card:calculate_modifier(context, key) + local mod = SMODS.CardModifiers[key] + if self.ability[mod.set] and type(mod.calculate) == 'function' then + for i, v in pairs(self.ability[mod.set]) do + if v.key == key then + local o = mod:calculate(self, context) + if o then + if not o.card then o.card = self end + return o + end + end + end + end +end + +function Card:add_modifier(modifier, bypass_check) + local modifier = SMODS.CardModifiers[modifier] + local in_sets = {} + for i, v in pairs(SMODS.ModifierTypes[modifier.set].sets or {}) do + if v == self.config.center.type then + in_sets = true + break + end + end + if bypass_check or in_sets then + modifier:apply(self, true) + SMODS.enh_cache:write(self, nil) + end +end + +function Card:remove_modifier(modifier) + local modifier = SMODS.CardModifiers[modifier] + if self.ability[modifier.set] then + local c + for i, v in pairs(self.ability[modifier.set]) do + if v == modifier.key then c = i end + end + if c then + if type(SMODS.CardModifiers[self.ability[modifier.set][c]].on_remove) == "function" then + SMODS.CardModifiers[self.ability[modifier.set][c]]:on_remove(card) + end + self.ability[modifier.set][c] = nil + SMODS.enh_cache:write(self, nil) + end + end +end + +SMODS.ModifierTypes = {} +SMODS.ModifierType = SMODS.ObjectType:extend { + obj_table = SMODS.ModifierTypes, + obj_buffer = ctype_buffer, + visible_buffer = {}, + set = 'ModifierType', + required_params = { + 'key', + }, + prefix_config = { key = false }, + collection_rows = { 6, 6 }, + register = function(self) + SMODS.ModifierType.super.register(self) + if self:check_dependencies() then + -- this is duplicate information but it's more convenient to keep + if not self.no_collection then SMODS.ModifierType.visible_buffer[#SMODS.ModifierType.visible_buffer + 1] = self.key end + end + end, + inject = function(self) + SMODS.ObjectType.inject(self) + G.localization.descriptions[self.key] = G.localization.descriptions[self.key] or {} + G.FUNCS['your_collection_' .. string.lower(self.key) .. 's'] = function(e) + G.SETTINGS.paused = true + G.FUNCS.overlay_menu { + definition = self:create_UIBox_your_collection(), + } + end + end, + process_loc_text = function(self) + SMODS.process_loc_text(G.localization.misc.dictionary, 'k_' .. string.lower(self.key), self.loc_txt, 'name') + SMODS.process_loc_text(G.localization.misc.dictionary, 'b_' .. string.lower(self.key) .. '_cards', + self.loc_txt, 'collection') + SMODS.process_loc_text(G.localization.descriptions.Other, 'undiscovered_' .. string.lower(self.key), + self.loc_txt, 'undiscovered') + end, + modifier_limit = 1, + allowed_sets = { "Enhanced", "Default" } +} \ No newline at end of file diff --git a/src/preflight/loader.lua b/src/preflight/loader.lua index d0db09977..b3dc53397 100644 --- a/src/preflight/loader.lua +++ b/src/preflight/loader.lua @@ -844,6 +844,7 @@ local function initializeModUIFunctions() }) end end + SMODS.GUI.create_modifiertype_collections() end local function checkForLoadFailure() diff --git a/src/ui.lua b/src/ui.lua index 4f5943b56..f864b8754 100644 --- a/src/ui.lua +++ b/src/ui.lua @@ -827,6 +827,19 @@ function create_UIBox_Other_GameObjects() }, } + for i, v in pairs(SMODS.ModifierTypes) do + local mods = {} + for i, m in pairs(SMODS.CardModifiers) do + if m.set == v.key then + mods[m.key] = m + end + end + smods_uibox_buttons[#smods_uibox_buttons+1] = { + count = G.ACTIVE_MOD_UI and modsCollectionTally(SMODS.PokerHands, nil, true), + button = UIBox_button({button = 'your_collection_'..(v.key:lower()), label = {localize('b_'..(v.key:lower()).."_collection")}, count = G.ACTIVE_MOD_UI and modsCollectionTally(mods, nil, true), minw = 5, id = 'your_collection_'..(v.key:lower())}) + } + end + if G.ACTIVE_MOD_UI then for _, tab in pairs(smods_uibox_buttons) do if tab.count.of > 0 then other_collections_tabs[#other_collections_tabs+1] = tab.button end @@ -3203,3 +3216,34 @@ function SMODS.GUI.create_UIBox_dropdown_menu(args, parent_width, parent) } } end + +function SMODS.GUI.create_modifiertype_collections() + for i, v in pairs(SMODS.ModifierTypes) do + G.FUNCS["your_collection_"..(v.key:lower())] = function(e) + G.SETTINGS.paused = true + G.FUNCS.overlay_menu{ + definition = _G["create_UIBox_your_collection_"..(v.key:lower())](), + } + end + _G["create_UIBox_your_collection_"..(v.key:lower())] = v.create_UIBox_your_collection or function() + local mods = {} + for i, m in pairs(SMODS.CardModifiers) do + if m.set == v.key then + mods[m.key] = m + end + end + return SMODS.card_collection_UIBox(mods, v.collection_rows or { 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) + end, + }) + end + end +end \ No newline at end of file diff --git a/src/utils.lua b/src/utils.lua index aaa957bef..6810bf420 100644 --- a/src/utils.lua +++ b/src/utils.lua @@ -3857,6 +3857,7 @@ function SMODS.get_badge_text_colour(key) if not key then return end if (SMODS.Rarities[key] or {}).text_colour then return SMODS.Rarities[key].text_colour end if (SMODS.Stickers[key] or {}).text_colour then return SMODS.Stickers[key].text_colour end + if (SMODS.CardModifiers[key] or {}).text_colour then return SMODS.CardModifiers[key].text_colour end for _, v in ipairs(G.P_CENTER_POOLS.Edition) do if v.key:sub(3) == key and v.text_colour then return v.text_colour end end