diff --git a/assets/1x/joker.png b/assets/1x/joker.png index 9d53e7f..8b9ed9f 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 cb77959..61542e7 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 80ea98e..216a66a 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 4ec4b7b..657bf5f 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 3308924..a5bcaf2 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 0f69e37..6637929 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 dc53e71..d64c206 100644 Binary files a/assets/2x/seal.png and b/assets/2x/seal.png differ diff --git a/assets/2x/spectral.png b/assets/2x/spectral.png index 84211ee..ddccc57 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 469d1cd..196c9e0 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 c20ee6d..d0f5b85 100644 Binary files a/assets/2x/tarot.png and b/assets/2x/tarot.png differ diff --git a/assets/repack.sh b/assets/repack.sh index 9aefaec..66cefa6 100755 --- a/assets/repack.sh +++ b/assets/repack.sh @@ -2,7 +2,7 @@ directory=$(dirname $(readlink -f "$0")) mkdir -p "$directory/1x/jokers" -for i in $(seq 0 25); do +for i in $(seq 0 $(find *.png | tail -n +2 | wc -l)); do files="$files $directory/1x/jokers/$i.png"; done diff --git a/localization/en-us.lua b/localization/en-us.lua index e4545bf..db34fc2 100644 --- a/localization/en-us.lua +++ b/localization/en-us.lua @@ -118,7 +118,7 @@ return { }, }, Joker = { - j_Roland_amberacorn = { + j_Roland_amber = { name = "Amber Acorn", text = {"{X:mult,C:white}X#1#{} Mult", "Moves before", "hand is played"}, }, @@ -152,7 +152,7 @@ return { "{C:inactive}(Currently {X:red,C:white}X#1#{C:inactive})", }, }, - j_Roland_coldturkey = { + j_Roland_cold = { name = "Cold Turkey", text = { "Third scored card", @@ -177,6 +177,23 @@ return { "hand {C:dark_edition}Frozen", }, }, + j_Roland_idle = { + name = "The Idle", + text = { + "Use to add card's", + "rank and suit", + "First {C:attention}scoring {}card", + "of each entry", + "gives {X:mult,C:white}X#19#{} Mult", + "{C:inactive}(Must be distinct)", + "{V:1,s:0.75}#1#{C:inactive,s:0.75}#2#{V:2,s:0.75}#3#{C:inactive,s:0.75}, " .. + "{V:3,s:0.75}#4#{C:inactive,s:0.75}#5#{V:4,s:0.75}#6#{C:inactive,s:0.75}", + "{V:5,s:0.75}#7#{C:inactive,s:0.75}#8#{V:6,s:0.75}#9#, " .. + "{V:7,s:0.75}#10#{C:inactive,s:0.75}#11#{V:8,s:0.75}#12#{C:inactive,s:0.75}", + "{V:9,s:0.75}#13#{C:inactive,s:0.75}#14#{V:10,s:0.75}#15#{C:inactive,s:0.75}, " .. + "{V:11,s:0.75}#16#{C:inactive,s:0.75}#17#{V:12,s:0.75}#18#", + }, + }, j_Roland_jokersr = { name = "Joker Sr.", text = {"{X:mult,C:white}X#1#{} Mult"}, @@ -401,12 +418,15 @@ return { c_Roland_Showdown = "Showdown", }, v_dictionary = { + b_Roland_add = "ADD", b_Roland_bye = "Bye!", + b_Roland_comma = ", ", + b_Roland_debuffed = "DEBUFFED", b_Roland_disabled = "Disabled", b_Roland_enabled = "Enabled", - b_Roland_comma = ", ", b_Roland_entering_shop = "Entering shop!", b_Roland_equinox_assist = "Assist: Only hide text (Equinox)", + b_Roland_full = "FULL", b_Roland_scribable_basket = "Scribable Basket (overpowered)", b_Roland_harsh_ante_scaling = "Harsh ante scaling (Ante 40+)", b_Roland_illusion_seal = "Allow seals from Illusion voucher", @@ -416,6 +436,7 @@ return { b_Roland_na = "N/A", b_Roland_of = " of ", b_Roland_toggle = "TOGGLE", + b_Roland_unassigned = "(Unassigned)", }, labels = { Roland_frozen = "Frozen", diff --git a/manifest.json b/manifest.json index 6bbec3b..e62d48b 100644 --- a/manifest.json +++ b/manifest.json @@ -6,7 +6,7 @@ "author": [ "Emik" ], - "version": "2.5.2", + "version": "2.5.3", "badge_colour": "8BE9FD", "main_file": "src/main.lua", "badge_text_colour": "44475A", diff --git a/src/joker.lua b/src/joker.lua index 71f2acb..798fc91 100644 --- a/src/joker.lua +++ b/src/joker.lua @@ -12,7 +12,7 @@ local joker = (function() return ret end - ---@param tbl SMODS.Joker|{artist?: string, sinis?: boolean|{x: number, y: number}, soul_pos?: boolean|{x: number, y: number}, attributes?: Attributes[]} + ---@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), sinis?: boolean|{x: number, y: number}, soul_pos?: boolean|{x: number, y: number}, attributes?: Attributes[]} return function(tbl) tbl.pos = inc() tbl.atlas = "joker" @@ -38,6 +38,37 @@ local function is_frozen(card) return card.edition and card.edition.key == "e_Roland_frozen" end +---@param card? Card|false|{suit: string, value: string} +---@param fallback? string +---@return {vars: {[number]: string|table|nil}|{colours: {[number]: {[1]: number, [2]: number, [3]: number, [4]: number}}}} +local function localize_card(card, fallback) + if not card then + return { + vars = { + "", + localize {type = "variable", key = fallback or "b_Roland_na"}, + "", + colours = {G.C.JOKER_GREY, G.C.JOKER_GREY}, + }, + } + end + + local suit = (card.base or card).suit + local value = (card.base or card).value + local name = (card.ability or card).name or "" + local no_suit = card.base and SMODS.has_no_suit(card) or not suit + local no_rank = card.base and SMODS.has_no_rank(card) or not value + + return { + vars = { + (value and not no_rank) and localize(value or 14, "ranks") or name, + (not no_rank and not no_suit) and localize {type = "variable", key = "b_Roland_of"} or "", + no_suit and "" or localize(suit, "suits_plural"), + colours = {G.C.IMPORTANT, G.C.SUITS[suit] or G.C.JOKER_GREY}, + }, + } +end + SMODS.Atlas { key = "joker", path = "joker.png", @@ -135,33 +166,7 @@ joker { blueprint_compat = true, perishable_compat = true, loc_vars = function(_, _, card) - local last = ((G.deck or {}).cards or {})[1] - - if not last or card.area ~= G.jokers then - return { - vars = { - "", - localize {type = "variable", key = "b_Roland_na"}, - "", - colours = {G.C.JOKER_GREY, G.C.JOKER_GREY}, - }, - } - end - - local suit = last.base.suit - local value = last.base.value - local name = last.ability.name or "" - local no_rank = SMODS.has_no_rank(last) - local no_suit = SMODS.has_no_suit(last) - - return { - vars = { - value and not no_rank and localize(value or 14, "ranks") or name, - not no_rank and not no_suit and localize {type = "variable", key = "b_Roland_of"} or "", - no_suit and "" or localize(suit, "suits_plural"), - colours = {G.C.IMPORTANT, G.C.SUITS[suit] or G.C.JOKER_GREY}, - }, - } + return localize_card(card.area == G.jokers and ((G.deck or {}).cards or {})[1]) end, calculate = function(_, _, context) if not context.selling_self and not context.forcetrigger then @@ -350,7 +355,7 @@ joker { } joker { - key = "coldturkey", + key = "cold", pronouns = "he_him", config = {extra = {xmult = 2}}, attributes = {"xmult"}, @@ -613,12 +618,8 @@ joker { blueprint_compat = true, perishable_compat = true, loc_vars = function(_, _, card) - return { - vars = {localize { - type = "variable", - key = card.ability.extra.flipped and "b_Roland_enabled" or "b_Roland_disabled", - }}, - } + local key = card.ability.extra.flipped and "b_Roland_enabled" or "b_Roland_disabled" + return {vars = {localize {type = "variable", key = key}}} end, inject = function(...) SMODS.Joker.inject(...) @@ -637,10 +638,7 @@ joker { 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", - } + 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) @@ -648,7 +646,7 @@ joker { } joker { - key = "amberacorn", + key = "amber", pronouns = "he_they", config = {extra = {xmult = 3}}, attributes = {"xmult"}, @@ -670,7 +668,7 @@ joker { end local keys = f(card.area.cards):where(f().nq(card)):keys():table() - local k = pseudorandom_element(keys, pseudoseed "Roland_stubborn") or card.rank + local k = pseudorandom_element(keys, pseudoseed "Roland_amber") or card.rank card.area.cards[k], card.area.cards[card.rank] = card.area.cards[card.rank], card.area.cards[k] @@ -869,3 +867,69 @@ joker { end end, } + +joker { + key = "idle", + pronouns = "they_them", + cost = 9, + rarity = 3, + Roland_idle_capacity = 6, + config = {extra = {cards = {}, xmult = 2}}, + attributes = {"rank", "suit", "xmult"}, + eternal_compat = true, + blueprint_compat = true, + perishable_compat = true, + loc_vars = function(self, _, card) + local extra = card.ability.extra + local col = {} + + ---@type { [number]: string|table|nil }|{colours: {[number]: {[1]: number, [2]: number, [3]: number, [4]: number}}} + local vars = f(self.Roland_idle_capacity):flatmap(function(v) + local l = localize_card(extra.cards[v], "b_Roland_unassigned").vars + + f(l.colours):each(function(c) + col[#col + 1] = c + end) + + l.colours = nil + return l + end):values():table() + + table.insert(vars, extra.xmult) + vars.colours = col + return {vars = vars} + end, + calculate = function(_, card, context) + return context.forcetrigger or + context.individual and + context.cardarea == G.play and + f(card.ability.extra.cards or {}):map(function(v) + return f(context.scoring_hand):any(function(x) + return x:is_suit(v.suit) and x.base.value == v.value + end) or {} + end):any(f().eq(context.other_card)) and {xmult = card.ability.extra.xmult} or nil + end, + Bakery_can_use = function(self, card) + return not card.debuff and + next(G.hand.highlighted) and + self.Roland_idle_capacity - #card.ability.extra.cards - #G.hand.highlighted >= 0 and + f(G.hand.highlighted):all(function(v) + return not SMODS.has_no_rank(v) and + not SMODS.has_no_suit(v) and + f(card.ability.extra.cards or {}):all(function(o) + return v.base.suit ~= o.suit or v.base.value ~= o.value + end) + end) + end, + Bakery_use_button_text = function(self, card) + local key = card.debuff and "b_Roland_debuffed" or + (self.Roland_idle_capacity - #card.ability.extra.cards > 0 and "b_Roland_add" or "b_Roland_full") + + return localize {type = "variable", key = key} + end, + Bakery_use_joker = function(_, card) + f(G.hand.highlighted):each(function(v) + table.insert(card.ability.extra.cards, {suit = v.base.suit, value = v.base.value}) + end) + end, +} diff --git a/src/lib/funky.lua b/src/lib/funky.lua index 7c1b901..c6f8baf 100644 --- a/src/lib/funky.lua +++ b/src/lib/funky.lua @@ -22,7 +22,7 @@ local none ---@param tbl table ---@param fpairs? fun(t: table): (fun(table: table, index?: K): K, V) ---@return fun(tbl: table, key: K): K, V ----@return K +---@return table ---@return V ---@nodiscard local function autopairs(tbl, fpairs) @@ -297,6 +297,56 @@ function f:flatmap(func, fpairs) end) end +---@generic K, V, U +---@param self F|{ [K]: V } +---@param func F|fun(v: V, k: K): { [any]: U } +---@param fpairs? fun(t: table): (fun(table: table, index?: K): K, V) +---@return F|{ [K]: U } +---@nodiscard +---@overload fun(self: F|{ [K]: V }, func: string, fpairs?: fun(t: table): (fun(table: table, index?: K): K, V)): F|{ [K]: U } +function f:flatmap(func, fpairs) + -- local i = 0 + local vt, vk, vv, vp + func = type(func) == "string" and f.index(func) or func + + return f.new(function() + if vk then + vk, vv = vp(vt, vk) + + if vk ~= nil then + -- i = i + 1 + -- return i, vv + return vk, vv + end + end + + while true do + local k, v = self:next() + + if k == nil then + return + end + + v = func(v, k) + + if type(v) ~= "table" then + -- i = i + 1 + -- return i, v + return k, v + end + + vp, vt, vk = autopairs(v, fpairs) + vk, vv = vp(vt, vk) + + if vk ~= nil then + -- i = i + 1 + -- return i, vv + return vk, vv + end + end + end) +end + ---@generic K, V ---@param self F|{ [K]: V } ---@param func F|fun(v: V, k: K): boolean