Add new charm

This commit is contained in:
Emik 2026-02-02 15:43:46 +01:00
parent e5bd52a1a3
commit 61194ae6ed
Signed by: emik
GPG key ID: 6B0CD72A5E503BDF
8 changed files with 116 additions and 112 deletions

View file

@ -15,6 +15,10 @@ return {
}, },
}, },
Blind = { Blind = {
bl_Roland_divide = {
name = "The Great Divide",
text = {"Half of the deck", "is {C:discard}discarded"},
},
bl_Roland_improbable = { bl_Roland_improbable = {
name = "The Improbable", name = "The Improbable",
text = {"All probabilities", "cannot happen"}, text = {"All probabilities", "cannot happen"},
@ -23,10 +27,6 @@ return {
name = "The Nimble", name = "The Nimble",
text = {"The first 5 cards", "drawn are played"}, text = {"The first 5 cards", "drawn are played"},
}, },
bl_Roland_divide = {
name = "The Great Divide",
text = {"Half of the deck", "is {C:discard}discarded"},
},
bl_Roland_tranquilizer = { bl_Roland_tranquilizer = {
name = "The Tranquilizer", name = "The Tranquilizer",
text = {"#1#s are debuffed", "Changes based on", "most common rank"}, text = {"#1#s are debuffed", "Changes based on", "most common rank"},
@ -40,31 +40,26 @@ return {
j_Roland_escapey = { j_Roland_escapey = {
name = "Escapey", name = "Escapey",
text = { text = {
"Destroy {C:attention}tags{} or {C:attention}non-selected", "Use to {C:attention}destroy tags{} or {C:attention}unselected consumables",
"{C:attention}consumables{} on use. Level up", "in exchange for {C:planet}leveling up #1# random hands",
"the {C:planet}most played hand{} by {C:planet}#1#{}", "{C:inactive,s:0.75,E:1}#2#{C:red,s:1.5,E:1}#3#{s:0.9}#4#{C:blue,E:1,s:0.9}#5#{s:0.9}#6#",
"for each destroyed object",
"{C:inactive}(Currently #2#)",
" ",
"#3#{C:inactive,s:0.75,E:1}#4#{C:red,s:1.5,E:1}#5#",
"#6#{C:blue,E:1}#7#{}#8#{C:inactive,s:0.75,E:1}#9#{C:red,s:1.5,E:1}#10#",
}, },
merge = {"Since no objects apply, fuse", "with other ", " jokers"}, merge = {"Since none apply, fuse with other ", " jokers"},
quotes = { quotes = {
marble = {{"there is no escape..."}}, marble = {"there is no escape..."},
normal = { normal = {
{"I can't wait to", "work with you!"}, "I can't wait to work with you!",
{"Did you need something", "from me?"}, "Did you need something from me?",
{"Oh! I'm just so", "happy to see you!"}, "Oh! I'm just so happy to see you!",
{"Can I talk about something irrelevant?", "I promise it won't be long."}, "Can I say something irrelevant? I promise it won't be long.",
{"Can you introduce me to your friends?", "Assuming you have friends of course!"}, "Tell me about your buddies! Assuming you have them, anyway.",
}, },
scared = { scared = {
{"What am I", "going to do?!"}, "What am I going to do?!",
{"I'm not scared,", "you are!"}, "I'm not scared, you are!",
{"Tell me when", "this is over..."}, "Tell me when this is over...",
{"I can't keep", "looking at this!"}, "I can't keep looking at this!",
{"Let me go hide in", "this corner... Okay?"}, "Let me go hide in this corner... Okay?",
}, },
}, },
}, },

View file

@ -1,5 +1,5 @@
{ {
"priority": -2, "priority": 5e-324,
"id": "Roland", "id": "Roland",
"name": "Roland", "name": "Roland",
"prefix": "Roland", "prefix": "Roland",

View file

@ -35,9 +35,7 @@ SMODS.Challenge {
pronouns = "she_them", pronouns = "she_them",
} }
q { q(function()
trigger = "immediate",
func = function()
f { f {
{G.P_CENTERS, is_joker, jokerful.banned_cards}, {G.P_CENTERS, is_joker, jokerful.banned_cards},
{G.P_TAGS, is_banned_from_pastry, pastries.banned_tags}, {G.P_TAGS, is_banned_from_pastry, pastries.banned_tags},
@ -46,5 +44,4 @@ q {
}:foreach(function(v) }:foreach(function(v)
f(v[1]):filter(v[2]):foreach(adder(v[3])) f(v[1]):filter(v[2]):foreach(adder(v[3]))
end) end)
end, end)
}

19
src/charm.lua Normal file
View file

@ -0,0 +1,19 @@
local _, q = unpack(... or require "src.functional")
Bakery_API.Charm {
key = "tags",
atlas = "void",
pos = {x = 0, y = 0},
calculate = function(_, _, context)
local _ = context.skip_blind and q(function()
G.round_eval = G.round_eval and G.round_eval:remove()
G.blind_select = G.blind_select and G.blind_select:remove()
G.blind_prompt_box = G.blind_prompt_box and G.blind_prompt_box:remove()
G.GAME.current_round.jokers_purchased = 0
G.STATE = G.STATES.SHOP
G.GAME.shop_free = nil
G.GAME.shop_d6ed = nil
G.STATE_COMPLETE = false
end)
end,
}

View file

@ -1,15 +1,5 @@
local f, q, u = unpack(... or require "src.functional") local f, q, u = unpack(... or require "src.functional")
local function common_hand()
return (G.GAME or {}).current_round and f(G.GAME.hands):reduce(
{name = "High Card", order = -1 / 0, played = 0},
function(a, v, k)
return (a.played < v.played or (a.played == v.played) and (a.order > v.order)) and
{name = k, order = v.order, played = v.played} or a
end
).name or "High Card"
end
local function destructible(card) local function destructible(card)
return not card.highlighted and not (card.ability or {}).eternal return not card.highlighted and not (card.ability or {}).eternal
end end
@ -26,6 +16,35 @@ local function is_mergeable_with(it)
end end
end end
local function level_up(hand, by, card)
local function update(handname, chips, mult, level, pitch)
update_hand_text(
{sound = "button", volume = 0.7, pitch = pitch or 0.8, delay = 0.3},
{handname = handname, chips = chips, level = level, mult = mult}
)
end
if by <= 0 then
return
end
hand = hand or "NO_HAND_SPECIFIED"
local hand_obj = G.GAME.hands[hand]
if hand == "all" or hand == "allhands" or hand == "all_hands" then
update(localize "k_all_hands", "...", "...", "")
f(G.GAME.hands):keys():foreach(function(k)
level_up_hand(card, k, nil, by)
end)
elseif hand_obj then
update(localize(hand, "poker_hands"), hand_obj.chips, hand_obj.mult, hand_obj.level)
level_up_hand(card, hand, nil, by)
end
update("", 0, 0, "", 1.1)
end
SMODS.Atlas { SMODS.Atlas {
px = 71, px = 71,
py = 95, py = 95,
@ -47,7 +66,7 @@ SMODS.Joker {
pos = {x = 0, y = 0}, pos = {x = 0, y = 0},
sinis = {x = 2, y = 0}, sinis = {x = 2, y = 0},
soul_pos = {x = 1, y = 0}, soul_pos = {x = 1, y = 0},
config = {extra = {level_up_by = 1}}, config = {extra = {hands = 2}},
cost = 8, cost = 8,
rarity = 3, rarity = 3,
eternal_compat = true, eternal_compat = true,
@ -61,27 +80,23 @@ SMODS.Joker {
local quotes = loc_self.quotes local quotes = loc_self.quotes
local merge = G.jokers local merge = G.jokers
and f(G.jokers.cards):filter(is_mergeable_with(card)):any() and f(G.jokers.cards):any(is_mergeable_with(card))
and loc_self.merge or {} and loc_self.merge or {}
local normal = (merge[1] or sinister) and {} or local normal = (merge[1] or sinister) and "" or
pseudorandom_element(quotes.normal, pseudoseed "EscapeyQuotes") or {} pseudorandom_element(quotes.normal, pseudoseed "EscapeyQuotes") or ""
local scared = (merge[1] or not sinister) and {} or local scared = (merge[1] or not sinister) and "" or
pseudorandom_element(quotes.scared, pseudoseed "EscapeyQuotes") or {} pseudorandom_element(quotes.scared, pseudoseed "EscapeyQuotes") or ""
return { return {
vars = { vars = {
card.ability.extra.level_up_by, card.ability.extra.hands,
localize(common_hand(), "poker_hands"), normal,
scared,
merge[1] or "", merge[1] or "",
normal[1] or "", merge[1] and loc_self.name or "",
scared[1] or "",
merge[2] or "", merge[2] or "",
merge[3] and loc_self.name or "",
merge[3] or "",
normal[2] or "",
scared[2] or "",
}, },
} }
end, end,
@ -92,15 +107,13 @@ SMODS.Joker {
end):sub(2)) end):sub(2))
end end
end, end,
---@param card Card
Bakery_can_use = function(_, card) Bakery_can_use = function(_, card)
return not card.debuff and u() and ( return not card.debuff and u() and (
#G.GAME.tags ~= 0 or #G.GAME.tags ~= 0 or
f(G.consumeables.cards):filter(destructible):any() or f(G.consumeables.cards):any(destructible) or
f(G.jokers.cards):filter(is_mergeable_with(card)):any() f(G.jokers.cards):any(is_mergeable_with(card))
) )
end, end,
---@param card Card
Bakery_use_button_text = function(_, card) Bakery_use_button_text = function(_, card)
if card.debuff then if card.debuff then
return "DEBUFFED" return "DEBUFFED"
@ -109,7 +122,6 @@ SMODS.Joker {
return #G.GAME.tags == 0 and not f(G.consumeables.cards):filter(destructible):any() and return #G.GAME.tags == 0 and not f(G.consumeables.cards):filter(destructible):any() and
f(G.jokers.cards):filter(is_mergeable_with(card)):any() and "FUSE" or "ESCAPE" f(G.jokers.cards):filter(is_mergeable_with(card)):any() and "FUSE" or "ESCAPE"
end, end,
---@param card Card
Bakery_use_joker = function(_, card) Bakery_use_joker = function(_, card)
if card.debuff then if card.debuff then
return return
@ -125,34 +137,19 @@ SMODS.Joker {
f(G.jokers.cards):filter(is_mergeable_with(card)):foreach(function(v) f(G.jokers.cards):filter(is_mergeable_with(card)):foreach(function(v)
any_carbon = any_carbon or is_carbon(v) any_carbon = any_carbon or is_carbon(v)
level_sum = level_sum + v.ability.extra.level_up_by * (v.getEvalQty and v:getEvalQty() or 1) level_sum = level_sum + v.ability.extra.hands * (v.getEvalQty and v:getEvalQty() or 1)
sell_sum = sell_sum + v.sell_cost * (v.getEvalQty and v:getEvalQty() or 1) sell_sum = sell_sum + v.sell_cost * (v.getEvalQty and v:getEvalQty() or 1)
v:start_dissolve({HEX "57ecab"}, nil, 1.6) v:start_dissolve({HEX "57ecab"}, nil, 1.6)
end) end)
if not any_carbon then if not any_carbon then
card.ability.extra.level_up_by = card.ability.extra.level_up_by + level_sum card.ability.extra.hands = card.ability.extra.hands + level_sum
end end
card.sell_cost = card.sell_cost + sell_sum card.sell_cost = card.sell_cost + sell_sum
return return
end end
local function update(name, chip, mul, lv, notif, snd, vol, pit, de)
update_hand_text({
sound = type(snd) == "string" and snd or type(snd) == "nil" and "button",
volume = vol or 0.7,
pitch = pit or 0.8,
delay = de or 0.3,
}, {
handname = name or "????",
chips = chip or "?",
level = lv or "?",
mult = mul or "?",
StatusText = notif,
})
end
local function fast_delete(v) local function fast_delete(v)
return function() return function()
attention_text { attention_text {
@ -171,19 +168,6 @@ SMODS.Joker {
end end
end end
local hand = common_hand()
if hand == "all" or hand == "allhands" or hand == "all_hands" then
update(localize "k_all_hands", "...", "...", "")
elseif G.GAME.hands[hand or "NO_HAND_SPECIFIED"] then
update(
localize(hand, "poker_hands"),
G.GAME.hands[hand].chips,
G.GAME.hands[hand].mult,
G.GAME.hands[hand].level
)
end
local destroyed = 0 local destroyed = 0
if consumable_count == 0 then if consumable_count == 0 then
@ -207,12 +191,17 @@ SMODS.Joker {
end) end)
end end
level_up_hand(card, hand, nil, destroyed * card.ability.extra.level_up_by) local hands = f(G.GAME.hands):filter(function(v, _)
return v.visible
end):keys():into()
update_hand_text( pseudoshuffle(hands, pseudoseed "RolandEscapey")
{sound = "button", volume = 0.7, pitch = 1.1, delay = 0}, local levels = destroyed * card.ability.extra.hands
{mult = 0, chips = 0, handname = "", level = ""} level_up("all", math.floor(levels / #hands), card)
)
f(hands):take(levels % #hands):foreach(function(v)
level_up(v, 1, card)
end)
end, end,
} }
@ -317,12 +306,16 @@ SMODS.Joker {
atlas = "void", atlas = "void",
pronouns = "they_them", pronouns = "they_them",
pos = {x = 0, y = 0}, pos = {x = 0, y = 0},
config = {extra = {money = 2}},
cost = 3, cost = 3,
rarity = 1, rarity = 1,
calculate = function(_, _, context) loc_vars = function(_, _, card)
return context.repetition and return {vars = {card.ability.extra.money}}
context.cardarea == G.play and end,
context.scoring_name == "Four of a Kind" and {repetitions = 1} or nil calculate = function(_, card, context)
return context.joker_main and
context.scoring_name == "Four of a Kind" and
{dollars = card.ability.extra.money} or nil
end, end,
} }

View file

@ -1,6 +1,6 @@
local qol = assert(SMODS.load_file "src/functional.lua")() or require "src.functional" local qol = assert(SMODS.load_file "src/functional.lua")() or require "src.functional"
qol[1] {"challenge", "spectral", "blind", "joker", "back", "seal"}:foreach(function(v) qol[1] {"challenge", "spectral", "blind", "charm", "joker", "back", "seal"}:foreach(function(v)
assert(SMODS.load_file("src/" .. v .. ".lua"))(qol) assert(SMODS.load_file("src/" .. v .. ".lua"))(qol)
end) end)

View file

@ -70,7 +70,7 @@ SMODS.Consumable {
end, end,
use = function(_, card, _) use = function(_, card, _)
local cards = f(G.hand.cards, ipairs):into() local cards = f(G.hand.cards, ipairs):into()
pseudoshuffle(cards, pseudoseed "Roland_two") pseudoshuffle(cards, pseudoseed "RolandDual")
f(cards):take(card.ability.extra.amount):foreach(function(v) f(cards):take(card.ability.extra.amount):foreach(function(v)
v:set_seal(SMODS.poll_seal {guaranteed = true}) v:set_seal(SMODS.poll_seal {guaranteed = true})

View file

@ -174,7 +174,7 @@ Balatest.TestPlay {
assert = function() assert = function()
Balatest.assert_eq(#G.jokers.cards, 1) Balatest.assert_eq(#G.jokers.cards, 1)
Balatest.assert_eq(G.jokers.cards[1].sell_cost, 8) Balatest.assert_eq(G.jokers.cards[1].sell_cost, 8)
Balatest.assert_eq(G.jokers.cards[1].ability.extra.level_up_by, 2) Balatest.assert_eq(G.jokers.cards[1].ability.extra.levels, 2)
end, end,
} }
@ -237,7 +237,7 @@ Balatest.TestPlay {
assert = function() assert = function()
Balatest.assert_eq(#G.jokers.cards, 1) Balatest.assert_eq(#G.jokers.cards, 1)
Balatest.assert_eq(G.jokers.cards[1].sell_cost, 8) Balatest.assert_eq(G.jokers.cards[1].sell_cost, 8)
Balatest.assert_eq(G.jokers.cards[1].ability.extra.level_up_by, 2) Balatest.assert_eq(G.jokers.cards[1].ability.extra.levels, 2)
end, end,
} }
@ -279,7 +279,7 @@ Balatest.TestPlay {
Balatest.assert_eq(#G.jokers.cards, 1) Balatest.assert_eq(#G.jokers.cards, 1)
Balatest.assert_eq(G.jokers.cards[1].sell_cost, 8) Balatest.assert_eq(G.jokers.cards[1].sell_cost, 8)
Balatest.assert_eq(G.jokers.cards[1].ability.extra.level_up_by, 1) Balatest.assert_eq(G.jokers.cards[1].ability.extra.levels, 1)
end, end,
} }
@ -322,7 +322,7 @@ Balatest.TestPlay {
Balatest.assert_eq(#G.jokers.cards, 1) Balatest.assert_eq(#G.jokers.cards, 1)
Balatest.assert_eq(G.jokers.cards[1].sell_cost, 8) Balatest.assert_eq(G.jokers.cards[1].sell_cost, 8)
Balatest.assert_eq(G.jokers.cards[1].ability.extra.level_up_by, 1) Balatest.assert_eq(G.jokers.cards[1].ability.extra.levels, 1)
end, end,
} }