Roland/src/joker.lua

922 lines
29 KiB
Lua

local f, q = unpack(... or require "lib.shared")
local negative = {key = "e_negative_consumable", set = "Edition", config = {extra = 1}}
local joker = (function()
local z = 0
---@return {x: number, y: number}
local function inc()
local ret = {x = z % 6, y = math.floor(z / 6)}
z = z + 1
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), sinis?: boolean|{x: number, y: number}, soul_pos?: boolean|{x: number, y: number}, attributes?: Attributes[]}
return function(tbl)
tbl.pos = inc()
tbl.atlas = "joker"
tbl.artist = tbl.artist and "Roland_" .. tbl.artist or nil
tbl.soul_pos = tbl.soul_pos and inc() or nil
tbl.sinis = tbl.sinis and inc() or nil
if ((tbl.config or {}).extra or {}).flipped ~= nil then
tbl.config.extra.front_pos = tbl.pos
tbl.config.extra.back_pos = inc()
end
local joker = SMODS.Joker(tbl)
q(function()
Bakery_API.credit(joker)
end)
end
end)()
---@param card Card
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",
px = 71,
py = 95,
}
SMODS.Sound {
key = "nilly",
path = "nilly.ogg",
}
joker {
key = "msjoker",
pronouns = "she_her",
cost = 1,
rarity = 1,
eternal_compat = true,
blueprint_compat = true,
perishable_compat = true,
config = {extra = {chips = 30}},
attributes = {"chips"},
loc_vars = function(_, _, card)
return {vars = {card.ability.extra.chips}}
end,
calculate = function(_, card, context)
return (context.joker_main or context.forcetrigger) and
{card = card, chips = card.ability.extra.chips} or nil
end,
}
joker {
key = "jokersr",
pronouns = "he_him",
config = {extra = {xmult = 1.25}},
attributes = {"xmult"},
cost = 2,
rarity = 2,
eternal_compat = true,
blueprint_compat = true,
perishable_compat = true,
loc_vars = function(_, _, card)
return {vars = {card.ability.extra.xmult}}
end,
calculate = function(_, card, context)
return (context.joker_main or context.forcetrigger) and
{card = card, xmult = card.ability.extra.xmult} or nil
end,
}
joker {
key = "mrsbones",
pronouns = "she_her",
artist = "char",
config = {extra = {xmult = 4, requirement = 4}},
attributes = {"xmult"},
cost = G.P_CENTERS.j_mr_bones.cost - 1,
rarity = 2,
eternal_compat = false,
blueprint_compat = true,
perishable_compat = true,
loc_vars = function(_, _, card)
return {vars = {card.ability.extra.xmult, card.ability.extra.requirement * 100}}
end,
calculate = function(_, card, context)
if context.joker_main or context.forcetrigger then
return {card = card, xmult = card.ability.extra.xmult}
end
if not card.getting_sliced and
context.end_of_round and
G.GAME.chips / card.ability.extra.requirement < G.GAME.blind.chips then
card.getting_sliced = true
local message = localize {type = "variable", key = "b_Roland_bye"}
SMODS.calculate_effect({message = message, colour = G.C.RED, message_card = card}, card)
q(function()
G.hand_text_area.blind_chips:juice_up()
G.hand_text_area.game_chips:juice_up()
card:start_dissolve()
play_sound "tarot1"
end)
end
end,
}
joker {
key = "sunny",
pronouns = "they_them",
artist = "char",
attributes = {"food", "on_sell"},
cost = 2,
rarity = 1,
eternal_compat = false,
blueprint_compat = true,
perishable_compat = true,
loc_vars = function(_, _, card)
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
return
end
draw_card(G.deck, G.hand, 100, "up", false, G.deck.cards[1])
local current_round = G.GAME.current_round
local facing_blind = G.GAME.facing_blind
SMODS.calculate_context {drawing_cards = true, draw = {G.deck.cards}}
SMODS.calculate_context {
first_hand_drawn = not current_round.any_hand_drawn and facing_blind or nil,
hand_drawn = facing_blind and {G.deck.cards[1]} --[[@as true]],
other_drawn = not facing_blind and {G.deck.cards[1]},
}
if type(facing_blind) == "table" then
facing_blind.any_hand_drawn = facing_blind.any_hand_drawn or facing_blind
end
end,
}
joker {
key = "hardboiled",
pronouns = "they_them",
attributes = {"food", "editions", "modify_card", "on_sell"},
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",
attributes = {"food", "generation", "on_sell"},
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 {
key = "monomino",
pronouns = "it_its",
artist = "char",
config = {extra = {price = 4, hand_name = "Four of a Kind"}},
attributes = {"sell_value", "scaling", "economy", "hand_type"},
cost = 4,
rarity = 1,
eternal_compat = true,
blueprint_compat = true,
perishable_compat = true,
loc_vars = function(_, _, card)
local extra = card.ability.extra
return {vars = {extra.price, localize(extra.hand_name, "poker_hands")}}
end,
calculate = function(_, card, context)
local extra = card.ability.extra
if (not context.before or context.scoring_name ~= extra.hand_name) and not context.forcetrigger then
return
end
local c = context.blueprint_card or card
c.ability.extra_value = c.ability.extra_value + extra.price
c:set_cost()
return {message = localize "k_val_up", colour = G.C.MONEY, message_card = card}
end,
}
joker {
key = "domino",
pronouns = "it_its",
artist = "char",
config = {extra = {mult_gain = 4, hand_name = "Four of a Kind", mult = 0}},
attributes = {"mult", "scaling", "hand_type"},
cost = 4,
rarity = 2,
eternal_compat = true,
blueprint_compat = true,
perishable_compat = false,
loc_vars = function(_, _, card)
local extra = card.ability.extra
return {vars = {extra.mult_gain, localize(extra.hand_name, "poker_hands"), extra.mult}}
end,
calculate = function(_, card, context)
local extra = card.ability.extra
if context.joker_main or context.forcetrigger then
return {card = card, mult = extra.mult}
end
if not context.before or context.scoring_name ~= extra.hand_name then
return
end
extra.mult = extra.mult + extra.mult_gain
return {message = localize "k_upgrade_ex", colour = G.C.RED, message_card = card}
end,
}
joker {
key = "trimino",
pronouns = "it_its",
artist = "char",
config = {extra = {times = 4, hand_name = "Four of a Kind"}},
attributes = {"generation", "hand_type"},
cost = 8,
rarity = 3,
eternal_compat = false,
blueprint_compat = true,
perishable_compat = true,
loc_vars = function(_, _, card)
local extra = card.ability.extra
return {vars = {extra.times, localize(extra.hand_name, "poker_hands")}}
end,
calculate = function(_, card, context)
local extra = card.ability.extra
if (not context.before or card.getting_sliced or context.scoring_name ~= extra.hand_name) and not context.forcetrigger then
return
end
card.getting_sliced = not context.forcetrigger
q(function()
local scored_cards = f(G.play.cards):where "highlighted":table()
local copied = {}
if not next(scored_cards) then
card.getting_sliced = nil
return
end
f(extra.times):each(function()
G.playing_card = (G.playing_card or 0) + 1
G.deck.config.card_limit = G.deck.config.card_limit + 1
local chosen = pseudorandom_element(scored_cards, pseudoseed "Roland_trimino")
local copy = copy_card(chosen, nil, nil, G.playing_card)
copy:add_to_deck()
G.hand:emplace(copy)
copy:start_materialize()
table.insert(copied, copy)
table.insert(G.playing_cards, copy)
end)
SMODS.calculate_effect({{message = localize "k_copied_ex", message_card = card}}, card)
playing_card_joker_effects(copied)
if not context.forcetrigger then
card:start_dissolve()
end
end)
end,
}
joker {
key = "cold",
pronouns = "he_him",
config = {extra = {xmult = 2}},
attributes = {"xmult"},
cost = 4,
rarity = 1,
eternal_compat = true,
blueprint_compat = true,
perishable_compat = true,
loc_vars = function(_, info_queue, card)
table.insert(info_queue, G.P_CENTERS.e_Roland_frozen)
return {vars = {card.ability.extra.xmult}}
end,
calculate = function(_, card, context)
local target = (context.scoring_hand or {})[3]
return (context.individual and
context.cardarea == G.play and
context.other_card == target and
is_frozen(context.other_card) or
context.forcetrigger) and
{xmult = card.ability.extra.xmult} or nil
end,
}
joker {
key = "snowsquall",
pronouns = "they_them",
config = {extra = {mult_gain = 1, mult = 0}},
attributes = {"mult", "scaling", "hand_type"},
cost = 6,
rarity = 2,
eternal_compat = true,
blueprint_compat = true,
perishable_compat = false,
loc_vars = function(_, info_queue, card)
table.insert(info_queue, G.P_CENTERS.e_Roland_frozen)
local extra = card.ability.extra
return {vars = {extra.mult_gain, extra.mult}}
end,
calculate = function(_, card, context)
local extra = card.ability.extra
if context.joker_main or context.forcetrigger then
return {card = card, mult = extra.mult}
end
if context.blueprint or
not context.individual or
context.cardarea ~= G.play or
not is_frozen(context.other_card) then
return
end
extra.mult = extra.mult + extra.mult_gain
return {message = localize "k_upgrade_ex", colour = G.C.RED, message_card = card}
end,
}
joker {
key = "arctic",
pronouns = "it_its",
cost = 10,
rarity = 3,
config = {extra = {frozen = 2, non_frozen = 1}},
attributes = {"retrigger", "editions"},
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,
inject = function(...)
SMODS.Joker.inject(...)
Bakery_API.retrigger_jokers.j_Roland_arctic = true
end,
calculate = function(_, card, context)
local extra = card.ability.extra
return (context.repetition and context.other_card) and
{card = card, repetitions = is_frozen(context.other_card) and extra.frozen or extra.non_frozen} 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.DARK_EDITION
return v
end):values():table()
)
end,
}
joker {
key = "sapling",
pronouns = "they_them",
artist = "char",
attributes = {"mult", "suit"},
cost = 4,
rarity = 1,
config = {extra = {mult = 15, suits = 3}},
eternal_compat = true,
blueprint_compat = true,
perishable_compat = true,
loc_vars = function(_, _, card)
local extra = card.ability.extra
return {vars = {extra.mult, extra.suits}}
end,
calculate = function(_, card, context)
local function count(_, k)
return f(context.scoring_hand):any(function(v)
return v:is_suit(k)
end)
end
if not context.joker_main and not context.forcetrigger then
return
end
local extra = card.ability.extra
if f(SMODS.Suits):count(count) >= card.ability.extra.suits or context.forcetrigger then
return {card = card, mult = extra.mult}
end
end,
}
joker {
key = "yard",
pronouns = "he_him",
config = {extra = {money = 2}},
attributes = {"economy"},
cost = 4,
rarity = 1,
eternal_compat = true,
blueprint_compat = true,
perishable_compat = true,
loc_vars = function(_, _, card)
return {vars = {card.ability.extra.money}}
end,
calculate = function(_, card, context)
return (context.remove_playing_cards or context.forcetrigger) and
{dollars = card.ability.extra.money * #context.removed, card = card} or nil
end,
}
joker {
key = "misfortune",
pronouns = "she_they",
artist = "char",
attributes = {"discard", "generation", "seals"},
cost = 6,
rarity = 2,
eternal_compat = true,
blueprint_compat = false,
perishable_compat = true,
loc_vars = function(_, info_queue)
table.insert(info_queue, G.P_SEALS.Purple)
table.insert(info_queue, negative)
end,
in_pool = function()
return f(G.playing_cards):any(function(v)
return v.seal == "Purple"
end)
end,
}
joker {
key = "bulldozer",
pronouns = "it_its",
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",
config = {extra = {xmult = 0.25}},
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",
config = {extra = {flipped = false}},
attributes = {"xmult"},
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,
inject = function(...)
SMODS.Joker.inject(...)
Bakery_API.double_sided_jokers.j_Roland_nilly = true
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 = "he_they",
config = {extra = {xmult = 3}},
pixel_size = {w = 68, h = 68},
attributes = {"xmult"},
cost = 9,
rarity = 3,
eternal_compat = true,
blueprint_compat = true,
perishable_compat = false,
loc_vars = function(_, _, card)
return {vars = {card.ability.extra.xmult}}
end,
calculate = function(_, card, context)
if context.joker_main or context.forcetrigger then
return {card = card, xmult = card.ability.extra.xmult}
end
if card.debuff or context.blueprint or not context.press_play then
return
end
local keys = f(card.area.cards):where(f().nq(card)):keys():table()
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]
end,
}
joker {
key = "martingale",
pronouns = "he_him",
config = {extra = {odds = 2}},
attributes = {"xmult", "chance"},
cost = 8,
rarity = 2,
eternal_compat = true,
blueprint_compat = true,
perishable_compat = true,
loc_vars = function(_, _, card)
local normal = G.GAME.probabilities.normal
local odds = card.ability.extra.odds
local vars = {normal}
for i = 0, 7 do
table.insert(vars, math.pow(odds, i))
end
return {vars = vars}
end,
calculate = function(self, card, context)
if not context.joker_main and not context.forcetrigger then
return
end
local g, extra, numerator, xmult = G.GAME, card.ability.extra, 1, 1
if g.blind.name == "bl_mp_nemesis" then
return {card = card, xmult = extra.odds}
end
for _ = 1, 64 do
local key = "RolandMartingale" .. tostring(g.modifiers.Roland_martingale_seed or "")
if SMODS.pseudorandom_probability(card, self.key, 1, extra.odds, key) then
break
end
numerator = numerator * (extra.odds - g.probabilities.normal)
local message = number_format(numerator) .. "/" .. number_format(xmult)
SMODS.calculate_effect({card = card, repetitions = 1, message = message, message_card = card}, card)
xmult = xmult * extra.odds
end
SMODS.calculate_effect({card = card, xmult = xmult}, card)
end,
}
joker {
key = "idle",
pronouns = "they_them",
rarity = 2,
Roland_idle_capacity = 6,
cost = G.P_CENTERS.j_idol.cost,
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,
}
joker {
key = "suitable",
pronouns = "she_they",
attributes = {"suit", "passive", "hearts", "diamonds", "spades", "clubs"},
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,
add_to_deck = function()
G.GAME.modifiers.Roland_suitable = (G.GAME.modifiers.Roland_suitable or 0) + 1
end,
remove_from_deck = function()
G.GAME.modifiers.Roland_suitable = (G.GAME.modifiers.Roland_suitable or 0) - 1
end,
}
function SMODS.current_mod.reset_game_globals()
local immutable = f(SMODS.find_card "j_Roland_suitable"):any(is_frozen)
local suitable = {suit = "Spades"}
G.GAME.current_round.Roland_suitable = immutable and
G.GAME.current_round.Roland_suitable or suitable
if immutable then
return
end
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 (G.GAME.modifiers.Roland_suitable or 0) <= 0 or
card.base.suit ~= G.GAME.current_round.Roland_suitable.suit or
(card.area ~= G.hand and card.area ~= G.play) then
return orig_get_enhancements(card, ...)
end
local ret = orig_get_enhancements(card, ...) or {}
ret.m_wild = true
return ret
end
joker {
key = "artemis",
pronouns = "she_they",
cost = 6,
rarity = 2,
config = {extra = {
dollars = 2,
increase = 3,
progress = 0,
flipped = false,
sequence = {"c_earth", "c_mars", "c_earth"},
}},
calc_dollar_bonus = function(_, card)
return card.ability.extra.dollars
end,
inject = function(...)
SMODS.Joker.inject(...)
Bakery_API.double_sided_jokers.j_Roland_artemis = true
end,
loc_vars = function(_, info_queue, card)
local extra = card.ability.extra
local function color(i)
return i == extra.progress + 1 and (i == 2 and G.C.ORANGE or G.C.BLUE) or G.C.JOKER_GREY
end
f(extra.sequence):each(function(v)
table.insert(info_queue, G.P_CENTERS[v])
end)
return {vars = {extra.dollars, extra.increase, colours = f(#extra.sequence):map(color):table()}}
end,
calculate = function(_, card, context)
local extra = card.ability.extra
if context.blueprint or
not context.using_consumeable or
context.consumeable.config.center.key ~= extra.sequence[extra.progress + 1] then
return
end
extra.progress = extra.progress + 1
_ = (extra.progress == 1) ~= extra.flipped and Bakery_API.flip_double_sided(card)
if extra.sequence[extra.progress + 1] then
return {
message = localize "k_progress",
colour = extra.progress == 2 and G.C.ORANGE or G.C.BLUE,
message_card = card,
}
end
extra.progress = 0
extra.dollars = extra.dollars + extra.increase
return {
message = localize "k_upgrade_ex",
colour = G.C.MONEY,
message_card = card,
}
end,
}
joker {
key = "oops",
pronouns = "she_they",
artist = "char",
cost = 7,
rarity = 3,
config = {extra = {probability = 1, probability_mult = 2, reset = 1}},
attributes = {"hands", "mod_chance", "scaling"},
eternal_compat = true,
blueprint_compat = false,
perishable_compat = true,
loc_vars = function(_, _, card)
local extra = card.ability.extra
return {vars = {extra.probability_mult, extra.probability}}
end,
calculate = function(_, card, context)
if context.blueprint and not context.forcetrigger or not card.ability then
return
end
local extra = card.ability.extra
if context.mod_probability then
return {card = card, numerator = extra.probability}
end
if context.end_of_round and extra.probability ~= extra.reset then
extra.probability = extra.reset
return {message = localize "k_reset", colour = G.C.RED, message_card = card}
end
if context.after then
extra.probability = extra.probability * extra.probability_mult
return {message = localize "k_upgrade_ex", colour = G.C.GREEN, message_card = card}
end
end,
}