Compare commits

..

No commits in common. "main" and "2.9.10" have entirely different histories.
main ... 2.9.10

34 changed files with 536 additions and 403 deletions

View file

@ -65,8 +65,4 @@
"unused-local": "Error",
"unused-vararg": "Error",
},
"Lua.runtime.version": "LuaJIT",
"Lua.workspace.library": [
"${3rd}/love2d/library"
],
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 77 KiB

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 89 KiB

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 242 KiB

After

Width:  |  Height:  |  Size: 242 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 85 KiB

After

Width:  |  Height:  |  Size: 85 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: 1 KiB

After

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 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: 22 KiB

View file

@ -495,22 +495,6 @@ return {
},
},
},
Voucher = {
v_Roland_ceres = {
name = "Ceres",
text = {
"Level up {C:attention}Flush House",
"by {C:attention}#1# {}when it is played",
},
},
v_Roland_neptune = {
name = "Neptune",
text = {
"Level up {C:attention}Straight Flush",
"by {C:attention}#1# {}when it is played",
},
},
},
},
misc = {
challenge_names = {
@ -561,7 +545,7 @@ return {
ch_c_Roland_Eternally_Verdant = {"{C:attention}Verdant Leaf{}'s effect is active every blind"},
ch_c_Roland_Eternally_Violet = {"{C:attention}Violet Vessel{}'s effect is active every blind"},
ch_c_Roland_Glass1 = {"Played cards with no seal have a"},
ch_c_Roland_Glass2 = {"{C:green}1 in 2{} chance to gain {C:dark_edition}Glass Seal"},
ch_c_Roland_Glass2 = {"{C:green}1 in 4{} chance to gain {C:dark_edition}Glass Seal"},
ch_c_Roland_Go = {"Set money to {C:money}$0 {}when entering the shop"},
ch_c_Roland_Jokerful = {"The only jokers are {C:mult}Joker{} and {C:chips}Ms. Joker"},
ch_c_Roland_Pastries = {"All blinds, cards, and tags are of {C:gold}Bakery{} or {C:blue}Roland"},

View file

@ -3,7 +3,7 @@
"id": "Roland",
"name": "Roland",
"prefix": "Roland",
"version": "2.9.28",
"version": "2.9.10",
"badge_colour": "8BE9FD",
"display_name": "Roland",
"main_file": "src/main.lua",

View file

@ -27,8 +27,9 @@ local back = (function()
tbl.atlas = "back"
x = x + 1
local back = q(SMODS.Back(tbl))
local sleeve = (_G["CardSleeves"] or {}).Sleeve
local _ = CardSleeves and CardSleeves.Sleeve {
local _ = sleeve and sleeve {
key = key,
pos = tbl.pos,
atlas = "sleeve",
@ -60,7 +61,7 @@ SMODS.Atlas {
py = 95,
}
local _ = CardSleeves and SMODS.Atlas {
local _ = _G["CardSleeves"] and SMODS.Atlas {
key = "sleeve",
path = "sleeve.png",
px = 73,

View file

@ -23,7 +23,10 @@ SMODS.Atlas {
atlas_table = "ANIMATION_ATLAS",
}
SMODS.Sound {key = "kick", path = "kick.ogg"}
SMODS.Sound {
key = "kick",
path = "kick.ogg",
}
local function common_rank()
local tally, to_name = {}, {}
@ -52,7 +55,7 @@ end
local function has_enhancement(card)
local e = SMODS.get_enhancements(card)
return e and next(e)
return not not (e and next(e))
end
local function set_freeze(state)
@ -239,16 +242,16 @@ blind {
disable = function(self)
self:defeat()
end,
calculate = function(self, b, context)
return not b.disabled and
context.hand_drawn and
self.cards()
calculate = function(self, b)
return not b.disabled and self.cards()
:where("Roland_blizzard", false)
:where("facing", "front")
:each(set_freeze(true)) or nil
end,
cards = function()
return f(G):where(getmetatable, CardArea):flatmap("cards", ipairs)
return f(G):where(function(v)
return type(v) == "table" and type(v.cards) == "table"
end):flatmap("cards", ipairs)
end,
}
@ -350,16 +353,6 @@ function SMODS.current_mod:calculate(context)
local _ = not str and type(G.calc[1]) == "function" and G.calc[1](f(context):keys():string())
end
local _ = context.before and
f {"v_Roland_ceres", "v_Roland_neptune"}
:where(f.index_into(G.GAME.used_vouchers))
:map(f.index_into(G.P_CENTERS))
:where("config.extra.hand_type", context.scoring_name)
:pun "SMODS.Voucher"
:each(function(v, _)
SMODS.smart_level_up_hand(nil, v.config.extra.hand_type, nil, v.config.extra.amount)
end)
local improbable, orig = G.GAME.modifiers.Roland_improbable, G.GAME.probabilities
local _ = context.end_of_round and
@ -483,15 +476,15 @@ local venerable_visage = blind {
vitriol = function(b)
local vitriol = SMODS.Mods.Roland.config.vitriol
local resize_to_w, resize_to_h = 320, 200
local is_fullscreen = love.window.getFullscreen()
local is_fullscreen = _G["love"].window.getFullscreen()
if vitriol then
love.window.setFullscreen(false)
_G["love"].window.setFullscreen(false)
delay(1.5)
end
local function jitter()
local x, y = love.window.getDesktopDimensions()
local x, y = _G["love"].window.getDesktopDimensions()
return pseudorandom(pseudoseed "RolandVenerableVisageX", 0, x) - x / 2,
pseudorandom(pseudoseed "RolandVenerableVisageY", 0, y) - y / 2
@ -519,16 +512,15 @@ local venerable_visage = blind {
play_sound("gong", v)
end)
---@type number, number, table
local w, h, flags = love.window.getMode()
local len = #G.playing_cards
local w, h, flags = _G["love"].window.getMode()
if vitriol then
love.window.setMode(resize_to_w, resize_to_h)
love.resize(resize_to_w, resize_to_h)
_G["love"].window.setMode(resize_to_w, resize_to_h)
_G["love"].resize(resize_to_w, resize_to_h)
end
local x, y = love.window.getPosition()
local x, y = _G["love"].window.getPosition()
f(G.playing_cards):each(function(v, i)
q {
@ -537,7 +529,7 @@ local venerable_visage = blind {
func = function()
if vitriol then
local x_random, y_random = jitter()
love.window.setPosition(x + x_random * i / len, y + y_random * i / len)
_G["love"].window.setPosition(x + x_random * i / len, y + y_random * i / len)
end
v:start_dissolve()
@ -551,10 +543,10 @@ local venerable_visage = blind {
trigger = "before",
delay = 1.5,
func = function()
love.window.setPosition(x, y)
love.window.setMode(w, h, flags)
love.resize(w, h)
love.window.setFullscreen(is_fullscreen)
_G["love"].window.setPosition(x, y)
_G["love"].window.setMode(w, h, flags)
_G["love"].resize(w, h)
_G["love"].window.setFullscreen(is_fullscreen)
end,
}

View file

@ -46,7 +46,7 @@ SMODS.Challenge {
key = "Glass",
rules = {custom = {{id = "Roland_Glass1"}, {id = "Roland_Glass2"}}},
pronouns = "they_them",
config = {extra = {odds = 2}},
config = {extra = {odds = 4}},
calculate = function(self, context)
if not context.after or context.blueprint_card then
return
@ -110,10 +110,12 @@ SMODS.Challenge {
pronouns = "she_them",
}
local starting_jokers = f(5):map(f.const {id = "j_joker"}):table()
SMODS.Challenge {
key = "Eternally_Amber",
rules = {custom = {{id = "Roland_Eternally_Amber"}, {id = "Roland_Showdown_Amber"}}},
jokers = {{id = "j_Roland_amber"}},
jokers = starting_jokers,
restrictions = amber,
pronouns = "they_them",
calculate = function(_, context)
@ -152,7 +154,7 @@ SMODS.Challenge {
SMODS.Challenge {
key = "Eternally_Cerulean",
rules = {custom = {{id = "Roland_Eternally_Cerulean"}, {id = "Roland_Showdown_Cerulean"}}},
jokers = {{id = "j_Roland_cerulean"}},
jokers = starting_jokers,
restrictions = cerulean,
pronouns = "she_her",
calculate = function(_, context)
@ -179,7 +181,7 @@ SMODS.Challenge {
SMODS.Challenge {
key = "Eternally_Crimson",
rules = {custom = {{id = "Roland_Eternally_Crimson"}, {id = "Roland_Showdown_Crimson"}}},
jokers = {{id = "j_Roland_crimson"}},
jokers = starting_jokers,
restrictions = crimson,
pronouns = "she_her",
calculate = function(_, context)
@ -188,7 +190,7 @@ SMODS.Challenge {
end)
local mod = G.GAME.modifiers
mod.Roland_Eternally_Crimson = context.setting_blind and true or mod.Roland_Eternally_Crimson
mod.Roland_Eternally_Crimson = not context.setting_blind and mod.Roland_Eternally_Crimson or nil
local debuff = context.debuff_card
local cards = G.jokers.cards
@ -239,7 +241,7 @@ SMODS.Challenge {
SMODS.Challenge {
key = "Eternally_Verdant",
rules = {custom = {{id = "Roland_Eternally_Verdant"}, {id = "Roland_Showdown_Verdant"}}},
jokers = {{id = "j_Roland_verdant"}},
jokers = starting_jokers,
restrictions = verdant,
pronouns = "she_her",
calculate = function(_, context)
@ -262,7 +264,7 @@ SMODS.Challenge {
SMODS.Challenge {
key = "Eternally_Violet",
rules = {custom = {{id = "Roland_Eternally_Violet"}, {id = "Roland_Showdown_Violet"}}},
jokers = {{id = "j_joker"}, {id = "j_Roland_violet"}},
jokers = starting_jokers,
restrictions = violet,
pronouns = "she_they",
calculate = function(_, context)

View file

@ -261,7 +261,7 @@ local orig_apply_to_run = Tag.apply_to_run
function Tag:apply_to_run(...)
if G.GAME.Bakery_charm == "BakeryCharm_Roland_wii" and
G.Bakery_charm_area.cards[1].ability.extra.active then
G.Bakery_charm_area.cards[1].config.center.ability.extra.active then
return
end

View file

@ -13,7 +13,7 @@ end
frozen_sound "_click"
local frozen_blocklist = {CardSleeve = true}
local frozen_sounds = f(4):map(frozen_sound):map "key":table()
local frozen_sounds = f(4):map(frozen_sound):map("key"):table()
local needs_chip_mult_override = {
Bull = true,
@ -144,7 +144,7 @@ local function hook_proxy()
local orig_calculate = proxy.calculate
function proxy:calculate(card, context, ...)
if not (card or {}).Roland_frozen or not (card.edition or {}).Roland_frozen then
if not card or not card.edition or not card.edition.Roland_frozen then
return orig_calculate(self, card, context, ...)
else
return SMODS.blueprint_effect(card, get_proxied_joker(card), context)
@ -154,7 +154,7 @@ local function hook_proxy()
local orig_loc_vars = proxy.loc_vars
function proxy:loc_vars(info_queue, card, ...)
if not (card or {}).Roland_frozen or not (card.edition or {}).Roland_frozen then
if not card or not card.edition or not card.edition.Roland_frozen then
return orig_loc_vars(self, info_queue, card, ...)
end

View file

@ -216,9 +216,9 @@ joker {
SMODS.calculate_context {drawing_cards = true, draw = {G.deck.cards}}
SMODS.calculate_context {
hand_drawn = facing_blind and {G.deck.cards[1]} and true,
other_drawn = not facing_blind and {G.deck.cards[1]} and true,
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
@ -488,9 +488,11 @@ joker {
end
end
return SMODS.merge_effects(
local key = card.config.center.key
local merged = SMODS.merge_effects(
f(G.jokers.cards):where(is_frozen):where(function(v)
return v.config.center.key ~= card.config.center.key
return v.config.center.key ~= key
end):map(function(v)
return SMODS.blueprint_effect(card, v, context)
end):where(type, "table"):map(function(v)
@ -498,6 +500,8 @@ joker {
return v
end):values():table()
)
return merged
end,
}
@ -648,7 +652,7 @@ joker {
local _ = card.area == G.jokers and self:cerulean(false)
end,
cerulean = function(_, value)
local _ = G.jokers and f(G.jokers.cards):each(function(v)
f(G.jokers.cards):each(function(v)
f {"click", "drag", "focus", "hover"}:map(f.index_into(v.states)):each(function(s)
s.can = value or v.config.center.key == "j_Roland_cerulean"
end)
@ -675,7 +679,7 @@ joker {
{card = card, xmult = card.ability.extra.xmult} or nil
end,
crimson = function()
local _ = G.jokers and f(G.jokers.cards, ipairs_reversed):where(is_frozen, false):each(function(v)
f(G.jokers.cards, ipairs_reversed):where(is_frozen, false):each(function(v)
local right = G.jokers.cards[v.rank + 1]
local debuffed_by_crimson = right and
@ -684,13 +688,11 @@ joker {
right.config.center.key == "j_Roland_crimson"
if debuffed_by_crimson and v.ability.Roland_crimson == nil then
local debuff = not not v.debuff
v.ability.Roland_crimson = not not v.debuff
v:set_debuff(true)
v.ability.Roland_crimson = debuff
elseif not debuffed_by_crimson and v.ability.Roland_crimson ~= nil then
local debuff = v.ability.Roland_crimson
v:set_debuff(v.ability.Roland_crimson)
v.ability.Roland_crimson = nil
v:set_debuff(debuff)
end
end)
end,
@ -757,7 +759,7 @@ joker {
key = "violet",
pronouns = "she_they",
idea = "hamester",
config = {extra = {before = 0.1, xmult = 6}},
config = {extra = {before = 0.1, xmult = 9}},
pixel_size = {w = 68, h = 68},
attributes = {"xmult"},
cost = 6,
@ -936,14 +938,10 @@ joker {
local extra, numerator, xmult = card.ability.extra, 1, 1
if G.GAME.blind.name == "bl_mp_nemesis" then
local n, d = SMODS.get_probability_vars(card, 1, extra.odds, self.key)
return n < d and {card = card, xmult = extra.odds} or nil
return {card = card, xmult = extra.odds}
end
-- 2^38 is the first iteration displayed as scientific notation.
local max, overflown = 38, false
for i = 1, max do
for _ = 1, 256 do
local key = "RolandMartingale" .. tostring(G.GAME.modifiers.Roland_martingale_seed or "")
if SMODS.pseudorandom_probability(card, self.key, 1, extra.odds, key) then
@ -955,18 +953,9 @@ joker {
xmult = xmult * extra.odds
local message = number_format(numerator) .. "/" .. number_format(xmult)
SMODS.calculate_effect({card = card, repetitions = 1, message = message, message_card = card}, card)
overflown = overflown or i == max
end
if overflown then
SMODS.calculate_effect({card = card, score = 1 / 0}, card)
q(function()
card:shatter()
end)
else
SMODS.calculate_effect({card = card, xmult = xmult}, card)
end
end,
}
@ -1258,7 +1247,7 @@ joker {
return {card = card, numerator = extra.probability}
end
if context.end_of_round and not context.repetition and extra.probability ~= extra.reset then
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, repetitions = 0}
end

View file

@ -9,91 +9,81 @@ local f = {}
if not f then
---@generic I, O
---@param first string|fun(v: I): O
---@param first fun(v: I): O
---@return fun(v: I): O
---@nodiscard
function f.chain(first)
error {first}
end
---@generic I, T, O
---@param first string|fun(v: I): T
---@param second string|fun(v: T): O
---@param first fun(v: I): T
---@param second fun(v: T): O
---@return fun(v: I): O
---@nodiscard
function f.chain(first, second)
error {first, second}
end
---@generic I, T1, T2, O
---@param first string|fun(v: I): T1
---@param second string|fun(v: T1): T2
---@param third string|fun(v: T2): O
---@param first fun(v: I): T1
---@param second fun(v: T1): T2
---@param third fun(v: T2): O
---@return fun(v: I): O
---@nodiscard
function f.chain(first, second, third)
error {first, second, third}
end
---@generic I, T1, T2, T3, O
---@param first string|fun(v: I): T1
---@param second string|fun(v: T1): T2
---@param third string|fun(v: T2): T3
---@param fourth string|fun(v: T3): O
---@param first fun(v: I): T1
---@param second fun(v: T1): T2
---@param third fun(v: T2): T3
---@param fourth fun(v: T3): O
---@return fun(v: I): O
---@nodiscard
function f.chain(first, second, third, fourth)
error {first, second, third, fourth}
end
---@generic I, T1, T2, T3, T4, O
---@param first string|fun(v: I): T1
---@param second string|fun(v: T1): T2
---@param third string|fun(v: T2): T3
---@param fourth string|fun(v: T3): T4
---@param fifth string|fun(v: T4): O
---@param first fun(v: I): T1
---@param second fun(v: T1): T2
---@param third fun(v: T2): T3
---@param fourth fun(v: T3): T4
---@param fifth fun(v: T4): O
---@return fun(v: I): O
---@nodiscard
function f.chain(first, second, third, fourth, fifth)
error {first, second, third, fourth, fifth}
end
---@generic I, O
---@param all { [1]: (string|fun(v: I): O) }
---@param all {[1]: (fun(v: I): O)}
---@return fun(v: I): O
---@nodiscard
function f.chain(all)
error(all)
end
---@generic I, T, O
---@param all { [1]: (string|fun(v: I): T), [2]: (string|fun(v: T): O) }
---@param all {[1]: (fun(v: I): T), [2]: (fun(v: T): O)}
---@return fun(v: I): O
---@nodiscard
function f.chain(all)
error(all)
end
---@generic I, T1, T2, O
---@param all { [1]: (string|fun(v: I): T1), [2]: (string|fun(v: T1): T2), [3]: (string|fun(v: T2): O) }
---@param all {[1]: (fun(v: I): T1), [2]: (fun(v: T1): T2), [3]: (fun(v: T2): O)}
---@return fun(v: I): O
---@nodiscard
function f.chain(all)
error(all)
end
---@generic I, T1, T2, T3, O
---@param all { [1]: (string|fun(v: I): T1), [2]: (string|fun(v: T1): T2), [3]: (string|fun(v: T2): T3), [4]: (string|fun(v: T3): O) }
---@param all {[1]: (fun(v: I): T1), [2]: (fun(v: T1): T2), [3]: (fun(v: T2): T3), [4]: (fun(v: T3): O)}
---@return fun(v: I): O
---@nodiscard
function f.chain(all)
error(all)
end
---@generic I, T1, T2, T3, T4, O
---@param all { [1]: (string|fun(v: I): T1), [2]: (string|fun(v: T1): T2), [3]: (string|fun(v: T2): T3), [4]: (string|fun(v: T3): T4), [4]: (string|fun(v: T4): O) }
---@param all {[1]: (fun(v: I): T1), [2]: (fun(v: T1): T2), [3]: (fun(v: T2): T3), [4]: (fun(v: T3): T4), [4]: (fun(v: T4): O)}
---@return fun(v: I): O
---@nodiscard
function f.chain(all)
error(all)
end
@ -114,7 +104,7 @@ local none
---@return T
---@nodiscard
local function autofunc(func)
return type(func) == "string" and f.indices(func) or func or f.id
return type(func) == "string" and f.index(func) or func or f.id
end
---@generic K, V
@ -128,6 +118,13 @@ local function autopairs(tbl, fpairs)
return (fpairs or (tbl[#tbl] and ipairs or pairs))(tbl)
end
---@param any any
---@return boolean
---@nodiscard
local function is_f(any)
return type(any) == "table" and any.from == f.from and any.new == f.new
end
--- Always returns nil.
---@return nil
---@nodiscard
@ -160,7 +157,6 @@ end
---@generic T
---@param value T
---@return fun(T): boolean
---@nodiscard
function f.eq(value)
return function(v)
return value == v
@ -170,7 +166,6 @@ end
---@generic T
---@param value T
---@return fun(T): boolean
---@nodiscard
function f.nq(value)
return function(v)
return value ~= v
@ -195,15 +190,6 @@ function f.const(v)
end
end
---@param i integer
---@return fun(...: any): any
---@nodiscard
function f.arg(i)
return function(...)
return ({...})[i]
end
end
---@generic K, V
---@param v K
---@return fun(x: { [K]: V }): V
@ -242,32 +228,17 @@ function f.indices(v)
end
end
---@param any any
---@return boolean
---@nodiscard
function f.isf(any)
return type(any) == "table" and any.from == f.from and any.new == f.new
end
f[true and "chain"] = function(...)
local ret
for _, v in ipairs {...} do
for _, v in ipairs(...) do
if type(v) == "table" then
for _, vv in ipairs(v) do
local copy = ret
vv = autofunc(vv)
ret = ret and function(...)
return vv(copy(...))
return vv(ret(...))
end or vv
end
else
local copy = ret
v = autofunc(v)
ret = ret and function(...)
return v(copy(...))
return v(ret(...))
end or v
end
end
@ -284,7 +255,6 @@ function f.new(fnext)
return {
all = f.all,
any = f.any,
arg = f.arg,
chain = f.chain,
concat = f.concat,
const = f.const,
@ -299,14 +269,12 @@ function f.new(fnext)
index = f.index,
index_into = f.index_into,
indices = f.indices,
isf = f.isf,
keys = f.keys,
map = f.map,
new = f.new,
next = fnext or f.noop,
noop = f.noop,
nq = f.nq,
peek = f.peek,
pun = f.pun,
skip = f.skip,
slice = f.slice,
@ -386,7 +354,7 @@ function f:concat(...)
local sum, last = 0, 0
for i = 1, #fs do
fs[i] = f.isf(fs[i]) and fs[i] or f.from(fs[i])
fs[i] = is_f(fs[i]) and fs[i] or f.from(fs[i])
end
return f.new(function()
@ -414,30 +382,12 @@ function f:concat(...)
end)
end
---@generic K, V
---@param self F|{ [K]: V }
---@param func fun(v: V, k: K): any
---@return F|{ [K]: V }
---@nodiscard
function f:peek(func)
func = autofunc(func)
return f.new(function()
local k, v = self:next()
if k ~= nil then
func(v, k)
return k, v
end
end)
end
---@generic K, V, U
---@param self F|{ [K]: V }
---@param func fun(v: V, k: K): U
---@param func F|fun(v: V, k: K): U
---@return F|{ [K]: U }
---@overload fun(self: F|{ [K]: V }, func: string): F|{ [K]: U }
---@nodiscard
---@overload fun(self: F|{ [K]: V }, func: string): F|{ [K]: U }
function f:map(func)
func = autofunc(func)
@ -452,11 +402,61 @@ end
---@generic K, V, U
---@param self F|{ [K]: V }
---@param func fun(v: V, k: K): { [any]: U }
---@param func F|fun(v: V, k: K): { [any]: U }
---@param fpairs? fun(t: table<K, V>): (fun(table: table<K, V>, index?: K): K, V)
---@return F|{ [K]: U }
---@overload fun(self: F|{ [K]: V }, func: string, fpairs?: fun(t: table<K, V>): (fun(table: table<K, V>, index?: K): K, V)): F|{ [K]: U }
---@nodiscard
---@overload fun(self: F|{ [K]: V }, func: string, fpairs?: fun(t: table<K, V>): (fun(table: table<K, V>, index?: K): K, V)): F|{ [K]: U }
function f:flatmap(func, fpairs)
-- local i = 0
local vt, vk, vv, vp
func = autofunc(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, U
---@param self F|{ [K]: V }
---@param func F|fun(v: V, k: K): { [any]: U }
---@param fpairs? fun(t: table<K, V>): (fun(table: table<K, V>, index?: K): K, V)
---@return F|{ [K]: U }
---@nodiscard
---@overload fun(self: F|{ [K]: V }, func: string, fpairs?: fun(t: table<K, V>): (fun(table: table<K, V>, index?: K): K, V)): F|{ [K]: U }
function f:flatmap(func, fpairs)
-- local i = 0
local vt, vk, vv, vp
@ -502,7 +502,7 @@ end
---@generic K, V
---@param self F|{ [K]: V }
---@param func fun(v: V, k: K): boolean
---@param func F|fun(v: V, k: K): boolean
---@param is? any
---@return F|{ [K]: V }
---@nodiscard
@ -665,10 +665,10 @@ end
---@generic K, V
---@param self F|{ [K]: V }
---@param func fun(v: V, k: K): any
---@param func F|fun(v: V, k: K): any
---@return boolean|V
---@overload fun(self: F|{ [K]: V }, func: string?): boolean|V
---@nodiscard
---@overload fun(self: F|{ [K]: V }, func: string?): boolean|V
function f:any(func)
func = autofunc(func)
@ -683,10 +683,10 @@ end
---@generic K, V
---@param self F|{ [K]: V }
---@param func fun(v: V, k: K): any
---@param func F|fun(v: V, k: K): any
---@return boolean|V
---@overload fun(self: F|{ [K]: V }, func: string?): boolean|V
---@nodiscard
---@overload fun(self: F|{ [K]: V }, func: string?): boolean|V
function f:all(func)
func = autofunc(func)
@ -701,10 +701,10 @@ end
---@generic K, V
---@param self F|{ [K]: V }
---@param func fun(v: V, k: K): any
---@param func F|fun(v: V, k: K): any
---@return integer
---@overload fun(self: F|{ [K]: V }, func: string): integer
---@nodiscard
---@overload fun(self: F|{ [K]: V }, func: string): integer
function f:count(func)
local ret = 0
func = autofunc(func)

View file

@ -1,8 +1,19 @@
---@meta
---@alias Attributes "mult"|"chips"|"xmult"|"xchips"|"score"|"xscore"|"blindsize"|"xblindsize"|"balance"|"swap"|"retrigger"|"scaling"|"reset"|"suit"|"diamonds"|"hearts"|"spades"|"clubs"|"hand_type"|"rank"|"ace"|"two"|"three"|"four"|"five"|"six"|"seven"|"eight"|"nine"|"ten"|"jack"|"queen"|"king"|"face"|"economy"|"generation"|"destroy_card"|"hands"|"discard"|"hand_size"|"chance"|"joker_slot"|"mod_chance"|"copying"|"full_deck"|"passive"|"joker"|"tarot"|"planet"|"spectral"|"enhancements"|"seals"|"editions"|"tag"|"skip"|"modify_card"|"perma_bonus"|"prevents_death"|"boss_blind"|"reroll"|"on_sell"|"sell_value"|"food"|"space"|"bakery_double_sided"|"bakery_usable"|"bakery_werewolf"
SMODS.Mods.Roland.config = require "config"
---@type Card[]
CardArea.cards = CardArea.cards
---@type userdata|{getWidth: fun(self: self): number}
SMODS.Atlas.image_data = SMODS.Atlas.image_data
--- @type { constants?: { TEN: table }, new: (fun(self: self, arr?: number[], sign?: number, noNormalize?: boolean): table), pow: (fun(x: number, y: number): number) }
_G["Big"] = _G["Big"]
--- @type fun(area: CardArea, ...: ...): Card
create_card_for_shop = create_card_for_shop
--- @overload fun(tbl: SMODS.Joker): SMODS.GameObject
Bakery_API.Charm = Bakery_API.Charm
@ -13,38 +24,6 @@ function Bakery_API.credit(obj)
error(obj)
end
---@type table
Balatest = Balatest
--- @type { constants?: { TEN: table }, new: (fun(self: self, arr?: number[], sign?: number, noNormalize?: boolean): table), pow: (fun(x: number, y: number): number) }
Big = Big
--- @type table?
CardSleeves = CardSleeves
--- @type table|fun(obj: SMODS.Back): SMODS.Back
CardSleeves.Sleeve = CardSleeves.Sleeve
--- @type {aliases: { [string]: [string] }}
Cryptid = Cryptid
--- @type fun(area: CardArea, ...: ...): Card
create_card_for_shop = create_card_for_shop
--- @type boolean|table
G.Bakery_charm_area.cards[1].ability.extra = G.Bakery_charm_area.cards[1].ability.extra
SMODS.Mods.Roland.config = require "config"
---@type userdata|{getWidth: fun(self: self): number}
SMODS.Atlas.image_data = SMODS.Atlas.image_data
--- @type table
Talisman = Talisman
--- @type fun(obj: any): number
to_number = to_number
-- This exists to remove the @deprecated warning.
---Returns the elements from the given `list`. This function is equivalent to
---```lua

View file

@ -1,59 +1,5 @@
local f = assert(SMODS.load_file "src/lib/funky.lua")() or require "lib.funky"
---@param v string
---@return Card|Tag
local function add(v)
if not G.P_TAGS[v] then
return SMODS.add_card {no_edition = true, key = v}
end
local tag = Tag(v)
if tag.name == "Orbital Tag" then
local hands = f(G.GAME.hands):where "visible":keys():table()
tag.ability.orbital_hand = pseudorandom_element(hands, pseudoseed "Roland_c_orbital_tag")
end
add_tag(tag)
return tag
end
local function simplify(x)
return type(x) == "string" and x:lower():gsub("%s", ""):gsub("_", ""):gsub("^the", "") or x
end
local function flatten(v)
return type(v) ~= "table" and {v} or (f.isf(v) and v:table() or v)
end
---@param it string
local function find(it)
if (G.P_CENTERS[it] or {}).config then
return it
end
local match = simplify(it)
local pool = f(G.P_CENTER_POOLS):any(f.chain(f.arg(2), simplify, f.eq(match)))
if type(pool) == "table" and next(pool) then
return pseudorandom_element(pool, pseudoseed "Roland_c").key
end
if Cryptid and Cryptid.aliases and Cryptid.aliases[it] then
return Cryptid.aliases[it]
end
return f(G.localization.descriptions)
:flatmap(flatten)
:where(type, "table")
:where(f.chain(f.arg(2), f.index_into(G.P_CENTERS), "config"))
:where(function(v, k)
return match == simplify(k) or match == simplify(v.name)
end)
:keys()
:any()
end
local function protect(fun)
return function()
local res, ret = pcall(fun)
@ -75,13 +21,14 @@ local function protect_ev(fun)
return Event {
blocking = false,
no_delete = true,
func = protect(function()
func = function()
if not Bakery_API or not Bakery_API.credit then
return false
end
Bakery_API.credit(fun)
end),
return true
end,
}
else
fun.func = protect(fun.func or fun[1])
@ -110,35 +57,4 @@ local function u()
G.STATE ~= G.STATES.PLAY_TAROT)
end
--- Creates one or more cards.
---@param ... any
---@return Card|Tag|(Card|Tag[])
local function c(...)
local cards = f {...}
:flatmap(flatten)
:where(type, "string")
:map(string.lower)
:map(find)
:where(f.id)
:map(add)
:values()
:table()
return #cards > 1 and cards or cards[1]
end
return {f, q, u, setmetatable({}, {
__call = function(_, ...)
return c(...)
end,
__index = function(_, k)
return c(k)
end,
__newindex = function(_, k, v)
local n = tonumber(v)
for _ = 1, type(n) == "number" and n or 1 do
c(k)
end
end,
})}
return {f, q, u}

View file

@ -52,32 +52,18 @@ q {
-- G.ARGS.LOC_COLOURS["Bakery_credit_bg_Roland_" .. k] = v.bg
end)
if not SMODS.Mods.DebugPlus or not SMODS.Mods.Roland.config.import_funky then
return
if SMODS.Mods.DebugPlus and SMODS.Mods.Roland.config.import_funky then
_G.f, _G.q, _G.u = unpack(qol)
end
_G.f, _G.q, _G.u, _G.c = unpack(qol)
end,
}
f {
"challenge",
"spectral",
"edition",
"tweaks",
"blind",
"charm",
"joker",
"tarot",
"back",
"seal",
"tag",
"voucher",
}:each(function(v)
f {"challenge", "spectral", "edition", "tweaks", "blind", "charm", "joker", "tarot", "back", "seal", "tag"}
:each(function(v)
assert(SMODS.load_file("src/" .. v .. ".lua"))(qol)
end)
end)
if Balatest then
if _G["Balatest"] then
f {"joker", "blind", "spectral"}:each(function(v)
assert(SMODS.load_file("src/tests/" .. v .. ".tests.lua"))(qol)
end)
@ -121,7 +107,7 @@ function SMODS.current_mod.config_tab()
toggle "equinox_assist",
SMODS.Mods.DebugPlus and toggle "import_funky",
G.P_CENTERS.c_Bakery_Scribe and toggle "scribable_basket",
Talisman and toggle "harsh_ante_scaling",
_G["Talisman"] and toggle "harsh_ante_scaling",
},
}},
}

View file

@ -69,15 +69,15 @@ spectral {
table.insert(info_queue, G.P_CENTERS.m_stone)
end,
can_use = function()
return next(G.hand.cards) and u()
return u() and not not next(G.hand.cards)
end,
use = function(_, card)
q {
trigger = "after",
delay = 0.4,
func = function()
card:juice_up(0.3, 0.5)
play_sound("tarot1")
card:juice_up(0.3, 0.5)
end,
}
@ -89,8 +89,8 @@ spectral {
delay = 0.15,
func = function()
v:flip()
v:juice_up(0.3, 0.3)
play_sound("card1", percent)
v:juice_up(0.3, 0.3)
return true
end,
}
@ -110,8 +110,8 @@ spectral {
delay = 0.15,
func = function()
v:flip()
v:juice_up(0.3, 0.3)
play_sound("tarot2", percent, 0.6)
v:juice_up(0.3, 0.3)
return true
end,
}
@ -155,7 +155,7 @@ spectral {
return {vars = {card.ability.extra.amount}}
end,
can_use = function()
return next(G.playing_cards) and u()
return #G.playing_cards > 1 and not not u()
end,
use = function(_, card)
local function destructible(v)

View file

@ -192,9 +192,9 @@ Balatest.TestPlay {
}
Balatest.TestPlay {
category = {"blind", "mitotic"},
name = "mitotic",
blind = "bl_Roland_mitotic",
category = {"blind", "xerox"},
name = "xerox",
blind = "bl_Roland_xerox",
execute = function()
Balatest.discard {"2S"}
end,
@ -204,9 +204,9 @@ Balatest.TestPlay {
}
Balatest.TestPlay {
category = {"blind", "mitotic"},
name = "mitotic_disabled",
blind = "bl_Roland_mitotic",
category = {"blind", "xerox"},
name = "xerox_disabled",
blind = "bl_Roland_xerox",
jokers = {"j_chicot"},
execute = function()
Balatest.discard {"2S"}

View file

@ -2,6 +2,330 @@ if not Balatest then
return
end
Balatest.TestPlay {
category = {"joker", "escapey", "escape"},
name = "escapey_none",
jokers = {"j_Roland_escapey"},
execute = function() end,
assert = function()
Balatest.assert(not G.jokers.cards[1].config.center:Bakery_can_use(G.jokers.cards[1]))
end,
}
Balatest.TestPlay {
category = {"joker", "escapey", "escape"},
name = "escapey_one_consumable",
jokers = {"j_Roland_escapey"},
consumeables = {"c_strength"},
execute = function()
Balatest.q(function()
G.FUNCS.Bakery_use_joker {config = {ref_table = G.jokers.cards[1]}}
end)
Balatest.wait()
end,
assert = function()
Balatest.assert_eq(G.GAME.hands["High Card"].level, 2)
end,
}
Balatest.TestPlay {
category = {"joker", "escapey", "escape"},
name = "escapey_two_consumables",
jokers = {"j_Roland_escapey"},
consumeables = {"c_strength", "c_strength"},
execute = function()
Balatest.q(function()
G.FUNCS.Bakery_use_joker {config = {ref_table = G.jokers.cards[1]}}
end)
Balatest.wait()
end,
assert = function()
Balatest.assert_eq(G.GAME.hands["High Card"].level, 3)
end,
}
Balatest.TestPlay {
category = {"joker", "escapey", "escape"},
name = "escapey_one_tag",
jokers = {"j_Roland_escapey"},
no_auto_start = true,
execute = function()
Balatest.skip_blind("tag_investment")
Balatest.q(function()
G.FUNCS.Bakery_use_joker {config = {ref_table = G.jokers.cards[1]}}
end)
Balatest.wait()
end,
assert = function()
Balatest.assert_eq(G.GAME.hands["High Card"].level, 2)
end,
}
Balatest.TestPlay {
category = {"joker", "escapey", "escape"},
name = "escapey_two_tags",
jokers = {"j_Roland_escapey"},
no_auto_start = true,
execute = function()
Balatest.skip_blind("tag_investment")
Balatest.skip_blind("tag_investment")
Balatest.q(function()
G.FUNCS.Bakery_use_joker {config = {ref_table = G.jokers.cards[1]}}
end)
Balatest.wait()
end,
assert = function()
Balatest.assert_eq(G.GAME.hands["High Card"].level, 3)
end,
}
Balatest.TestPlay {
category = {"joker", "escapey", "escape"},
name = "escapey_consumables_and_tags",
jokers = {"j_Roland_escapey"},
consumeables = {"c_strength"},
no_auto_start = true,
execute = function()
Balatest.skip_blind("tag_investment")
Balatest.skip_blind("tag_investment")
Balatest.q(function()
G.FUNCS.Bakery_use_joker {config = {ref_table = G.jokers.cards[1]}}
end)
Balatest.wait()
end,
assert = function()
Balatest.assert_eq(G.GAME.hands["High Card"].level, 2)
end,
}
Balatest.TestPlay {
category = {"joker", "escapey", "escape"},
name = "escapey_partial_selected_consumables_and_tags",
jokers = {"j_Roland_escapey"},
consumeables = {"c_strength", "c_strength"},
no_auto_start = true,
execute = function()
Balatest.skip_blind("tag_investment")
Balatest.skip_blind("tag_investment")
Balatest.q(function()
G.consumeables:add_to_highlighted(G.consumeables.cards[1])
end)
Balatest.wait()
Balatest.q(function()
G.FUNCS.Bakery_use_joker {config = {ref_table = G.jokers.cards[1]}}
end)
Balatest.wait()
end,
assert = function()
Balatest.assert_eq(G.GAME.hands["High Card"].level, 2)
end,
}
Balatest.TestPlay {
category = {"joker", "escapey", "escape"},
name = "escapey_full_selected_consumables_and_tags",
jokers = {"j_Roland_escapey"},
consumeables = {"c_strength"},
no_auto_start = true,
execute = function()
Balatest.skip_blind("tag_investment")
Balatest.skip_blind("tag_investment")
Balatest.q(function()
G.consumeables:add_to_highlighted(G.consumeables.cards[1])
end)
Balatest.wait()
Balatest.q(function()
G.FUNCS.Bakery_use_joker {config = {ref_table = G.jokers.cards[1]}}
end)
Balatest.wait()
end,
assert = function()
Balatest.assert_eq(G.GAME.hands["High Card"].level, 3)
end,
}
Balatest.TestPlay {
category = {"joker", "escapey", "fuse"},
name = "escapey_fusion",
jokers = {"j_Roland_escapey", "j_Roland_escapey"},
execute = function()
Balatest.q(function()
G.FUNCS.Bakery_use_joker {config = {ref_table = G.jokers.cards[1]}}
end)
Balatest.wait()
end,
assert = function()
Balatest.assert_eq(#G.jokers.cards, 1)
Balatest.assert_eq(G.jokers.cards[1].sell_cost, 8)
Balatest.assert_eq(G.jokers.cards[1].ability.extra.levels, 2)
end,
}
Balatest.TestPlay {
category = {"joker", "escapey", "fuse"},
name = "escapey_consumable_takes_precedence",
jokers = {"j_Roland_escapey", "j_Roland_escapey"},
consumeables = {"c_strength"},
execute = function()
Balatest.q(function()
G.FUNCS.Bakery_use_joker {config = {ref_table = G.jokers.cards[1]}}
end)
Balatest.wait()
end,
assert = function()
Balatest.assert_eq(#G.jokers.cards, 2)
Balatest.assert_eq(G.GAME.hands["High Card"].level, 2)
end,
}
Balatest.TestPlay {
category = {"joker", "escapey", "fuse"},
name = "escapey_tag_takes_precedence",
jokers = {"j_Roland_escapey", "j_Roland_escapey"},
no_auto_start = true,
execute = function()
Balatest.skip_blind("tag_investment")
Balatest.q(function()
G.FUNCS.Bakery_use_joker {config = {ref_table = G.jokers.cards[1]}}
end)
Balatest.wait()
end,
assert = function()
Balatest.assert_eq(#G.jokers.cards, 2)
Balatest.assert_eq(G.GAME.hands["High Card"].level, 2)
end,
}
Balatest.TestPlay {
category = {"joker", "escapey", "fuse"},
name = "escapey_fusion_takes_precedence",
jokers = {"j_Roland_escapey", "j_Roland_escapey"},
consumeables = {"c_strength"},
execute = function()
Balatest.q(function()
G.consumeables:add_to_highlighted(G.consumeables.cards[1])
end)
Balatest.wait()
Balatest.q(function()
G.FUNCS.Bakery_use_joker {config = {ref_table = G.jokers.cards[1]}}
end)
Balatest.wait()
end,
assert = function()
Balatest.assert_eq(#G.jokers.cards, 1)
Balatest.assert_eq(G.jokers.cards[1].sell_cost, 8)
Balatest.assert_eq(G.jokers.cards[1].ability.extra.levels, 2)
end,
}
Balatest.TestPlay {
category = {"joker", "escapey", "fuse"},
name = "escapey_scribe_fusion",
jokers = {"j_Roland_escapey"},
execute = function()
if not G.P_CENTERS.c_Bakery_Scribe then
sendWarnMessage("escapey_scribe_fusion cannot run without c_Bakery_Scribe, skipping test.")
return
end
Balatest.q(function()
local scribe = create_card(nil, G.consumeables, nil, nil, nil, nil, "c_Bakery_Scribe", "balatest")
scribe:add_to_deck()
G.consumeables:emplace(scribe)
end)
Balatest.wait()
Balatest.q(function()
G.jokers:add_to_highlighted(G.jokers.cards[1])
end)
Balatest.wait()
Balatest.use(function() return G.consumeables.cards[1] end)
Balatest.q(function()
G.FUNCS.Bakery_use_joker {config = {ref_table = G.jokers.cards[1]}}
end)
Balatest.wait()
end,
assert = function()
if not G.P_CENTERS.c_Bakery_Scribe then
return
end
Balatest.assert_eq(#G.jokers.cards, 1)
Balatest.assert_eq(G.jokers.cards[1].sell_cost, 8)
Balatest.assert_eq(G.jokers.cards[1].ability.extra.levels, 1)
end,
}
Balatest.TestPlay {
category = {"joker", "escapey", "fuse"},
name = "escapey_scribe_fusion_alt",
jokers = {"j_Roland_escapey"},
execute = function()
if not G.P_CENTERS.c_Bakery_Scribe then
sendWarnMessage("escapey_scribe_fusion_alt cannot run without c_Bakery_Scribe, skipping test.")
return
end
Balatest.q(function()
local scribe = create_card(nil, G.consumeables, nil, nil, nil, nil, "c_Bakery_Scribe", "balatest")
scribe:add_to_deck()
G.consumeables:emplace(scribe)
end)
Balatest.wait()
Balatest.q(function()
G.jokers:add_to_highlighted(G.jokers.cards[1])
end)
Balatest.wait()
Balatest.use(function() return G.consumeables.cards[1] end)
Balatest.q(function()
G.jokers:add_to_highlighted(G.jokers.cards[2])
G.FUNCS.Bakery_use_joker {config = {ref_table = G.jokers.cards[2]}}
end)
Balatest.wait()
end,
assert = function()
if not G.P_CENTERS.c_Bakery_Scribe then
return
end
Balatest.assert_eq(#G.jokers.cards, 1)
Balatest.assert_eq(G.jokers.cards[1].sell_cost, 8)
Balatest.assert_eq(G.jokers.cards[1].ability.extra.levels, 1)
end,
}
Balatest.TestPlay {
category = {"joker", "martingale"},
name = "martingale_oops",
@ -10,7 +334,7 @@ Balatest.TestPlay {
Balatest.play_hand {"2S"}
end,
assert = function()
Balatest.assert_chips(7)
Balatest.assert_chips(7 * 2)
end,
}
@ -23,6 +347,6 @@ Balatest.TestPlay {
Balatest.play_hand {"2S"}
end,
assert = function()
Balatest.assert_chips(1 / 0)
Balatest.assert_chips(7 * math.pow(2, 32))
end,
}

View file

@ -2,6 +2,22 @@ if not Balatest then
return
end
Balatest.TestPlay {
category = {"spectral", "afterimage"},
name = "afterimage",
consumeables = {"c_Roland_afterimage"},
deck = {cards = {{s = "S", r = "2"}}},
execute = function()
Balatest.highlight({"2S"})
Balatest.use(G.consumeables.cards[1])
Balatest.end_round()
end,
assert = function()
Balatest.assert_eq(G.hand.config.card_limit, 51)
Balatest.assert(G.deck.cards[1].edition.negative)
end,
}
Balatest.TestPlay {
category = {"spectral", "void"},
name = "spectral",

View file

@ -2,16 +2,11 @@ local f, q = (... or require "lib.shared")[1], (... or require "lib.shared")[2]
SMODS.Joker:take_ownership("joker", {cost = 1}, true)
local orig_set_debuff = Card.set_debuff
function Card:set_debuff(should_debuff, ...)
if self.ability.Roland_crimson ~= nil then
self.ability.Roland_crimson = not not should_debuff
return
end
function Card:set_debuff(...)
if SMODS.get_enhancements(self).m_wild and SMODS.Mods.Roland.config.no_wild_debuff then
self.debuff = false
else
orig_set_debuff(self, should_debuff, ...)
orig_set_debuff(self, ...)
end
end
@ -67,10 +62,7 @@ function G.FUNCS.use_card(e, ...)
discover_card(ref.config.center)
ref:use_consumeable(ref.area)
SMODS.calculate_context {area = ref.area, consumeable = ref, using_consumeable = true}
q(function()
ref:remove()
end)
if normal then
return
@ -102,11 +94,11 @@ local orig_get_blind_amount = get_blind_amount
---@param ante number
---@return table|number
local function blind(ante)
return ante == 39 and 1e294 or (to_number or f.id)(orig_get_blind_amount(ante))
return ante == 39 and 1e294 or (_G["to_number"] or f.id)(orig_get_blind_amount(ante))
end
local function no_harsh_ante_scaling()
return not Talisman or not SMODS.Mods.Roland.config.harsh_ante_scaling
return not _G["Talisman"] or not SMODS.Mods.Roland.config.harsh_ante_scaling
end
function get_blind_amount(ante, ...)
@ -120,10 +112,10 @@ function get_blind_amount(ante, ...)
return 1 / 0
end
local rem = tonumber(blind((ante % loop) + 1))
local big, rem = _G["Big"], tonumber(blind((ante % loop) + 1))
return ante / 15 >= loop and Big:new(f(blind(ante - (loop * 15))):map(f.const(10)):table()) or
(ante / 9 >= loop and Big:new(f(ante / loop - 8):map(f.const(10)):concat {rem}:table()) or
(ante / 2 >= loop and Big:new {rem, ante / loop} or
(Big.constants and Big.constants.TEN or Big:new {10}):pow(rem)))
return ante / 15 >= loop and big:new(f(blind(ante - (loop * 15))):map(f.const(10)):table()) or
(ante / 9 >= loop and big:new(f(ante / loop - 8):map(f.const(10)):concat {rem}:table()) or
(ante / 2 >= loop and big:new {rem, ante / loop} or
(big.constants and big.constants.TEN or big:new {10}):pow(rem)))
end

View file

@ -1,44 +0,0 @@
local voucher = (function()
local x = 0
---@param tbl SMODS.Voucher|{attributes: Attributes[]}
---@return SMODS.Voucher
return function(tbl)
tbl.pos = {x = x, y = 0}
tbl.atlas = "voucher"
tbl.cost = 10
x = x + 1
return SMODS.Voucher(tbl)
end
end)()
SMODS.Atlas {
px = 71,
py = 95,
key = "voucher",
path = "voucher.png",
}
voucher {
key = "ceres",
pronouns = "it_its",
config = {extra = {amount = 1, hand_type = "Flush House"}},
attributes = {"planet", "passive", "hand_type", "space"},
loc_vars = function(_, _, card)
return {vars = {card.ability.extra.amount}}
end,
in_pool = function(self)
return G.GAME.hands[self.config.extra.hand_type].visible
end,
}
voucher {
key = "neptune",
pronouns = "it_its",
requires = {"v_Roland_ceres"},
config = {extra = {amount = 2, hand_type = "Straight Flush"}},
attributes = {"planet", "passive", "hand_type", "space"},
loc_vars = function(_, _, card)
return {vars = {card.ability.extra.amount}}
end,
}