Compare commits

...

11 commits

Author SHA1 Message Date
f77dbe3ac8
Bump version 2026-03-19 19:42:23 +01:00
d219e79c89
Add dedicated Estate support 2026-03-19 19:41:49 +01:00
11120727f6
Add dev-art 2026-03-19 12:47:16 +01:00
59e9d43703
Buff new joker 2026-03-19 12:46:08 +01:00
78136a494c
Add more joker art 2026-03-19 01:38:42 +01:00
1869e60d91
Add new joker 2026-03-19 01:34:19 +01:00
286d1c6dc7
Add more joker art 2026-03-19 01:05:23 +01:00
455e08bbf7
Remove artifacts 2026-03-19 00:21:25 +01:00
87be46c360
Add more joker art 2026-03-19 00:21:06 +01:00
1bf6ac6a91
Merge branch 'main' into frozen-jokers 2026-03-18 02:38:49 +01:00
b21f20b127
Add 2 new jokers 2026-03-17 23:02:37 +01:00
13 changed files with 215 additions and 8 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 KiB

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1 KiB

After

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 41 KiB

View file

@ -126,6 +126,18 @@ return {
}, },
}, },
Joker = { Joker = {
j_Roland_arctic = {
name = "Arctic Circle",
text = {"Retrigger all", "{C:dark_edition}Frozen {}cards"},
},
j_Roland_basket = {
name = "Basket",
text = {
"Sell this Joker to",
"create {C:dark_edition}Negative {}copies",
"of every consumable",
},
},
j_Roland_bulldozer = { j_Roland_bulldozer = {
name = "Bulldozer", name = "Bulldozer",
text = { text = {
@ -169,6 +181,14 @@ return {
}, },
}, },
}, },
j_Roland_hardboiled = {
name = "Hard-Boiled",
text = {
"Sell this Joker to",
"turn all cards in",
"hand {C:dark_edition}Frozen",
},
},
j_Roland_jokersr = { j_Roland_jokersr = {
name = "Joker Sr.", name = "Joker Sr.",
text = {"{X:mult,C:white}X#1#{} Mult"}, text = {"{X:mult,C:white}X#1#{} Mult"},
@ -238,6 +258,10 @@ return {
"least {C:attention}#2# suits", "least {C:attention}#2# suits",
}, },
}, },
j_Roland_suitable = {
name = "Suitable",
text = {"{V:1}#1# {}are {C:attention}Wild", "Suit changes", "every round"},
},
j_Roland_sunny = { j_Roland_sunny = {
name = "Sunny Side Up", name = "Sunny Side Up",
text = { text = {

View file

@ -6,7 +6,7 @@
"author": [ "author": [
"Emik" "Emik"
], ],
"version": "2.1.4", "version": "2.2.0",
"badge_colour": "8BE9FD", "badge_colour": "8BE9FD",
"main_file": "src/main.lua", "main_file": "src/main.lua",
"badge_text_colour": "44475A", "badge_text_colour": "44475A",

View file

@ -16,7 +16,6 @@ local frozen_sounds = f(4):map(frozen_sound):map("key"):table()
local needs_chip_mult_override = { local needs_chip_mult_override = {
Bull = true, Bull = true,
Estate = true,
Erosion = true, Erosion = true,
Misprint = true, Misprint = true,
TierList = true, TierList = true,
@ -36,6 +35,7 @@ local current_round_overrides = {
Obelisk = "most_played_poker_hand", Obelisk = "most_played_poker_hand",
["Ancient Joker"] = "ancient_card", ["Ancient Joker"] = "ancient_card",
Wherewolf = "Bakery_Wherewolf_card", Wherewolf = "Bakery_Wherewolf_card",
j_Roland_suitable = "Roland_suitable",
} }
SMODS.current_mod.frozen_chip_mult = needs_chip_mult_override SMODS.current_mod.frozen_chip_mult = needs_chip_mult_override
@ -83,6 +83,7 @@ SMODS.Edition {
freeze(card) freeze(card)
end, end,
on_remove = function(card) on_remove = function(card)
card.Roland_frozen_estate = nil
card.Roland_frozen_ability = nil card.Roland_frozen_ability = nil
end, end,
get_weight = function(self) get_weight = function(self)
@ -155,8 +156,6 @@ function Card:calculate_joker(context, ...)
ability.Roland_frozen_mult_mod or ability.Roland_frozen_mult_mod or
ability.Roland_frozen_chip_mod or ability.Roland_frozen_chip_mod or
ability.Roland_frozen_xmult, ability.Roland_frozen_xmult,
(ability.Roland_frozen_mult_mod and ability.Roland_frozen_chip_mod) and
ability.Roland_frozen_chip_mod or nil,
}, },
}, },
} }
@ -182,6 +181,57 @@ function Card:calculate_dollar_bonus(...)
return orig_calculate_dollar_bonus(self, ...) return orig_calculate_dollar_bonus(self, ...)
end end
q(function()
local estate = G.P_CENTERS.j_Bakery_Estate
if not estate then
return
end
local function estate_pos(card)
if card.area ~= G.jokers and card.area.config.type ~= "title" then
return 1
end
card.Roland_frozen_estate = card.Roland_frozen_estate and
card.Roland_frozen_estate or
(f(card.area.cards):swap():any(function(_, k)
return k == card
end) or 1)
return card.Roland_frozen_estate
end
local orig_calculate = estate.calculate
---@param card Card|{ Roland_frozen_ability: table, Roland_frozen_estate: integer }
function estate:calculate(card, context, ...)
if not card or not card.edition or not card.edition.Roland_frozen then
return orig_calculate(self, card, context, ...)
end
if not context.joker_main then
return
end
local joker_count = estate_pos(card)
local extra = card.ability.extra or {}
return {chips = extra.chips * joker_count, mult = extra.mult * joker_count}
end
local orig_loc_vars = estate.loc_vars
function estate:loc_vars(info_queue, card, ...)
if not card or not card.edition or not card.edition.Roland_frozen then
return orig_loc_vars(self, info_queue, card, ...)
end
local joker_count = estate_pos(card)
local extra = card.ability.extra or {}
return {vars = {extra.chips * joker_count, extra.mult * joker_count}}
end
end)
q(function() q(function()
local proxy = G.P_CENTERS.j_Bakery_Proxy local proxy = G.P_CENTERS.j_Bakery_Proxy

View file

@ -31,10 +31,16 @@ 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
---@param card Card
local function is_carbon(card) local function is_carbon(card)
return card.edition and card.edition.key == "e_Bakery_Carbon" return card.edition and card.edition.key == "e_Bakery_Carbon"
end end
---@param card Card
local function is_frozen(card)
return card.edition and card.edition.key == "e_Roland_frozen"
end
local function is_mergeable_with(x) local function is_mergeable_with(x)
return function(y) return function(y)
return x.rank ~= y.rank and return x.rank ~= y.rank and
@ -242,6 +248,7 @@ joker {
joker { joker {
key = "mrsbones", key = "mrsbones",
pronouns = "she_her", pronouns = "she_her",
artist = "char",
config = {extra = {xmult = 4, requirement = 4}}, config = {extra = {xmult = 4, requirement = 4}},
cost = G.P_CENTERS.j_mr_bones.cost - 1, cost = G.P_CENTERS.j_mr_bones.cost - 1,
rarity = 2, rarity = 2,
@ -408,8 +415,9 @@ joker {
} }
joker { joker {
key = "sunny", -- Cracked egg key = "sunny",
pronouns = "they_them", pronouns = "they_them",
artist = "char",
cost = 2, cost = 2,
rarity = 1, rarity = 1,
eternal_compat = false, eternal_compat = false,
@ -466,9 +474,57 @@ joker {
end, end,
} }
joker {
key = "hardboiled",
pronouns = "they_them",
cost = 5,
rarity = 2,
eternal_compat = false,
blueprint_compat = true,
perishable_compat = true,
loc_vars = function(_, info_queue)
table.insert(info_queue, G.P_CENTERS.e_Roland_frozen)
end,
calculate = function(_, _, context)
return (context.selling_self or context.forcetrigger) and f(G.hand.cards):each(function(v)
q {
delay = 0.1,
func = function()
v:set_edition {Roland_frozen = true}
end,
}
end) or nil
end,
}
joker {
key = "basket",
pronouns = "they_them",
cost = 8,
rarity = 3,
eternal_compat = false,
blueprint_compat = true,
perishable_compat = true,
loc_vars = function(_, info_queue)
table.insert(info_queue, negative)
end,
calculate = function(_, _, context)
return (context.selling_self or context.forcetrigger) and f(G.consumeables.cards):each(function(v)
q {
delay = 1,
func = function()
play_sound "timpani"
SMODS.add_card {edition = "e_negative", key = v.config.center.key}
end,
}
end) or nil
end,
}
joker { joker {
key = "sapling", key = "sapling",
pronouns = "they_them", pronouns = "they_them",
artist = "char",
cost = 4, cost = 4,
rarity = 1, rarity = 1,
config = {extra = {mult = 15, suits = 3}}, config = {extra = {mult = 15, suits = 3}},
@ -502,8 +558,8 @@ joker {
key = "yard", key = "yard",
pronouns = "he_him", pronouns = "he_him",
config = {extra = {money = 2}}, config = {extra = {money = 2}},
cost = 6, cost = 4,
rarity = 2, rarity = 1,
eternal_compat = true, eternal_compat = true,
blueprint_compat = true, blueprint_compat = true,
perishable_compat = true, perishable_compat = true,
@ -516,9 +572,46 @@ joker {
end, end,
} }
joker {
key = "suitable",
pronouns = "she_they",
cost = 4,
rarity = 2,
eternal_compat = true,
blueprint_compat = false,
perishable_compat = true,
loc_vars = function(_, info_queue)
table.insert(info_queue, G.P_CENTERS.m_wild)
local suit = (G.GAME.current_round.Roland_suitable or {}).suit or "Spades"
return {vars = {localize(suit, "suits_plural"), colours = {G.C.SUITS[suit]}}}
end,
}
function SMODS.current_mod.reset_game_globals()
local suitable = {suit = "Spades"}
G.GAME.current_round.Roland_suitable = suitable
local suits = f(G.playing_cards):where(SMODS.has_no_suit, false):table()
local card = pseudorandom_element(suits, "Roland_suitable" .. G.GAME.round_resets.ante)
suitable.suit = card and card.base.suit or suitable.suit
end
local orig_get_enhancements = SMODS.get_enhancements
function SMODS.get_enhancements(card, ...)
if not next(SMODS.find_card "j_Roland_suitable") or
card.base.suit ~= G.GAME.current_round.Roland_suitable.suit then
return orig_get_enhancements(card, ...)
end
local ret = orig_get_enhancements(card, ...) or {}
ret.m_wild = true
return ret
end
joker { joker {
key = "misfortune", key = "misfortune",
pronouns = "she_they", pronouns = "she_they",
artist = "char",
cost = 6, cost = 6,
rarity = 2, rarity = 2,
eternal_compat = true, eternal_compat = true,
@ -594,7 +687,7 @@ joker {
return (context.joker_main or context.forcetrigger) and {card = card, xmult = self:xmult_frozen(card)} or nil return (context.joker_main or context.forcetrigger) and {card = card, xmult = self:xmult_frozen(card)} or nil
end, end,
xmult_frozen = function(self, card) xmult_frozen = function(self, card)
if not card.edition or not card.edition.Roland_frozen then if not is_frozen(card) then
return self.xmult() return self.xmult()
end end
@ -697,3 +790,29 @@ joker {
end end
end, end,
} }
joker {
key = "arctic",
pronouns = "it_its",
cost = 10,
rarity = 3,
config = {extra = {repetitions = 1}},
eternal_compat = true,
blueprint_compat = true,
perishable_compat = true,
loc_vars = function(_, info_queue)
table.insert(info_queue, G.P_CENTERS.e_Roland_frozen)
end,
calculate = function(_, card, context)
return (context.repetition and is_frozen(context.other_card)) and {repetitions = 1} or SMODS.merge_effects(
f(G.jokers.cards):where(is_frozen):map(function(v)
return SMODS.blueprint_effect(card, v, context) or true
end):where(function(v)
return type(v) == "table"
end):map(function(v)
v.colour = G.C.BLACK
return v
end):table()
)
end,
}

View file

@ -342,6 +342,20 @@ function f:values()
end) end)
end end
---@generic K, V
---@param self F|{ [K]: V }
---@return F|{ [V]: K }
---@nodiscard
function f:swap()
return f.new(function()
local k, v = self:next()
if k ~= nil then
return v, k
end
end)
end
---@generic K, V ---@generic K, V
---@param self F|{ [K]: V } ---@param self F|{ [K]: V }
---@param skip? integer ---@param skip? integer