diff --git a/assets/1x/joker.png b/assets/1x/joker.png index 84252a2..1263964 100644 Binary files a/assets/1x/joker.png and b/assets/1x/joker.png differ diff --git a/assets/2x/back.png b/assets/2x/back.png index 36c1165..604dac7 100644 Binary files a/assets/2x/back.png and b/assets/2x/back.png differ diff --git a/assets/2x/blind.png b/assets/2x/blind.png index f184097..693fc38 100644 Binary files a/assets/2x/blind.png and b/assets/2x/blind.png differ diff --git a/assets/2x/charm.png b/assets/2x/charm.png index 76d5b25..0246329 100644 Binary files a/assets/2x/charm.png and b/assets/2x/charm.png differ diff --git a/assets/2x/icon.png b/assets/2x/icon.png index 9efb323..49c175d 100644 Binary files a/assets/2x/icon.png and b/assets/2x/icon.png differ diff --git a/assets/2x/joker.png b/assets/2x/joker.png index 3f504a4..f417e12 100644 Binary files a/assets/2x/joker.png and b/assets/2x/joker.png differ diff --git a/assets/2x/seal.png b/assets/2x/seal.png index 5c9facd..d8e8f34 100644 Binary files a/assets/2x/seal.png and b/assets/2x/seal.png differ diff --git a/assets/2x/sleeve.png b/assets/2x/sleeve.png index 916e354..6158c5b 100644 Binary files a/assets/2x/sleeve.png and b/assets/2x/sleeve.png differ diff --git a/assets/2x/spectral.png b/assets/2x/spectral.png index 59e726b..c7fdbba 100644 Binary files a/assets/2x/spectral.png and b/assets/2x/spectral.png differ diff --git a/assets/2x/tag.png b/assets/2x/tag.png index 5363154..7ea1360 100644 Binary files a/assets/2x/tag.png and b/assets/2x/tag.png differ diff --git a/assets/2x/tarot.png b/assets/2x/tarot.png index e0738d0..97db883 100644 Binary files a/assets/2x/tarot.png and b/assets/2x/tarot.png differ diff --git a/assets/2x/unicon.png b/assets/2x/unicon.png index ecce61d..0d1acfc 100644 Binary files a/assets/2x/unicon.png and b/assets/2x/unicon.png differ diff --git a/localization/en-us.lua b/localization/en-us.lua index 1755766..5592c02 100644 --- a/localization/en-us.lua +++ b/localization/en-us.lua @@ -355,6 +355,18 @@ return { "{C:attention}#2# {}scored cards", }, }, + j_Roland_violet = { + name = "Violet Vessel", + text = { + "{X:mult,C:white}X#1#{} Mult,", + "but {X:mult,C:white}X#2#{} Mult", + "{C:attention}before {}scoring", + }, + }, + j_Roland_venerable = { + name = "Venerable Visage", + text = {"{X:red,C:white}X#1#{} discards each round"}, + }, j_Roland_yard = { name = "Yard Sale", text = { diff --git a/manifest.json b/manifest.json index 198d724..17af693 100644 --- a/manifest.json +++ b/manifest.json @@ -3,7 +3,7 @@ "id": "Roland", "name": "Roland", "prefix": "Roland", - "version": "2.8.36", + "version": "2.9.0", "badge_colour": "8BE9FD", "display_name": "Roland", "main_file": "src/main.lua", diff --git a/src/blind.lua b/src/blind.lua index cc056c8..2abeb84 100644 --- a/src/blind.lua +++ b/src/blind.lua @@ -3,14 +3,20 @@ local f, q = unpack(... or require "lib.shared") local blind = (function() local y = 0 - ---@param tbl SMODS.Blind + ---@param tbl SMODS.Blind|{idea?: string} ---@return SMODS.Blind return function(tbl) tbl.pos = {x = 0, y = y} tbl.atlas = "blind" - local ret = SMODS.Blind(tbl) + tbl.idea = tbl.idea and "Roland_" .. tbl.idea or nil + local blind = SMODS.Blind(tbl) y = y + 1 - return ret + + q(function() + Bakery_API.credit(blind) + end) + + return blind end end)() @@ -237,6 +243,7 @@ blind { blind { key = "blizzard", + idea = "redstoad", boss = {min = 3}, boss_colour = HEX "102a41ff", pronouns = "it_its", diff --git a/src/joker.lua b/src/joker.lua index f3c7364..d004479 100644 --- a/src/joker.lua +++ b/src/joker.lua @@ -22,10 +22,11 @@ local joker = (function() return ret end - ---@param tbl SMODS.Joker|{artist?: string, Bakery_can_use: (fun(self: self, card: Card): boolean?), Bakery_use_button_text: (fun(self: self, card: Card): string|table|nil), Bakery_use_joker: fun(self: self, card: Card), attributes?: Attributes[]} + ---@param tbl SMODS.Joker|{artist?: string, idea?: string, Bakery_can_use: (fun(self: self, card: Card): boolean?), Bakery_use_button_text: (fun(self: self, card: Card): string|table|nil), Bakery_use_joker: fun(self: self, card: Card), attributes?: Attributes[]} return function(tbl) tbl.pos = inc() tbl.atlas = "joker" + tbl.idea = tbl.idea and "Roland_" .. tbl.idea or nil tbl.artist = tbl.artist and "Roland_" .. tbl.artist or nil if ((tbl.config or {}).extra or {}).flipped ~= nil then @@ -38,6 +39,8 @@ local joker = (function() q(function() Bakery_API.credit(joker) end) + + return joker end end)() @@ -161,6 +164,7 @@ joker { key = "mrsbones", pronouns = "she_her", artist = "ghostlyfield", + idea = "redstoad", config = {extra = {xmult = 4, requirement = 4}}, attributes = {"xmult"}, cost = G.P_CENTERS.j_mr_bones.cost - 1, @@ -197,6 +201,7 @@ joker { key = "sunny", pronouns = "it_its", artist = "char", + idea = "redstoad", attributes = {"food", "on_sell"}, cost = 2, rarity = 1, @@ -510,6 +515,7 @@ joker { key = "sapling", pronouns = "they_them", artist = "char", + idea = "redstoad", attributes = {"mult", "suit"}, cost = 4, rarity = 1, @@ -580,103 +586,6 @@ joker { end, } -joker { - key = "bulldozer", - pronouns = "she_her", - attributes = {"xmult"}, - cost = 6, - rarity = 2, - eternal_compat = true, - blueprint_compat = true, - perishable_compat = true, - loc_vars = function(self, _, card) - return {vars = {self:xmult_frozen(card)}} - end, - calculate = function(self, card, context) - return (context.joker_main or context.forcetrigger) and {card = card, xmult = self:xmult_frozen(card)} or nil - end, - xmult_frozen = function(self, card) - if not is_frozen(card) then - return self.xmult() - end - - local ability = card.Roland_frozen_ability or {} - card.Roland_frozen_ability = ability - ability.Roland_frozen_xmult = ability.Roland_frozen_xmult or self.xmult() - return ability.Roland_frozen_xmult - end, - xmult = function() - local function mult(id) - local next = {Select = true, Upcoming = true} - local states = G.GAME.round_resets.blind_states - local choices = G.GAME.round_resets.blind_choices - return next[states[id]] and G.P_BLINDS[choices[id]].mult - end - - local m = ((G.GAME or {}).blind or {}).mult - return m and m ~= 0 and m or mult "Small" or mult "Big" or mult "Boss" or 1 - end, -} - -joker { - key = "phytoestrogens", - pronouns = "she_her", - artist = "ghostlyfield", - config = {extra = {xmult = 0.3}}, - attributes = {"mult", "xmult"}, - cost = 8, - rarity = 3, - eternal_compat = true, - blueprint_compat = true, - perishable_compat = true, - loc_vars = function(_, _, card) - return {vars = {card.ability.extra.xmult}} - end, - calculate = function(_, card, context) - if not context.joker_main and not context.forcetrigger then - return - end - - SMODS.calculate_effect({mult = hand_chips}, card) - SMODS.calculate_effect({xmult = card.ability.extra.xmult}, card) - end, -} - -joker { - key = "nilly", - pronouns = "any_all", - artist = "ghostlyfield", - config = {extra = {flipped = false}}, - attributes = {"xmult", "bakery_double_sided"}, - cost = 0, - rarity = 2, - eternal_compat = true, - blueprint_compat = true, - perishable_compat = true, - loc_vars = function(_, _, card) - local key = card.ability.extra.flipped and "b_Roland_enabled" or "b_Roland_disabled" - return {vars = {localize {type = "variable", key = key}}} - end, - calculate = function(_, card, context) - if (not context.joker_main or not card.ability.extra.flipped) and not context.forcetrigger then - return - end - - mult = mod_mult(0) - update_hand_text({delay = 0}, {chips = hand_chips, mult = mult}) - return {sound = "Roland_nilly", message = "0X " .. localize "k_mult", colour = G.C.MULT, message_card = card} - end, - Bakery_can_use = function(_, card) - return not card.debuff - end, - Bakery_use_button_text = function(_, card) - return localize {type = "variable", key = card.debuff and "b_Roland_debuffed" or "b_Roland_toggle"} - end, - Bakery_use_joker = function(_, card) - local _ = card.debuff or Bakery_API.flip_double_sided(card) - end, -} - joker { key = "amber", pronouns = "they_them", @@ -731,7 +640,7 @@ joker { pixel_size = {w = 68, h = 68}, attributes = {"xmult"}, cost = 6, - rarity = 2, + rarity = 3, eternal_compat = true, blueprint_compat = true, perishable_compat = true, @@ -852,9 +761,163 @@ function CardArea:unhighlight_all(...) return orig_unhighlight_all(self, ...) end +joker { + key = "violet", + pronouns = "she_they", + idea = "hamester", + config = {extra = {before = 1 / 3, xmult = 9}}, + pixel_size = {w = 68, h = 68}, + attributes = {"xmult"}, + cost = 6, + rarity = 3, + eternal_compat = true, + blueprint_compat = true, + perishable_compat = true, + loc_vars = function(_, _, card) + local extra = card.ability.extra + return {vars = {extra.xmult, extra.before}} + end, + calculate = function(_, card, context) + local extra = card.ability.extra + + return (context.joker_main or context.forcetrigger) and + {card = card, xmult = extra.xmult} or + (context.before and {card = card, xmult = extra.before} or nil) + end, +} + +joker { + key = "venerable", + pronouns = "any_all", + config = {extra = {xdiscard = 3}}, + pixel_size = {w = 68, h = 68}, + attributes = {"discard", "passive"}, + cost = 6, + rarity = 3, + eternal_compat = true, + blueprint_compat = false, + perishable_compat = true, + loc_vars = function(_, _, card) + local extra = card.ability.extra + return {vars = {extra.xdiscard}} + end, + add_to_deck = function(self, card) + self:venerable(math.ceil(G.GAME.round_resets.discards * card.ability.extra.xdiscard)) + end, + remove_from_deck = function(self, card) + self:venerable(math.floor(G.GAME.round_resets.discards / card.ability.extra.xdiscard)) + end, + venerable = function(_, amount) + local round_resets = G.GAME.round_resets + local discards = round_resets.discards + round_resets.discards = amount + ease_discard(round_resets.discards - discards) + end, +} + +joker { + key = "bulldozer", + pronouns = "she_her", + idea = "redstoad", + attributes = {"xmult"}, + cost = 6, + rarity = 2, + eternal_compat = true, + blueprint_compat = true, + perishable_compat = true, + loc_vars = function(self, _, card) + return {vars = {self:xmult_frozen(card)}} + end, + calculate = function(self, card, context) + return (context.joker_main or context.forcetrigger) and {card = card, xmult = self:xmult_frozen(card)} or nil + end, + xmult_frozen = function(self, card) + if not is_frozen(card) then + return self.xmult() + end + + local ability = card.Roland_frozen_ability or {} + card.Roland_frozen_ability = ability + ability.Roland_frozen_xmult = ability.Roland_frozen_xmult or self.xmult() + return ability.Roland_frozen_xmult + end, + xmult = function() + local function mult(id) + local next = {Select = true, Upcoming = true} + local states = G.GAME.round_resets.blind_states + local choices = G.GAME.round_resets.blind_choices + return next[states[id]] and G.P_BLINDS[choices[id]].mult + end + + local m = ((G.GAME or {}).blind or {}).mult + return m and m ~= 0 and m or mult "Small" or mult "Big" or mult "Boss" or 1 + end, +} + +joker { + key = "phytoestrogens", + pronouns = "she_her", + artist = "ghostlyfield", + config = {extra = {xmult = 0.3}}, + attributes = {"mult", "xmult"}, + cost = 8, + rarity = 3, + eternal_compat = true, + blueprint_compat = true, + perishable_compat = true, + loc_vars = function(_, _, card) + return {vars = {card.ability.extra.xmult}} + end, + calculate = function(_, card, context) + if not context.joker_main and not context.forcetrigger then + return + end + + SMODS.calculate_effect({mult = hand_chips}, card) + SMODS.calculate_effect({xmult = card.ability.extra.xmult}, card) + end, +} + +joker { + key = "nilly", + pronouns = "any_all", + artist = "ghostlyfield", + idea = "redstoad", + config = {extra = {flipped = false}}, + attributes = {"xmult", "bakery_double_sided"}, + cost = 0, + rarity = 2, + eternal_compat = true, + blueprint_compat = true, + perishable_compat = true, + loc_vars = function(_, _, card) + local key = card.ability.extra.flipped and "b_Roland_enabled" or "b_Roland_disabled" + return {vars = {localize {type = "variable", key = key}}} + end, + calculate = function(_, card, context) + if (not context.joker_main or not card.ability.extra.flipped) and not context.forcetrigger then + return + end + + mult = mod_mult(0) + update_hand_text({delay = 0}, {chips = hand_chips, mult = mult}) + return {sound = "Roland_nilly", message = "0X " .. localize "k_mult", colour = G.C.MULT, message_card = card} + end, + Bakery_can_use = function(_, card) + return not card.debuff + end, + Bakery_use_button_text = function(_, card) + return localize {type = "variable", key = card.debuff and "b_Roland_debuffed" or "b_Roland_toggle"} + end, + Bakery_use_joker = function(_, card) + local _ = card.debuff or Bakery_API.flip_double_sided(card) + end, +} + joker { key = "martingale", pronouns = "he_him", + idea = "redstoad", config = {extra = {odds = 2}}, attributes = {"xmult", "chance"}, cost = 8, @@ -1033,6 +1096,8 @@ end joker { key = "artemis", pronouns = "any_all", + artist = "hamester", + idea = "redstoad", cost = 6, rarity = 2, config = {extra = { @@ -1097,6 +1162,7 @@ joker { joker { key = "excalibur", pronouns = "he_him", + idea = "redstoad", cost = 8, rarity = 3, config = {extra = { diff --git a/src/lib/shared.lua b/src/lib/shared.lua index c08d7a4..be26c43 100644 --- a/src/lib/shared.lua +++ b/src/lib/shared.lua @@ -6,31 +6,19 @@ local function protect(fun) sendErrorMessage(tostring(ret), "Roland") end - return not res or ret ~= false + return not res or ret ~= false and not (SMODS.current_mod and ret ~= true) end end -local function protect_ev(fun, retries) - if type(fun) == "function" and retries then - local orig_fun = fun - - fun = function(...) - local ret = orig_fun(...) - - if ret == true then - retries = retries - 1 - return retries <= 0 - else - return ret - end - end - end +local function protect_ev(fun) + local no_delete = not not SMODS.current_mod if type(fun) == "table" then fun.func = protect(fun.func) + fun.no_delete = no_delete fun = getmetatable(fun) == Event and fun or Event(fun) elseif type(fun) == "function" then - fun = Event {func = protect(fun)} + fun = Event {func = protect(fun), no_delete = no_delete} else error("Expected a function or event, got a " .. type(fun), 3) end @@ -89,11 +77,12 @@ end local f = assert(SMODS.load_file "src/lib/funky.lua")() or require "lib.funky" --- Queues an event to be run. ---- Note that events added this way implicitly `return true` unless you explicitly `return false`, unlike the vanilla ones. ---- @param fun (fun():boolean?)|Event The event or a function to run turn into an event. ---- @param front? boolean `true` to add the event to the front of the queue, rather than the end. -local function q(fun, front) - G.E_MANAGER:add_event(protect_ev(fun, SMODS.current_mod and 100), nil, front) +--- Note that events added this way implicitly `return true` unless you explicitly `return false`. +--- For `front`; boolean `true` to add the event to the front of the queue, rather than the end. +--- @param fun fun():boolean?|{front?: boolean}|Event The event or a function to run turn into an event. +local function q(fun) + local ev = protect_ev(fun) + G.E_MANAGER:add_event(ev, nil, ev.front) end --- Determines if a center is allowed to be usable. diff --git a/src/main.lua b/src/main.lua index 09206e3..1c93a09 100644 --- a/src/main.lua +++ b/src/main.lua @@ -1,17 +1,6 @@ local qol = assert(SMODS.load_file "src/lib/shared.lua")() or require "lib.shared" local f, q = unpack(qol) -f {"challenge", "spectral", "edition", "tweaks", "blind", "charm", "joker", "tarot", "back", "seal", "tag"} - :each(function(v) - assert(SMODS.load_file("src/" .. v .. ".lua"))(qol) - end) - -if _G["Balatest"] then - f {"joker", "blind", "spectral"}:each(function(v) - assert(SMODS.load_file("src/tests/" .. v .. ".tests.lua"))(qol) - end) -end - q(function() local contributors = (Bakery_API or {}).contributors @@ -20,7 +9,7 @@ q(function() end -- Special shoutout to all contributors. <3 - f { + local credits = { aster = { name = "asterSSH", fg = HEX "f8f8f2ff", @@ -41,14 +30,37 @@ q(function() fg = HEX "ffffffff", bg = HEX "b290e6ff", }, - }:each(function(v, k) + hamester = { + name = "Hamester", + fg = HEX "ffffffff", + bg = HEX "ffa100ff", + }, + redstoad = { + name = "RedsToad", + fg = HEX "ffffffff", + bg = HEX "da4044ff", + }, + } + + f(credits):each(function(v, k) contributors["Roland_" .. k] = v end) if SMODS.Mods.DebugPlus and SMODS.Mods.Roland.config.import_funky then _G.f, _G.q, _G.u = unpack(qol) end -end, true) +end) + +f {"challenge", "spectral", "edition", "tweaks", "blind", "charm", "joker", "tarot", "back", "seal", "tag"} + :each(function(v) + assert(SMODS.load_file("src/" .. v .. ".lua"))(qol) + end) + +if _G["Balatest"] then + f {"joker", "blind", "spectral"}:each(function(v) + assert(SMODS.load_file("src/tests/" .. v .. ".tests.lua"))(qol) + end) +end local function toggle(id) return create_toggle { @@ -71,8 +83,6 @@ SMODS.Atlas { atlas_table = animated and "ANIMATION_ATLAS" or "ASSET_ATLAS", } -SMODS.current_mod.qol = qol - function SMODS.current_mod.config_tab() return { n = G.UIT.ROOT, @@ -93,3 +103,5 @@ function SMODS.current_mod.config_tab() }}, } end + +SMODS.current_mod.qol = qol diff --git a/src/spectral.lua b/src/spectral.lua index f570cf6..31e74d3 100644 --- a/src/spectral.lua +++ b/src/spectral.lua @@ -11,14 +11,14 @@ local spectral = (function() tbl.atlas = "spectral" tbl.pos = {x = x, y = 0} tbl.artist = tbl.artist and "Roland_" .. tbl.artist or nil - local ret = SMODS.Consumable(tbl) + local spectral = SMODS.Consumable(tbl) x = x + 1 q(function() - Bakery_API.credit(ret) + Bakery_API.credit(spectral) end) - return ret + return spectral end end)()