Compare commits

..

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

20 changed files with 146 additions and 523 deletions

View file

@ -1,52 +0,0 @@
# Roland
[![License](https://img.shields.io/github/license/Emik03/Roland.svg?color=6272a4&style=for-the-badge)](https://github.com/Emik03/Roland/blob/main/LICENSE)
This is a [Steamodded](https://github.com/Steamodded/smods) mod for the video game [Balatro (2024)](https://playbalatro.com).
This mod has been in the works since early 2025, and been worked on continously until its official public release as a celebration for my 23rd birthday.
---
- [About](#about)
- [Contents](#contents)
- [Installation](#installation)
- [License](#license)
---
## About
The main theme of this mod centers around the addition of a new edition: Frozen.
Frozen can be applied to playing cards or jokers and will cause whatever state they have to be locked in place, removing any possibility of future scaling; positive or negative.
The primary goal is to create interesting interactions in-and-outside of the added editions. This does not necessarily mean that these mechanics have to be balanced, but does hopefully make new strategies viable and breathe new life into some of the base game's weaker jokers. It is designed to work very well with its parent mod [Bakery](https://github.com/BakersDozenBagels/BalatroBakery), but can work just as well on its own or with other content mods.
The mod offers a config for accessibility options, general convenience, modifications that I believe make the game healthier, and otherwise purely cosmetic.
## Contents
- 31 Jokers
- 1 Tarot Card
- 4 Spectral Cards
- 2 Vouchers
- 1 Seal
- 1 Edition
- 2 Tags
- 9 Blinds
- 4 Decks
- 4 [Deck Sleeves (CardSleeves)](https://github.com/larswijn/CardSleeves)
- 5 [Charms (Bakery)](https://github.com/BakersDozenBagels/BalatroBakery)
## Installation
1. Set up [Steamodded](https://github.com/Steamodded/smods/wiki#i-want-to-play-with-mods).
2. Set up [Bakery](https://github.com/BakersDozenBagels). You are free to use the [Lite version](https://github.com/BakersDozenBagels/BalatroBakery/tree/lite) if you want to play Roland standalone.
3. Clone the repository into your mods folder, or download it as a zip and place it there.
## License
This repository falls under the [MPL-2 license](https://www.mozilla.org/en-US/MPL/2.0/).
You may copy individual or multiple source files, granted that you keep the copyright license, and disclose the source back to this repository.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 85 KiB

View file

@ -414,16 +414,6 @@ return {
text = {"{X:red,C:white}X#1#{} discards each round"}, text = {"{X:red,C:white}X#1#{} discards each round"},
unlock = {"Defeat {C:dark_edition}#1#"}, unlock = {"Defeat {C:dark_edition}#1#"},
}, },
j_Roland_yard = {
name = "Yard Sale",
text = {
"Gain {C:money}$#1#{} when a",
"card is {C:attention}added",
"or {C:attention}removed",
"from the deck",
},
unlock = {"Complete the", "{C:attention}#1#", "challenge"},
},
}, },
Other = { Other = {
roland_glass_seal = { roland_glass_seal = {
@ -604,7 +594,7 @@ return {
c_Roland_Jokerful = "Jokerful", c_Roland_Jokerful = "Jokerful",
c_Roland_Pastries = "Sweet Pastries", c_Roland_Pastries = "Sweet Pastries",
c_Roland_Spin_To_Win = "Spin to Win", c_Roland_Spin_To_Win = "Spin to Win",
c_Roland_Spring_Cleaning = "Spring Cleaning", c_Roland_Yard_Sale = "Yard Sale",
}, },
v_dictionary = { v_dictionary = {
b_Roland_add = "ADD", b_Roland_add = "ADD",
@ -644,6 +634,8 @@ return {
ch_c_Roland_Eternally_Violet = {"{C:attention}Violet Vessel{}'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_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 2{} chance to gain {C:dark_edition}Glass Seal"},
ch_c_Roland_Yard_Sale1 = {"Gain {C:money}$5 {}when playing cards are {C:attention}added {}or {C:attention}removed"},
ch_c_Roland_Yard_Sale2 = {"Earn {C:red}no money {}from any other source"},
ch_c_Roland_Go = {"Set money to {C:money}$0 {}when entering the shop"}, 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_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"}, ch_c_Roland_Pastries = {"All blinds, cards, and tags are of {C:gold}Bakery{} or {C:blue}Roland"},
@ -652,7 +644,6 @@ return {
ch_c_Roland_Showdown_Crimson = {"Showdown blinds are {C:attention}Crimson Heart {}(stacks with above)"}, ch_c_Roland_Showdown_Crimson = {"Showdown blinds are {C:attention}Crimson Heart {}(stacks with above)"},
ch_c_Roland_Showdown_Verdant = {"Showdown blinds are {C:attention}Verdant Leaf {}(stacks with above)"}, ch_c_Roland_Showdown_Verdant = {"Showdown blinds are {C:attention}Verdant Leaf {}(stacks with above)"},
ch_c_Roland_Showdown_Violet = {"Showdown blinds are {C:attention}Violet Vessel {}(stacks with above)"}, ch_c_Roland_Showdown_Violet = {"Showdown blinds are {C:attention}Violet Vessel {}(stacks with above)"},
ch_c_Roland_Spring_Cleaning = {"Earn {C:red}no money {}from sources other than {C:attention}Yard Sale"},
}, },
}, },
} }

View file

@ -65,18 +65,6 @@ position = "at"
payload = "elseif G.GAME.blind_on_deck == 'Big' then" payload = "elseif G.GAME.blind_on_deck == 'Big' then"
match_indent = true match_indent = true
# Prevent Incantation from overriding Faster Planets
[[patches]]
[patches.pattern]
target = '=[SMODS incantation "Incantation.lua"]'
pattern = "function Card:use_consumeable(area, copier)"
position = "after"
payload = """if SMODS.Mods.Roland.config.faster_planets and
self.ability.consumeable.hand_type then
return useconsumeref(self, area, copier)
end"""
match_indent = true
# Misfortune Cookie # Misfortune Cookie
[[patches]] [[patches]]
[patches.pattern] [patches.pattern]
@ -95,7 +83,7 @@ pattern = "local card = create_card('Tarot',G.consumeables, nil, nil, nil, nil,
position = "after" position = "after"
times = 1 times = 1
payload = """if next(SMODS.find_card "j_Roland_misfortune") then payload = """if next(SMODS.find_card "j_Roland_misfortune") then
card:set_edition("e_negative", true, true) card:set_edition "e_negative"
end""" end"""
match_indent = true match_indent = true
@ -117,7 +105,7 @@ target = "card.lua"
pattern = "local card = create_card(card_type,G.consumeables, nil, nil, nil, nil, _planet, 'blusl')" pattern = "local card = create_card(card_type,G.consumeables, nil, nil, nil, nil, _planet, 'blusl')"
position = "after" position = "after"
payload = """if next(SMODS.find_card "j_Roland_misfortune") then payload = """if next(SMODS.find_card "j_Roland_misfortune") then
card:set_edition("e_negative", true, true) card:set_edition "e_negative"
end""" end"""
match_indent = true match_indent = true

View file

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

View file

@ -40,7 +40,7 @@ local back = (function()
return ret return ret
end, end,
apply = function(self, ...) apply = function(self, ...)
return save((tbl.alt_apply and self:is_alt() and tbl.alt_apply or apply)(self, ...)) return (tbl.alt_apply and self:is_alt() and tbl.alt_apply or apply)(self, ...)
end, end,
calculate = function(self, ...) calculate = function(self, ...)
return (tbl.alt_calculate and self:is_alt() and tbl.alt_calculate or calculate)(self, ...) return (tbl.alt_calculate and self:is_alt() and tbl.alt_calculate or calculate)(self, ...)
@ -80,10 +80,10 @@ back {
pronouns = "any_all", pronouns = "any_all",
config = {extra = {alt_times = 9, times = 3}}, config = {extra = {alt_times = 9, times = 3}},
attributes = {"passive", "boss_blind"}, attributes = {"passive", "boss_blind"},
loc_vars = function(self) loc_vars = function(self, _, _)
return {vars = {self.config.extra.alt_times}} return {vars = {self.config.extra.alt_times}}
end, end,
apply = function() apply = function(_, _)
G.GAME.modifiers.Roland_blossom_deck = true G.GAME.modifiers.Roland_blossom_deck = true
end, end,
calculate = function(self, b, context) calculate = function(self, b, context)

View file

@ -257,7 +257,7 @@ blind {
boss = {min = 6}, boss = {min = 6},
boss_colour = HEX "bdaeccff", boss_colour = HEX "bdaeccff",
pronouns = "they_them", pronouns = "they_them",
collection_loc_vars = function() collection_loc_vars = function(_)
return { return {
vars = {localize { vars = {localize {
type = "variable", type = "variable",
@ -265,7 +265,7 @@ blind {
}}, }},
} }
end, end,
loc_vars = function() loc_vars = function(_)
local _, name = common_rank() local _, name = common_rank()
return {vars = {localize(name or "Ace", "ranks")}} return {vars = {localize(name or "Ace", "ranks")}}
end, end,
@ -319,7 +319,7 @@ blind {
dollars = 5, dollars = 5,
defeat = disable_improbable, defeat = disable_improbable,
disable = disable_improbable, disable = disable_improbable,
set_blind = function() set_blind = function(_)
G.GAME.modifiers.Roland_improbable = true G.GAME.modifiers.Roland_improbable = true
end, end,
} }
@ -380,7 +380,7 @@ function SMODS.current_mod:calculate(context)
:map(f.index_into(G.P_CENTERS)) :map(f.index_into(G.P_CENTERS))
:where("config.extra.hand_type", context.scoring_name) :where("config.extra.hand_type", context.scoring_name)
:pun "SMODS.Voucher" :pun "SMODS.Voucher"
:each(function(v) :each(function(v, _)
SMODS.smart_level_up_hand(nil, v.config.extra.hand_type, false, v.config.extra.amount) SMODS.smart_level_up_hand(nil, v.config.extra.hand_type, false, v.config.extra.amount)
end) end)

View file

@ -40,7 +40,7 @@ end
---@param v SMODS.GameObject ---@param v SMODS.GameObject
---@return boolean|string ---@return boolean|string
local function is_economy(v) local function is_economy(v)
return f(Bakery_API.econ_only_items):where(f.eq(v.key)):any() return f(Bakery_API.econ_only_items):where(f.id, v.key):any()
end end
---@param key string ---@param key string
@ -82,22 +82,26 @@ SMODS.Challenge {
end, end,
} }
local yard_sale
SMODS.Challenge { SMODS.Challenge {
key = "Spring_Cleaning", key = "Yard_Sale",
config = {no_interest = true}, config = {extra = {dollars = 5}, no_interest = true},
consumeables = {{id = "c_hanged_man"}},
jokers = {{id = "j_Roland_yard"}, {id = "j_Roland_yard"}},
vouchers = {{id = "v_magic_trick"}, {id = "v_overstock_norm"}}, vouchers = {{id = "v_magic_trick"}, {id = "v_overstock_norm"}},
rules = {custom = {{id = "Roland_Spring_Cleaning"}}}, rules = {custom = multirule("Yard_Sale", 2), modifiers = {{id = "dollars", value = 14}}},
restrictions = yard, restrictions = yard,
apply = function() apply = function()
G.GAME.modifiers.no_blind_reward = {Small = true, Big = true, Boss = true} G.GAME.modifiers.no_blind_reward = {Small = true, Big = true, Boss = true}
G.GAME.modifiers.no_extra_hand_money = true G.GAME.modifiers.no_extra_hand_money = true
f(Bakery_API.econ_only_items):keys():where(f.nq "j_Roland_yard"):each(function(v) f(Bakery_API.econ_only_items):keys():each(function(v)
G.GAME.banned_keys[v] = true G.GAME.banned_keys[v] = true
end) end)
end, end,
calculate = function(self, context)
yard_sale = (context.playing_card_added or context.remove_playing_cards) and not context.blueprint
return yard_sale and {dollars = self.config.extra.dollars * #(context.cards or context.removed or {})} or nil
end,
} }
SMODS.Challenge { SMODS.Challenge {
@ -338,14 +342,12 @@ q {
return false return false
end end
table.insert(Bakery_API.econ_only_items, "j_Roland_yard")
table.insert(Bakery_API.econ_only_items, "j_Roland_artemis")
local orig = Bakery_API.no_money_decks local orig = Bakery_API.no_money_decks
Bakery_API.no_money_decks = setmetatable({}, { Bakery_API.no_money_decks = setmetatable({}, {
orig = orig, orig = orig,
__index = function(_, k) __index = function(_, k)
return (G.GAME or {}).challenge == "c_Roland_Spring_Cleaning" or orig[k] return (G.GAME or {}).challenge == "c_Roland_Yard_Sale" and not yard_sale or orig[k]
end, end,
}) })

View file

@ -10,6 +10,11 @@ return {
fg = HEX "362708ff", fg = HEX "362708ff",
bg = HEX "edd198ff", bg = HEX "edd198ff",
}, },
char = {
name = "char (@irregulester)",
fg = HEX "f8f8f2ff",
bg = HEX "ff79c6ff",
},
ghostlyfield = { ghostlyfield = {
name = "ghostlyfield", name = "ghostlyfield",
fg = HEX "ffffffff", fg = HEX "ffffffff",

View file

@ -329,6 +329,8 @@ function Card:calculate_dollar_bonus(...)
return orig_calculate_dollar_bonus(self, ...) return orig_calculate_dollar_bonus(self, ...)
end end
local orig_get_probability_vars = SMODS.get_probability_vars
function SMODS.current_mod.bootstraps_mult(card) function SMODS.current_mod.bootstraps_mult(card)
local ability = card.Roland_frozen_ability local ability = card.Roland_frozen_ability
local ret = math.floor((G.GAME.dollars + (G.GAME.dollar_buffer or 0)) / card.ability.extra.dollars) local ret = math.floor((G.GAME.dollars + (G.GAME.dollar_buffer or 0)) / card.ability.extra.dollars)
@ -341,17 +343,9 @@ function SMODS.current_mod.bootstraps_mult(card)
return ability.Roland_bootstraps_mult return ability.Roland_bootstraps_mult
end end
local orig_get_probability_vars = SMODS.get_probability_vars
function SMODS.get_probability_vars(trigger_obj, ...) function SMODS.get_probability_vars(trigger_obj, ...)
local numerator, denominator = orig_get_probability_vars(trigger_obj, ...) local numerator, denominator = orig_get_probability_vars(trigger_obj, ...)
local override = ((trigger_obj or {}).Roland_frozen or {}).probability return trigger_obj and (trigger_obj.Roland_frozen or {}).probability or numerator, denominator
if override then
return type(denominator) == "table" and to_big(override) or override, denominator
else
return numerator, denominator
end
end end
q { q {

View file

@ -54,10 +54,25 @@ local joker = (function()
end end
end)() end)()
---@generic T
---@param tbl T[]
---@return fun(t: T[], i: integer): integer, T
---@return T[]
local function ipairs_reversed(tbl)
return function(t, i)
local k = i and i - 1 or #t
local v = t[k]
if v ~= nil then
return k, v
end
end, tbl
end
---@param card Card ---@param card Card
---@return boolean ---@return boolean
local function is_frozen(card) local function is_frozen(card)
return card and card.edition and card.edition.Roland_frozen return card and card.edition and card.edition.key == "e_Roland_frozen"
end end
---@param card? Card|false|{suit: string, value: string} ---@param card? Card|false|{suit: string, value: string}
@ -196,8 +211,8 @@ joker {
joker { joker {
key = "sunny", key = "sunny",
pronouns = "it_its", pronouns = "it_its",
artist = "char",
idea = "redstoad", idea = "redstoad",
artist = "ghostlyfield",
attributes = {"food", "on_sell"}, attributes = {"food", "on_sell"},
cost = 2, cost = 2,
rarity = 1, rarity = 1,
@ -218,8 +233,8 @@ joker {
SMODS.calculate_context {drawing_cards = true, draw = {G.deck.cards}} SMODS.calculate_context {drawing_cards = true, draw = {G.deck.cards}}
SMODS.calculate_context { SMODS.calculate_context {
hand_drawn = facing_blind and {G.deck.cards[1]} or true, hand_drawn = facing_blind and {G.deck.cards[1]} and true,
other_drawn = not facing_blind and {G.deck.cards[1]} or 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, first_hand_drawn = not current_round.any_hand_drawn and facing_blind or nil,
} }
@ -243,15 +258,14 @@ joker {
table.insert(info_queue, G.P_CENTERS.e_Roland_frozen) table.insert(info_queue, G.P_CENTERS.e_Roland_frozen)
end, end,
calculate = function(_, _, context) calculate = function(_, _, context)
return (context.selling_self or context.forcetrigger) and return (context.selling_self or context.forcetrigger) and f(G.hand.cards):each(function(v)
f(G.hand.cards):where("edition", false):each(function(v) q {
q { delay = 0.1,
delay = 0.1, func = function()
func = function() v:set_edition {Roland_frozen = true}
v:set_edition {Roland_frozen = true} end,
end, }
} end) or nil
end) or nil
end, end,
} }
@ -274,9 +288,7 @@ joker {
delay = 1, delay = 1,
func = function() func = function()
play_sound "timpani" play_sound "timpani"
SMODS.add_card {edition = "e_negative", key = v.config.center.key}
SMODS.add_card {edition = "e_negative", key = v.config.center.key, silent = true}
.ability.qty = v.ability.qty
end, end,
} }
end) or nil end) or nil
@ -286,7 +298,7 @@ joker {
joker { joker {
key = "monomino", key = "monomino",
pronouns = "it_its", pronouns = "it_its",
artist = "ghostlyfield", artist = "char",
config = {extra = {price = 4, hand_name = "Four of a Kind"}}, config = {extra = {price = 4, hand_name = "Four of a Kind"}},
attributes = {"sell_value", "scaling", "economy", "hand_type"}, attributes = {"sell_value", "scaling", "economy", "hand_type"},
cost = 4, cost = 4,
@ -315,7 +327,7 @@ joker {
joker { joker {
key = "domino", key = "domino",
pronouns = "it_its", pronouns = "it_its",
artist = "ghostlyfield", artist = "char",
config = {extra = {mult_gain = 4, hand_name = "Four of a Kind", mult = 0}}, config = {extra = {mult_gain = 4, hand_name = "Four of a Kind", mult = 0}},
attributes = {"mult", "scaling", "hand_type"}, attributes = {"mult", "scaling", "hand_type"},
cost = 4, cost = 4,
@ -346,7 +358,7 @@ joker {
joker { joker {
key = "trimino", key = "trimino",
pronouns = "it_its", pronouns = "it_its",
artist = "ghostlyfield", artist = "char",
config = {extra = {times = 4, hand_name = "Four of a Kind"}}, config = {extra = {times = 4, hand_name = "Four of a Kind"}},
attributes = {"generation", "hand_type"}, attributes = {"generation", "hand_type"},
cost = 8, cost = 8,
@ -405,7 +417,7 @@ joker {
joker { joker {
key = "misfortune", key = "misfortune",
pronouns = "she_they", pronouns = "she_they",
artist = "ghostlyfield", artist = "char",
attributes = {"discard", "passive", "tarot", "planet", "generation", "seals"}, attributes = {"discard", "passive", "tarot", "planet", "generation", "seals"},
cost = 6, cost = 6,
rarity = 2, rarity = 2,
@ -425,7 +437,6 @@ joker {
joker { joker {
key = "polaris", key = "polaris",
pronouns = "he_him", pronouns = "he_him",
artist = "ghostlyfield",
attributes = {"editions", "space"}, attributes = {"editions", "space"},
cost = 6, cost = 6,
rarity = 1, rarity = 1,
@ -498,7 +509,6 @@ joker {
joker { joker {
key = "snowsquall", key = "snowsquall",
pronouns = "he_they", pronouns = "he_they",
artist = "ghostlyfield",
config = {extra = {mult_gain = 3, mult = 0}}, config = {extra = {mult_gain = 3, mult = 0}},
attributes = {"mult", "scaling", "hand_type"}, attributes = {"mult", "scaling", "hand_type"},
cost = 6, cost = 6,
@ -530,37 +540,13 @@ joker {
end, end,
} }
---comment
---@param card Card
---@param context table|CalcContext
---@return function
local function copy(card, context)
---@param v Card
return function(v)
local override_compat = v.config.center.blueprint_compat == nil
if override_compat then
v.config.center.blueprint_compat = true
end
local ret = SMODS.blueprint_effect(card, v, context)
if override_compat then
v.config.center.blueprint_compat = nil
end
return ret
end
end
joker { joker {
key = "arctic", key = "arctic",
pronouns = "they_them", pronouns = "they_them",
artist = "ghostlyfield",
cost = 10, cost = 10,
rarity = 3, rarity = 3,
config = {extra = {frozen = 1, non_frozen = 0, color = "DARK_EDITION"}}, config = {extra = {frozen = 1, non_frozen = 0, max_stack = 6, color = "DARK_EDITION"}},
attributes = {"retrigger", "editions", "copying"}, attributes = {"retrigger", "editions"},
eternal_compat = true, eternal_compat = true,
blueprint_compat = true, blueprint_compat = true,
perishable_compat = true, perishable_compat = true,
@ -570,9 +556,9 @@ joker {
calculate = function(_, card, context) calculate = function(_, card, context)
local extra = card.ability.extra local extra = card.ability.extra
if f(context.blueprint_copiers_stack) if extra.max_stack and
:where("config.center.key", card.config.center.key) context.blueprint_copiers_stack and
:any() then extra.max_stack < #context.blueprint_copiers_stack then
return return
end end
@ -585,15 +571,14 @@ joker {
end end
return SMODS.merge_effects( return SMODS.merge_effects(
f(G) f(G.jokers.cards):where(is_frozen):where(function(v)
:where(getmetatable, CardArea) return v.config.center.key ~= card.config.center.key
:flatmap("cards", ipairs) end):map(function(v)
:where(is_frozen) return SMODS.blueprint_effect(card, v, context)
:map(copy(card, context)) end):where(type, "table"):map(function(v)
:where(type, "table") v.colour = G.C[extra.color]
:map(f.insert(G.C[extra.color], "colour")) return v
:values() end):values():table()
:table()
) )
end, end,
} }
@ -601,8 +586,8 @@ joker {
joker { joker {
key = "sapling", key = "sapling",
pronouns = "they_them", pronouns = "they_them",
artist = "char",
idea = "redstoad", idea = "redstoad",
artist = "ghostlyfield",
attributes = {"mult", "suit"}, attributes = {"mult", "suit"},
cost = 4, cost = 4,
rarity = 1, rarity = 1,
@ -735,9 +720,9 @@ joker {
{card = card, xmult = card.ability.extra.xmult} or nil {card = card, xmult = card.ability.extra.xmult} or nil
end, end,
crimson = function() crimson = function()
local _ = G.jokers and f(G.jokers.cards, f.revpairs):where(is_frozen, false):each(function(v) local _ = G.jokers and f(G.jokers.cards, ipairs_reversed):where(is_frozen, false):each(function(v)
local right = G.jokers.cards[v.rank + 1] local r = G.jokers.cards[v.rank + 1]
local debuffed_by_crimson = right and not right.debuff and right.config.center.key == "j_Roland_crimson" local debuffed_by_crimson = r and not r.debuff and r.config.center.key == "j_Roland_crimson"
if debuffed_by_crimson and v.ability.Roland_crimson == nil then if debuffed_by_crimson and v.ability.Roland_crimson == nil then
local debuff = not not v.debuff local debuff = not not v.debuff
@ -839,7 +824,6 @@ joker {
joker { joker {
key = "venerable", key = "venerable",
pronouns = "any_all", pronouns = "any_all",
artist = "ghostlyfield",
defeated_blind = "bl_Roland_venerable_visage", defeated_blind = "bl_Roland_venerable_visage",
config = {extra = {xdiscard = 3}}, config = {extra = {xdiscard = 3}},
pixel_size = {w = 68, h = 68}, pixel_size = {w = 68, h = 68},
@ -866,45 +850,11 @@ joker {
ease_discard(round_resets.discards - discards) ease_discard(round_resets.discards - discards)
end, end,
} }
joker {
key = "yard",
pronouns = "he_him",
artist = "ghostlyfield",
config = {extra = {dollars = 3}},
attributes = {"economy"},
cost = 6,
rarity = 1,
unlocked = true,
discovered = true,
eternal_compat = true,
blueprint_compat = true,
perishable_compat = true,
check_for_unlock = function()
return not not f.indices "challenge_progress.completed.c_Roland_Spring_Cleaning" (G.PROFILES[G.SETTINGS.profile])
end,
locked_loc_vars = function()
return {vars = {localize("c_Roland_Spring_Cleaning", "challenge_names")}}
end,
loc_vars = function(_, _, card)
return {vars = {card.ability.extra.dollars}}
end,
calculate = function(_, card, c)
local ret = (c.forcetrigger or c.playing_card_added or c.remove_playing_cards) and
{dollars = card.ability.extra.dollars * #(c.cards or c.removed or {c.forcetrigger})} or nil
if ret and (G.GAME or {}).challenge == "c_Roland_Spring_Cleaning" then
G.GAME.dollars = G.GAME.dollars + ret.dollars
else
return ret
end
end,
}
joker { joker {
key = "bulldozer", key = "bulldozer",
pronouns = "she_her", pronouns = "she_her",
idea = "redstoad", idea = "redstoad",
artist = "ghostlyfield",
attributes = {"xmult"}, attributes = {"xmult"},
cost = 6, cost = 6,
rarity = 2, rarity = 2,
@ -967,8 +917,8 @@ joker {
joker { joker {
key = "nilly", key = "nilly",
pronouns = "any_all", pronouns = "any_all",
idea = "redstoad",
artist = "ghostlyfield", artist = "ghostlyfield",
idea = "redstoad",
config = {extra = {flipped = false}}, config = {extra = {flipped = false}},
attributes = {"xmult", "bakery_double_sided"}, attributes = {"xmult", "bakery_double_sided"},
cost = 0, cost = 0,
@ -1004,7 +954,6 @@ joker {
key = "martingale", key = "martingale",
pronouns = "he_him", pronouns = "he_him",
idea = "redstoad", idea = "redstoad",
artist = "ghostlyfield",
config = {extra = {odds = 2}}, config = {extra = {odds = 2}},
attributes = {"xmult", "chance"}, attributes = {"xmult", "chance"},
cost = 8, cost = 8,
@ -1068,7 +1017,6 @@ joker {
joker { joker {
key = "idle", key = "idle",
pronouns = "any_all", pronouns = "any_all",
artist = "ghostlyfield",
rarity = 2, rarity = 2,
Roland_idle_capacity = 6, Roland_idle_capacity = 6,
cost = G.P_CENTERS.j_idol.cost, cost = G.P_CENTERS.j_idol.cost,
@ -1145,7 +1093,6 @@ joker {
joker { joker {
key = "suitable", key = "suitable",
pronouns = "she_they", pronouns = "she_they",
artist = "ghostlyfield",
attributes = {"suit", "passive", "hearts", "diamonds", "spades", "clubs"}, attributes = {"suit", "passive", "hearts", "diamonds", "spades", "clubs"},
cost = 4, cost = 4,
rarity = 2, rarity = 2,
@ -1198,8 +1145,8 @@ end
joker { joker {
key = "artemis", key = "artemis",
pronouns = "any_all", pronouns = "any_all",
idea = "redstoad",
artist = "hamester", artist = "hamester",
idea = "redstoad",
cost = 6, cost = 6,
rarity = 2, rarity = 2,
config = {extra = { config = {extra = {
@ -1265,7 +1212,6 @@ joker {
key = "excalibur", key = "excalibur",
pronouns = "he_him", pronouns = "he_him",
idea = "redstoad", idea = "redstoad",
artist = "ghostlyfield",
cost = 8, cost = 8,
rarity = 3, rarity = 3,
config = {extra = { config = {extra = {
@ -1337,7 +1283,7 @@ joker {
joker { joker {
key = "oops", key = "oops",
pronouns = "she_they", pronouns = "she_they",
artist = "ghostlyfield", artist = "char",
cost = 7, cost = 7,
rarity = 3, rarity = 3,
config = {extra = {probability = 1, probability_mult = 2, reset = 1}}, config = {extra = {probability = 1, probability_mult = 2, reset = 1}},
@ -1371,3 +1317,15 @@ joker {
end end
end, end,
} }
q {
blocking = false,
no_delete = true,
func = function()
if not Bakery_API then
return false
end
table.insert(Bakery_API.econ_only_items, "j_Roland_artemis")
end,
}

View file

@ -8,42 +8,6 @@
local f = {} local f = {}
if not f then if not f then
---@generic T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, R
---@param self F
---@param first? T1
---@param second? T2
---@param third? T3
---@param fourth? T4
---@param fifth? T5
---@param sixth? T6
---@param seventh? T7
---@param eighth? T8
---@param ninth? T9
---@param tenth? T10
---@return fun(v: fun(first: T1, second: T2, third: T3, fourth: T4, fifth: T5, sixth: T6, seventh: T7, eighth: T8, ninth: T9, tenth: T10): R): R
---@nodiscard
function f:call(first, second, third, fourth, fifth, sixth, seventh, eighth, ninth, tenth)
error {first, second, third, fourth, fifth, sixth, seventh, eighth, ninth, tenth}
end
---@generic T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, R
---@param self string
---@param first? T1
---@param second? T2
---@param third? T3
---@param fourth? T4
---@param fifth? T5
---@param sixth? T6
---@param seventh? T7
---@param eighth? T8
---@param ninth? T9
---@param tenth? T10
---@return fun(v: {[string]: fun(self: self, first: T1, second: T2, third: T3, fourth: T4, fifth: T5, sixth: T6, seventh: T7, eighth: T8, ninth: T9, tenth: T10): R}): R
---@nodiscard
function f.call(self, first, second, third, fourth, fifth, sixth, seventh, eighth, ninth, tenth)
error {self, first, second, third, fourth, fifth, sixth, seventh, eighth, ninth, tenth}
end
---@generic I, O ---@generic I, O
---@param first integer|string|fun(v: I): O ---@param first integer|string|fun(v: I): O
---@return fun(v: I): O ---@return fun(v: I): O
@ -134,96 +98,6 @@ if not f then
error(all) error(all)
end end
---@generic I, O
---@param first integer|string|fun(v: I): O
---@return fun(v: I): O
---@nodiscard
function f.compose(first)
error {first}
end
---@generic I, T, O
---@param first integer|string|fun(v: T): O
---@param second integer|string|fun(v: I): T
---@return fun(v: I): O
---@nodiscard
function f.compose(first, second)
error {first, second}
end
---@generic I, T1, T2, O
---@param first integer|string|fun(v: T2): O
---@param second integer|string|fun(v: T1): T2
---@param third integer|string|fun(v: I): T1
---@return fun(v: I): O
---@nodiscard
function f.compose(first, second, third)
error {first, second, third}
end
---@generic I, T1, T2, T3, O
---@param first integer|string|fun(v: T3): O
---@param second integer|string|fun(v: T2): T3
---@param third integer|string|fun(v: T1): T2
---@param fourth integer|string|fun(v: I): T1
---@return fun(v: I): O
---@nodiscard
function f.compose(first, second, third, fourth)
error {first, second, third, fourth}
end
---@generic I, T1, T2, T3, T4, O
---@param first integer|string|fun(v: T4): O
---@param second integer|string|fun(v: T3): T4
---@param third integer|string|fun(v: T2): T3
---@param fourth integer|string|fun(v: T1): T2
---@param fifth integer|string|fun(v: I): T1
---@return fun(v: I): O
---@nodiscard
function f.compose(first, second, third, fourth, fifth)
error {first, second, third, fourth, fifth}
end
---@generic I, O
---@param all { [1]: (integer|string|fun(v: I): O) }
---@return fun(v: I): O
---@nodiscard
function f.compose(all)
error(all)
end
---@generic I, T, O
---@param all { [1]: (integer|string|fun(v: T): O), [2]: (integer|string|fun(v: I): T) }
---@return fun(v: I): O
---@nodiscard
function f.compose(all)
error(all)
end
---@generic I, T1, T2, O
---@param all { [1]: (integer|string|fun(v: T2): O), [2]: (integer|string|fun(v: T1): T2), [3]: (integer|string|fun(v: I): T1) }
---@return fun(v: I): O
---@nodiscard
function f.compose(all)
error(all)
end
---@generic I, T1, T2, T3, O
---@param all { [1]: (integer|string|fun(v: T3): O), [2]: (integer|string|fun(v: T2): T3), [3]: (integer|string|fun(v: T1): T2), [4]: (integer|string|fun(v: I): T1) }
---@return fun(v: I): O
---@nodiscard
function f.compose(all)
error(all)
end
---@generic I, T1, T2, T3, T4, O
---@param all { [1]: (integer|string|fun(v: T4): O), [2]: (integer|string|fun(v: T3): T4), [3]: (integer|string|fun(v: T2): T3), [4]: (integer|string|fun(v: T1): T2), [4]: (integer|string|fun(v: I): T1) }
---@return fun(v: I): O
---@nodiscard
function f.compose(all)
error(all)
end
---@generic K, V ---@generic K, V
---@param self F | { [K]: V } ---@param self F | { [K]: V }
---@return K?, V? ---@return K?, V?
@ -295,7 +169,7 @@ end
---@generic T ---@generic T
---@param value T ---@param value T
---@return fun(v: T): boolean ---@return fun(T): boolean
---@nodiscard ---@nodiscard
function f.eq(value) function f.eq(value)
return function(v) return function(v)
@ -378,36 +252,6 @@ function f.indices(v)
end end
end end
---@generic K, V
---@param v V
---@param k K
---@return fun(x: { [K]: V }): { [K]: V }
---@nodiscard
function f.insert(v, k)
return function(x)
if type(x) == "table" then
x[k] = v
end
return x
end
end
---@generic T
---@param tbl T[]
---@return fun(t: T[], i?: integer): integer, T
---@return T[]
function f.revpairs(tbl)
return function(t, i)
local k = i and i - 1 or #t
local v = t[k]
if v ~= nil then
return k, v
end
end, tbl
end
---@param any any ---@param any any
---@return boolean ---@return boolean
---@nodiscard ---@nodiscard
@ -415,24 +259,10 @@ function f.isf(any)
return type(any) == "table" and any.from == f.from and any.new == f.new return type(any) == "table" and any.from == f.from and any.new == f.new
end end
local unpack = table.unpack or unpack
f[true and "call"] = function(self, ...)
local args = {...}
return type(self) == "string" and function(v)
return v[self](v, unpack(args))
end or function(v)
return v(unpack(args))
end
end
f[true and "chain"] = function(...) f[true and "chain"] = function(...)
local ret local ret
for _, v in ipairs {...} do for _, v in ipairs {...} do
v = f.isf(v) and v:table() or v
if type(v) == "table" then if type(v) == "table" then
for _, vv in ipairs(v) do for _, vv in ipairs(v) do
local copy = ret local copy = ret
@ -455,10 +285,6 @@ f[true and "chain"] = function(...)
return ret or f.noop return ret or f.noop
end end
f[true and "compose"] = function(...)
return f.chain(f.from({...}, f.revpairs):values())
end
---@generic K, V ---@generic K, V
---@param fnext? fun(): K?, V? ---@param fnext? fun(): K?, V?
---@return F|{ [K]: V } ---@return F|{ [K]: V }
@ -469,9 +295,7 @@ function f.new(fnext)
all = f.all, all = f.all,
any = f.any, any = f.any,
arg = f.arg, arg = f.arg,
call = f.call,
chain = f.chain, chain = f.chain,
compose = f.compose,
concat = f.concat, concat = f.concat,
const = f.const, const = f.const,
count = f.count, count = f.count,
@ -486,7 +310,6 @@ function f.new(fnext)
index = f.index, index = f.index,
index_into = f.index_into, index_into = f.index_into,
indices = f.indices, indices = f.indices,
insert = f.insert,
isf = f.isf, isf = f.isf,
keys = f.keys, keys = f.keys,
map = f.map, map = f.map,
@ -496,8 +319,6 @@ function f.new(fnext)
nq = f.nq, nq = f.nq,
peek = f.peek, peek = f.peek,
pun = f.pun, pun = f.pun,
rev = f.rev,
revpairs = f.revpairs,
skip = f.skip, skip = f.skip,
slice = f.slice, slice = f.slice,
string = f.string, string = f.string,
@ -556,10 +377,10 @@ function f.from(iter, fpairs, step)
end end
end) end)
else else
local next, tbl, k, v = autopairs(iter, type(fpairs) == "function" and fpairs or nil) local next, context, k, v = autopairs(iter, type(fpairs) == "function" and fpairs or nil)
return f.new(function() return f.new(function()
k, v = next(tbl, k) k, v = next(context, k)
return k, v return k, v
end) end)
end end
@ -571,14 +392,12 @@ end
---@return F|{ [K]: V } ---@return F|{ [K]: V }
---@nodiscard ---@nodiscard
function f:concat(...) function f:concat(...)
self = f.isf(self) and self or f.from(self)
local fsi = 0 local fsi = 0
local fs = {...} local fs = {...}
local sum, last = 0, 0 local sum, last = 0, 0
for i = 1, #fs do for i = 1, #fs do
local s = fs[i] fs[i] = f.isf(fs[i]) and fs[i] or f.from(fs[i])
fs[i] = f.isf(s) and s or f.from(s)
end end
return f.new(function() return f.new(function()
@ -612,7 +431,6 @@ end
---@return F|{ [K]: V } ---@return F|{ [K]: V }
---@nodiscard ---@nodiscard
function f:peek(func) function f:peek(func)
self = f.isf(self) and self or f.from(self)
func = autofunc(func) func = autofunc(func)
return f.new(function() return f.new(function()
@ -632,7 +450,6 @@ end
---@overload fun(self: F|{ [K]: V }, func: string): F|{ [K]: U } ---@overload fun(self: F|{ [K]: V }, func: string): F|{ [K]: U }
---@nodiscard ---@nodiscard
function f:map(func) function f:map(func)
self = f.isf(self) and self or f.from(self)
func = autofunc(func) func = autofunc(func)
return f.new(function() return f.new(function()
@ -652,14 +469,11 @@ end
---@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 } ---@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 ---@nodiscard
function f:flatmap(func, fpairs) function f:flatmap(func, fpairs)
self = f.isf(self) and self or f.from(self)
-- local i = 0 -- local i = 0
local vt, vk, vp local vt, vk, vv, vp
func = autofunc(func) func = autofunc(func)
return f.new(function() return f.new(function()
local vv
if vk then if vk then
vk, vv = vp(vt, vk) vk, vv = vp(vt, vk)
@ -705,7 +519,6 @@ end
---@nodiscard ---@nodiscard
---@overload fun(self: F|{ [K]: V }, func: string, is?: any): F|{ [K]: V } ---@overload fun(self: F|{ [K]: V }, func: string, is?: any): F|{ [K]: V }
function f:where(func, is) function f:where(func, is)
self = f.isf(self) and self or f.from(self)
func = autofunc(func) func = autofunc(func)
return f.new(function() return f.new(function()
@ -738,7 +551,6 @@ end
---@return F|{ [integer]: K } ---@return F|{ [integer]: K }
---@nodiscard ---@nodiscard
function f:keys() function f:keys()
self = f.isf(self) and self or f.from(self)
local i = 0 local i = 0
return f.new(function() return f.new(function()
@ -756,7 +568,6 @@ end
---@return F|{ [integer]: V } ---@return F|{ [integer]: V }
---@nodiscard ---@nodiscard
function f:values() function f:values()
self = f.isf(self) and self or f.from(self)
local i = 0 local i = 0
return f.new(function() return f.new(function()
@ -774,8 +585,6 @@ end
---@return F|{ [V]: K } ---@return F|{ [V]: K }
---@nodiscard ---@nodiscard
function f:swap() function f:swap()
self = f.isf(self) and self or f.from(self)
return f.new(function() return f.new(function()
local k, v = self:next() local k, v = self:next()
@ -785,28 +594,6 @@ function f:swap()
end) end)
end end
---@generic K, V
---@param self F|{ [K]: V }
---@return F|{ [K]: V }
---@nodiscard
function f:rev()
self = f.isf(self) and self or f.from(self)
local t, p, k
return f.new(function()
if not t then
p, t = f.revpairs(self:table())
end
local v
k, v = p(t, k)
if k ~= nil then
return k, v
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
@ -814,8 +601,6 @@ end
---@return F|{ [K]: V } ---@return F|{ [K]: V }
---@nodiscard ---@nodiscard
function f:slice(skip, take) function f:slice(skip, take)
self = f.isf(self) and self or f.from(self)
if (not skip or skip <= 0) and not take then if (not skip or skip <= 0) and not take then
return self return self
end end
@ -847,7 +632,6 @@ end
---@return F|{ [K]: V } ---@return F|{ [K]: V }
---@nodiscard ---@nodiscard
function f:skip(n) function f:skip(n)
self = f.isf(self) and self or f.from(self)
return self:slice(n) return self:slice(n)
end end
@ -857,7 +641,6 @@ end
---@return F|{ [K]: V } ---@return F|{ [K]: V }
---@nodiscard ---@nodiscard
function f:take(n) function f:take(n)
self = f.isf(self) and self or f.from(self)
return self:slice(0, n) return self:slice(0, n)
end end
@ -869,7 +652,6 @@ end
---@overload fun(self: F|{ [K]: V }, seed: fun(a: A, v: V, k: K): A): A ---@overload fun(self: F|{ [K]: V }, seed: fun(a: A, v: V, k: K): A): A
---@nodiscard ---@nodiscard
function f:fold(seed, func) function f:fold(seed, func)
self = f.isf(self) and self or f.from(self)
local k, v local k, v
if not func then if not func then
@ -899,7 +681,6 @@ end
---@overload fun(self: F|{ [K]: V }, func: string?): boolean|V ---@overload fun(self: F|{ [K]: V }, func: string?): boolean|V
---@nodiscard ---@nodiscard
function f:any(func) function f:any(func)
self = f.isf(self) and self or f.from(self)
func = autofunc(func) func = autofunc(func)
for k, v in self.next do for k, v in self.next do
@ -918,7 +699,6 @@ end
---@overload fun(self: F|{ [K]: V }, func: string?): boolean|V ---@overload fun(self: F|{ [K]: V }, func: string?): boolean|V
---@nodiscard ---@nodiscard
function f:all(func) function f:all(func)
self = f.isf(self) and self or f.from(self)
func = autofunc(func) func = autofunc(func)
for k, v in self.next do for k, v in self.next do
@ -937,9 +717,8 @@ end
---@overload fun(self: F|{ [K]: V }, func: string): integer ---@overload fun(self: F|{ [K]: V }, func: string): integer
---@nodiscard ---@nodiscard
function f:count(func) function f:count(func)
self = f.isf(self) and self or f.from(self)
func = autofunc(func)
local ret = 0 local ret = 0
func = autofunc(func)
for k, v in self.next do for k, v in self.next do
if not func or func(v, k) then if not func or func(v, k) then
@ -954,16 +733,15 @@ end
---@param self F|{ [K]: V } ---@param self F|{ [K]: V }
---@param other { [K]: V } ---@param other { [K]: V }
---@param func? fun(v: V, k: K): any ---@param func? fun(v: V, k: K): any
---@return K?, V? ---@return K?
---@overload fun(self: F|{ [K]: V }, func: string): integer ---@overload fun(self: F|{ [K]: V }, func: string): integer
---@nodiscard ---@nodiscard
function f:diff(other, func) function f:diff(other, func)
self = f.isf(self) and self or f.from(self)
func = autofunc(func) func = autofunc(func)
for k, v in self.next do for k, v in self.next do
if (not func or func(v, k)) and other[k] ~= v then if (not func or func(v, k)) and other[k] ~= v then
return k, v return k
end end
end end
end end
@ -982,7 +760,6 @@ end
---@return string ---@return string
---@nodiscard ---@nodiscard
function f:string() function f:string()
self = f.isf(self) and self or f.from(self)
local k, v = self:next() local k, v = self:next()
if k == nil then if k == nil then
@ -1007,7 +784,6 @@ end
---@return { [K]: V } ---@return { [K]: V }
---@nodiscard ---@nodiscard
function f:table() function f:table()
self = f.isf(self) and self or f.from(self)
local ret = {} local ret = {}
for k, v in self.next do for k, v in self.next do
@ -1021,8 +797,6 @@ end
---@param self F|{ [K]: V } ---@param self F|{ [K]: V }
---@param func? fun(v: V, k: K): nil ---@param func? fun(v: V, k: K): nil
function f:each(func) function f:each(func)
self = f.isf(self) and self or f.from(self)
for k, v in self.next do for k, v in self.next do
if func then if func then
func(v, k) func(v, k)

View file

@ -28,11 +28,6 @@ CardSleeves.Sleeve = CardSleeves.Sleeve
--- @type {aliases: { [string]: [string] }} --- @type {aliases: { [string]: [string] }}
Cryptid = Cryptid Cryptid = Cryptid
---@return Card
function copy_card(...)
error(...)
end
--- @type fun(area: CardArea, ...: ...): Card --- @type fun(area: CardArea, ...: ...): Card
create_card_for_shop = create_card_for_shop create_card_for_shop = create_card_for_shop
@ -48,18 +43,13 @@ G.playing_cards = G.playing_cards
---@type userdata|{getWidth: fun(self: self): number} ---@type userdata|{getWidth: fun(self: self): number}
SMODS.Atlas.image_data = SMODS.Atlas.image_data SMODS.Atlas.image_data = SMODS.Atlas.image_data
---@param context CalcContext|table|{hand_drawn: true, other_drawn: true} ---@return Card
---@param return_table? table function copy_card(...)
---@return table? error(...)
function SMODS.calculate_context(context, return_table)
error {context, return_table}
end end
SMODS.Mods.Roland.config = require "config" SMODS.Mods.Roland.config = require "config"
---@type (fun(rem: number): number|table)[]
SMODS.Mods.Roland.harsh_ante_scaling = SMODS.Mods.Roland.harsh_ante_scaling
--- @type table --- @type table
Talisman = Talisman Talisman = Talisman

View file

@ -14,13 +14,10 @@ local function add(v)
end end
if G.P_BLINDS[v] then if G.P_BLINDS[v] then
if G.STATE ~= G.STATES.MENU then G.from_boss_tag = true
G.from_boss_tag = true G.GAME.perscribed_bosses = G.GAME.perscribed_bosses or {}
G.GAME.perscribed_bosses = G.GAME.perscribed_bosses or {} G.GAME.perscribed_bosses[G.GAME.round_resets.ante] = v
G.GAME.perscribed_bosses[G.GAME.round_resets.ante] = v G.FUNCS.reroll_boss()
G.FUNCS.reroll_boss()
end
return G.P_BLINDS[v] return G.P_BLINDS[v]
end end

View file

@ -1,7 +1,7 @@
local qol = assert(SMODS.load_file "src/lib/shared.lua")() or require "lib.shared" local qol = assert(SMODS.load_file "src/lib/shared.lua")() or require "lib.shared"
local animated = SMODS.current_mod.config.animated_icon
SMODS.current_mod.qol = qol
local f, q = qol[1], qol[2] local f, q = qol[1], qol[2]
SMODS.current_mod.qol = qol
local animated = SMODS.Mods.Roland.config.animated_icon
q { q {
front = true, front = true,

View file

@ -38,32 +38,26 @@ spectral {
return {vars = {card.ability.extra.amount}} return {vars = {card.ability.extra.amount}}
end, end,
can_use = function() can_use = function()
return next(G.hand.cards) and u() return u() and #G.hand.cards > 0
end, end,
use = function(_, card) use = function(_, card, _)
local cards = f(G.hand.cards):table() local cards = f(G.hand.cards):table()
pseudoshuffle(cards, pseudoseed "RolandDual") pseudoshuffle(cards, pseudoseed "RolandDual")
f(cards):take(card.ability.extra.amount):each(function(v) f(cards):take(card.ability.extra.amount):each(function(v)
local seal = SMODS.poll_seal { local seal
guaranteed = true,
options = f(G.P_SEALS):keys():where(f.nq "Roland_glass"):values():table(),
}
local _ = not card.Roland_immediate and q { for _ = 1, 64 do
delay = 0.5, seal = SMODS.poll_seal {guaranteed = true}
trigger = "after",
func = function() if seal ~= "Roland_glass" then
v:set_seal(seal, nil, true) break
end, end
} or v:set_seal(seal, true, true) end
v:set_seal(seal == "Roland_glass" and "Red" or seal)
end) end)
end, end,
bulk_use = function(self, card, area, copier, number)
card.Roland_immediate = true
f(number):map(f.const(self)):each(f.call("use", card, area, copier))
card.Roland_immediate = nil
end,
} }
spectral { spectral {
@ -83,7 +77,7 @@ spectral {
delay = 0.4, delay = 0.4,
func = function() func = function()
card:juice_up(0.3, 0.5) card:juice_up(0.3, 0.5)
play_sound "tarot1" play_sound("tarot1")
end, end,
} }
@ -138,10 +132,9 @@ spectral {
return {vars = {card.ability.extra.amount}} return {vars = {card.ability.extra.amount}}
end, end,
can_use = function(_, card) can_use = function(_, card)
local count = #Bakery_API.get_highlighted() return u() and #Bakery_API.get_highlighted() == card.ability.extra.amount
return u() and count > 0 and count <= card.ability.extra.amount
end, end,
use = function() use = function(_, _, _)
f(Bakery_API.get_highlighted()):each(function(v) f(Bakery_API.get_highlighted()):each(function(v)
v:set_seal "Roland_glass" v:set_seal "Roland_glass"
end) end)

View file

@ -60,8 +60,8 @@ SMODS.Tag {
pos = {x = 0, y = 0}, pos = {x = 0, y = 0},
config = {amount = 5}, config = {amount = 5},
loc_vars = function(self, info_queue, tag) loc_vars = function(self, info_queue, tag)
info_queue[#info_queue + 1] = G.P_CENTERS.e_Roland_frozen
tag.ability = tag.ability or {} tag.ability = tag.ability or {}
table.insert(info_queue, G.P_CENTERS.e_Roland_frozen)
return {vars = {tag.ability.amount or self.config.amount}} return {vars = {tag.ability.amount or self.config.amount}}
end, end,
apply = function(self, tag, context) apply = function(self, tag, context)
@ -73,10 +73,9 @@ SMODS.Tag {
end end
if tag.triggered or if tag.triggered or
not context.card or (tag.ability.amount or self.config.amount) <= 0 or
context.card.edition or ((context.card or {}).edition or {}).Roland_frozen or
context.type ~= "Bakery_score_card" or context.type ~= "Bakery_score_card" then
(tag.ability.amount or self.config.amount) <= 0 then
return return
end end
@ -122,7 +121,6 @@ SMODS.Tag {
ab.total_rounds = ab.total_rounds or self.config.total_rounds ab.total_rounds = ab.total_rounds or self.config.total_rounds
if tag.triggered or if tag.triggered or
not G.jokers or
not next(G.jokers.cards) or not next(G.jokers.cards) or
ab.invis_rounds < ab.total_rounds or ab.invis_rounds < ab.total_rounds or
#G.jokers.cards + (modifiers.Roland_invisible or 0) >= G.jokers.config.card_limit then #G.jokers.cards + (modifiers.Roland_invisible or 0) >= G.jokers.config.card_limit then

View file

@ -26,9 +26,8 @@ q(SMODS.Consumable {
end end
local highlighted = Bakery_API.get_highlighted() local highlighted = Bakery_API.get_highlighted()
local count = #G.jokers.highlighted + #highlighted
return count > 0 and count <= card.ability.extra.amount and return #G.jokers.highlighted + #highlighted == card.ability.extra.amount and
f(G.jokers.highlighted):concat(highlighted):all(function(v) f(G.jokers.highlighted):concat(highlighted):all(function(v)
return not v.edition return not v.edition
end) end)

View file

@ -20,7 +20,7 @@ local orig_use_consumeable = Card.use_consumeable
function Card:use_consumeable(area, copier, ...) function Card:use_consumeable(area, copier, ...)
if SMODS.Mods.Roland.config.faster_planets and self.ability.consumeable.hand_type then if SMODS.Mods.Roland.config.faster_planets and self.ability.consumeable.hand_type then
set_consumeable_usage(self) set_consumeable_usage(self)
level_up_hand(copier or self, self.ability.consumeable.hand_type, true, self.ability.qty or 1) level_up_hand(copier or self, self.ability.consumeable.hand_type, true)
return return
end end
@ -110,35 +110,21 @@ local function no_harsh_ante_scaling()
return not Talisman or not SMODS.Mods.Roland.config.harsh_ante_scaling return not Talisman or not SMODS.Mods.Roland.config.harsh_ante_scaling
end end
---@type (fun(rem: number): number|table)[]
SMODS.current_mod.harsh_ante_scaling = {
function(rem)
return (Big.constants and Big.constants.TEN or Big:new {10}):pow(blind(rem + 1))
end,
function(rem)
return Big:new {1, rem + 2}
end,
function(rem)
return Big:new {1, 1, [rem + 2] = 1}
end,
function(rem)
return Big:new {1, 1, [blind(rem) + 2] = 1}
end,
function(rem)
return rem <= 1 and Big:new {1.7976931348623157e308, 1, [1.7975e308] = 1} or 1 / 0
end,
}
function get_blind_amount(ante, ...) function get_blind_amount(ante, ...)
local offset = 40 local loop = 39
if ante < offset or no_harsh_ante_scaling() then if ante < loop or no_harsh_ante_scaling() then
return orig_get_blind_amount(ante, ...) return orig_get_blind_amount(ante, ...)
end end
local loop = 10 if (ante - 9) / 15 >= loop then
return 1 / 0
end
return f(SMODS.Mods.Roland.harsh_ante_scaling, f.revpairs):any(function(_, k) local rem = tonumber(blind((ante % loop) + 1))
return (ante - offset) / loop + 1 >= k
end)((ante - offset) % 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)))
end end