#💻・modding-dev
1 messages · Page 95 of 1
Easy quick question: What is the max handsize equivalent for what ease_hands_played does with + hands? I tried looking around but haven't gotten much luck finding documentation for the functions
EDIT: figured it out
Pardon me if this is already easily available, but I am making a test deck for my mod and want it to start me with the jokers I have modded in. I can't figure out how to do that. Can someone point me in the right direction?
You can use DebugPlus for debug tools, if this is purely for debugging.
It lets you spawn any joker and any card at any time, alongside a bunch of other goodies
https://github.com/WilsontheWolf/DebugPlus
Ah, fantastic. In the case that I wanted to make a playable deck with a starting joker though, how would I go about doing that?
Nevermind, figured this out
function definition usually starts with keyword "function"
if you want to search for definition of the function you have to search "function add_joker"
this might be a stupid question but if you do get_suit(“Suit”) and get_suit(“Suit2”) for all 4 suits, is that a way to check for wild cards?
card.ability.name == 'Wild Card'?
Oh what the heck
I'm just using test colors for now and it looks like i spilled milk in a bucket of paint
it looks so weird, i kinda like it
oh that looks cool, looks like a negative color photo
literally
They're honestly all green, all blue, and all White for the colors
This is how it actually looks rn
Actually makes me think of cyanotyping for some reason.
The cyanotype (from Ancient Greek: κυάνεος, kyáneos 'dark blue' and τύπος, týpos 'mark, impression, type') is a slow-reacting, photographic printing formulation sensitive to a limited near ultraviolet and blue light spectrum, the range 300 nm to 400 nm known as UVA radiation. It produces a monochrome, blue coloured print on a range of supports,...
i dont know if this'd be weird; but it'd be cool if they were a white and gray background
to match the bg of the tags
Can I make a deck start with a joker? G.jokers doesn't exist yet so I'm not sure what the area would be
peak
wasnt this also in jen's?
this has more plans than just "Gain a tag" in the future
this isnt a critisism just an observation
The gain a tag part is for another deck w/ Ditpyrc
This is just being made for that
These will act more like CCD tags
This just made me think of https://www.youtube.com/watch?v=dcCwDVX_ZtY
This is the Playstation 2 Slim Startup Screen and Noise. Please give it a thumbs up and subscribe :D
is this also a different mod by itself?
👍
It's a bunch of stuff that people can use if they wish as a dependency
want the link to the current version?
oh yeah I should probably do that
there should def be more cryptid stuff with the adding stuff to playing card feature.
surprisedd only fudge is there
btw is the CSL dormant or smth?
i dont know if its just me or
i havent seen any suggestions move statuses in ages, i thought a screening run was yesterday or last week.
progress has been slow but we are aware of the backlog and working on it
it’s been hard the last few days to get everyone for a screening run
by the way... no hard feelings?
no comment
#1315020305487495310 <- Btw we working on trying to make a new card creation thing
accessible new card stuff seems nice
if im reading this right
im liking the wip code tho
seems way easier
The problem is to implement it
...understandable
i cant believe that at some point there was another balatro modding thing people ACTUALLY used over smods sometimes
considering how big smods is now
I’m also interested in porting it to SMODS alongside the same things for Jokers
There
very nice
whats up with the text
Wanted something different
Ty
np
still can't figure this out
Crap
I forgot i need to make a tag for tag packs
and then a tag card for the tag for tag packs
That's a self recursion--
Yeah but you don't always get the tag pack tag card in the tag card pack
how do I create a specific consumable from code? I know the name and key of what I want to create, just not how
SMODS.create_card({ key = "c_???" })
will that toss it into the consumables area for me too?
thank you
took this code from source and changed it a smidge to not be random, and its throwing an error?
if #G.consumeables.cards + G.GAME.consumeable_buffer < G.consumeables.config.card_limit then
print("we got the cuzz (context huzz)")
G.GAME.consumeable_buffer = G.GAME.consumeable_buffer + 1
G.E_MANAGER:add_event(Event({
trigger = 'before',
delay = 0.0,
func = (function()
local card = create_card('Tarot',G.consumeables, nil, nil, nil, nil, nil, 'hal')
card:add_to_deck()
G.consumeables:emplace(card)
G.GAME.consumeable_buffer = 0
return true
end)}))
card_eval_status_text(self, 'extra', nil, nil, nil, {message = localize('k_plus_tarot'), colour = G.C.PURPLE})
end
end
end
end
}
i can show the first part of the error, but discord is deciding to be a pain in the ass and not allow me to send it as a file
nvm, can just make my own .txt file
try changing the self in card_eval_status_text to card
i swear some messages always get ghosted no matter how many times you send them
I'd say, get the amount of 7 in hand and use that as retrigger amount?
Animate how?
show your code
calculate = function(self, card, context)
if context.repetition and context.cardarea == G.play and context.other_card.base.id == 4 then
local repetitions = 0
for k, v in ipairs(G.hand.cards) do
if v.base.id == 7 then
card_eval_status_text(card, "extra", nil, nil, nil, { message = localize("k_again_ex") })
v:juice_up(0.3, 0.5)
eval_card(context.other_card)
end
end
end
end
and what isn't working?
the four doesn't retrigger
you don't return anything
i need to retrigger the 4 manually in order to animate the 7
you need to tell the game to retrigger the 4
the v:juice_up() will make the 7 jiggle
calculate = function(self, card, context)
if context.repetition and context.cardarea == G.play and context.other_card.base.id == 4 then
local repetitions = 0
for k, v in ipairs(G.hand.cards) do
if v.base.id == 7 then
G.E_MANAGER:add_event(Event({
trigger = 'after',
delay = 0.4,
func = function()
v:juice_up(0.3, 0.5)
repetitions = repetitions + 1
return true
end
}))
end
end
return { message = localize("k_again_ex"), repetitions = repetitions, card = card }
end
end
this just doesn't work at all
for some reason the 4 doesn't retrigger
repetitions = card.ability.extra.repetitions
no, repetitions is a local within calculate
hrm, didnt know you could do that
actually, this almost works
calculate = function(self, card, context)
if context.repetition and context.cardarea == G.play and context.other_card.base.id == 4 then
local repetitions = 0
for k, v in ipairs(G.hand.cards) do
if v.base.id == 7 then
repetitions = repetitions + 1
G.E_MANAGER:add_event(Event({
trigger = 'after',
delay = 0.4,
func = function()
v:juice_up(0.3, 0.5)
return true
end
}))
end
end
return { message = localize("k_again_ex"), repetitions = repetitions, card = card }
end
end
last time repetitions was being updated too late
but i still have the problem that the 7s animate at the wrong time
calculation guide has been rewritten by @bleak cave 🎉 https://github.com/Steamopollys/Steamodded/wiki/Guide-‐-Joker-Calculation
do y'all know what i'm doing wrong here? it crashes on the set:edition() line. i'm a little confused ```lua
SMODS.Back {
name = "Chroma Deck",
key = "b_chr",
atlas = 'chrdeckatl',
pos = { x = 0, y = 0 },
loc_txt = {
name = "Chroma Deck",
text = {
"5 cards in deck have",
"a random {C:attention}edition{}",
},
},
config = {},
unlocked = true,
discovered = true,
apply = function(self)
local editions_added = 0
G.E_MANAGER:add_event(Event({
func = function()
while editions_added < 5 do
local card_procced = pseudorandom_element(G.playing_cards, pseudoseed(self.key))
if not card_procced.edition then
editions_added = editions_added + 1
local edition_chosen = pseudorandom_element({'polychrome', 'foil', 'holo'}, pseudoseed(self.key))
card_procced:set_edition(edition_chosen, true, true)
end
end
return true
end
}))
end
}```
GOD IS GOOOOOOD
keys are e_polychrome etc.
you can also use poll_edition for your edition generation
it'll respect weights and allow for other modded editions
oh, you can?? nice :>
out of curiosity, is there similar functions for tags or enhancements?
yes
enhancements uses SMODS.poll_enhancement
tags are a little different in that you'd have to do the random selection yourself but you can use get_current_pool('Tag') to get a table of valid tags
poll_edition(self.key, nil, true, true)
what function handles the visual effects/sounds when a card/joker is counted?
assuming you don't want negative
does the nil control if negative gets added?
the nil is a modifier if the 4th option is not true
what would control the negative?
the third argument is for not negative, so setting it to true stops negative from being generated, as nil it would allow negatives
okay, so if it was poll_edition(self.key, nil, false, true) negatives would be included then
got it :>
the 4th option is whetehr the edition is guaranteed or not, they ahve a base 4% chance of spawning, so setting this as true sets it to 100%, or altering the second argument to say 2, would increase it to 8%
yes
thank you so much for the help i very much appreciate it :>
the enhancement one works in a similar way but takes a table as the argument instead
as in, you would put in a list of banned enhancements instead of true?
it'll just roll between all enhancements or a list you pass it
it doesn't support banning enhancements
perhaps it should
yeah
i guess you could bandaid fix go "if [unwanted enhancement,] then reroll enhancement"
thank you for the help!!!!!!!!!
for the record, i think i meant seal here 😅
my bad, oopsie
seal is like enhancement
wait, so how would the prior code work if it was an enhancement instead of an edition? because currently it's throwing an error
apply = function(self)
local enhancements_added = 0
G.E_MANAGER:add_event(Event({
func = function()
while enhancements_added < 10 do
local card_procced = pseudorandom_element(G.playing_cards, pseudoseed(self.key))
if not card_procced.abliity then
enhancements_added = enhancements_added + 1
local enhancement_chosen = SMODS.poll_enhancement(self.key, nil, nil, true)
card_procced:set_ability(enhancement_chosen, nil, true)
end
end
return true
end
}))
end```
still unresolved
so an enhancement would be like this SMODS.poll_enhancement({key = self.key, guaranteed = true})
like this? because it's still not really working, it doesn't throw an error but it freezes and crashes```lua
apply = function(self)
local enhancements_added = 0
G.E_MANAGER:add_event(Event({
func = function()
while enhancements_added < 10 do
local card_procced = pseudorandom_element(G.playing_cards, pseudoseed(self.key))
if not card_procced.ability then
enhancements_added = enhancements_added + 1
local enhancement_chosen = SMODS.poll_enhancement({key = self.key, guaranteed = true})
card_procced:set_ability(enhancement_chosen, nil, true)
end
end
return true
end
}))
end
}
needs to be card_procced:set_ability(G.P_CENTERS[enhancement_chosen], nil, true)
huh
oh
card.procced.ability will always be true
its just stuck in an infinite loop of not doing anything
if card.ability.set ~= 'Enhanced' then
ah! sorry, i'm a beginner, thanks again :>
where can i start learning how to make custom boss blinds? never made a mod so everything is new
Is it possible to allow a pach to pach inside a pach that has already been patched
3 chances to spell patch correctly

This feels like a tremendously stupid question but I just can not get the hang of the data structures: where do I find the scoring cards during joker evaluation?
i'm still lost with that guide, i just dont know where to start
What I do is I look at other mods and steal what they do for the baseplate then change from there
Nevermind found it
do you have any examples of mods you made
Yeah here
SMODS.Blind{
key = "creeper",
loc_txt = {
name = 'The Creeper',
text = { "Ends run if not",
"beaten in #1#"},
},
name = "The Creeper",
dollars = 5,
mult = 2,
boss= {min = 3, max = 10},
boss_colour = HEX("297711"),
atlas = "mc_blinds",
pos = { x = 0, y = 0},
vars = {"0:20"},
config = {},
set_blind = function(self)
G.GAME.blind.config.creepertiming = 20
end,
loc_vars = function(self, info_queue, card)
if G.GAME.blind.config.creepertiming == nil then
return {vars = {"0:20.00"}}
end
local m = math.floor(G.GAME.blind.config.creepertiming / 60)
local s = (G.GAME.blind.config.creepertiming - (60 * m))
local d = math.floor(100 * (s - math.floor(s)))
s = tostring(math.floor(s))
if string.len(s) == 1 then
s = "0" .. s
end
d = tostring(d)
if string.len(d) == 1 then
d = "0" .. d
end
m = tostring(m)
return {vars = {m .. ":" .. s .. "." .. d}}
end,
}
SMODS.Blind{
key = "wither",
loc_txt = {
name = 'Midnight Wither',
text = { "All cards scored gain",
"Wither sticker"},
},
dollars = 5,
mult = 3,
boss= {showdown = true, min = 10, max = 10},
boss_colour = HEX("1a1a1a"),
atlas = "mc_blinds",
pos = { x = 0, y = 1},
vars = {},
config = {},
}
one example of a boss blind i wanted to do just to learn to do one was for example all spade cards are drawn face down
I would check cruel blinds for that
ah ok
There entire thing is blinds
im just trying to find one to start a base off of to learn how to do
well it has stakes and deck too
boss blinds and challenge packs is what i really wanted to focus on
cruel blinds is literally that
word
gonna look at that rq
also noticing a lot of the blind mods are undiscovered i was trying to figure out how to change that
How might I save variables in between calculate calls? Like how many times a particular rank has scored in the blind?
i dont know how you managed to get a timer working but i am impressed
(they copied code)
Yeah be impressed with mathguy not me he made the Original timer
In bonus blinds
Now as a shameless plug you should go vote for Minecraft to be the next cross content mod
Yes
It shouldn't be too difficult
Cryptid does It I think
tysm, glad u are enjoying it.
Cryptid has a blind that debuffs every other rank and randomly picks between odd and even
for card in hand do if v:get_id()%2 ~= 0 then v:set_debuff(true) end end
etc etc
that wouldnt be hard to not make pseudocode but i cant be bothered
LOL i dont know what any of that means
oh nice got it
local place = G.hand --G.play for played cards, G.hand for cards in hand
for i, v in pairs(place.cards) do
if v:get_id() % 2 ~= 0 then
v:set_debuff(true)
end
end
This feels trivial and yet I still can't figure out what I consider good-practice ways of doing it given how smods sets things up
thats it?
I mean, there would also be the rest of the Blind definition
But that is how it would debuff all the odd cards
ts is so confusing but im willing to learn
Are you at all familiar with Lua in the first place?
nope
actually no it would debuff face cards and whatnot
If not, I recommend doing a little bit of online learning about it
Go do a tutorial or smth. Really helps, trust me.
local place = G.hand --G.play for played cards, G.hand for cards in hand
for i, v in pairs(place.cards) do
if v:get_id() % 2 ~= 0 and v:get_id() <= 10 and v:get_id() > 0 then
v:set_debuff(true)
end
end
not familiar with lua at all, just wanted to make custom mods
I can go spin up my debug game if you want me to find out lol
Do you have Any coding knowledge
what the actual fuck???
Modding requires Lua. You'll have a much easier time of this if you know the language.
a very tiny bit of python knowledge
but thats it
ohh i get it
and how long would that take
it needs to be an actual number so the game can function but it cant be the same number because the stone cards would then be able to form 4oaks and whatnot
and other things
so its just some random negative number
😭
I have no idea. A few days maybe? To learn the bare minimum to understand the structures that SMODS involves.
I came into this knowing Lua from my days screwing around with ComputerCraft
so its actually not that hard
That's kinda smart tbh? I would have personally reserved an id (probably a negative one) for Stone cards and then just checked that in the hand eval.
coming back to this again 😭 pls help
do you remember what guides you looked at or specific tutorials you may have looked at
that you recommend or anything
This was like 10 years ago. I think I used Codeacademy but iirc most of what used to be free there is locked behind paywalls now.
it seems that there is a small, yet existent chance for 5 stone cards to form a 5 of a kind
checking the code it seems possible
Yeah, that's why I would have reserved an id and just checked against it in hand eval
unless that behavior is intended. i dunno
okay, ill go look at a youtube guide or somehting
looks like SMODS inadvertently patches this
ah wait nevermind
theres a very roundabout way of ensuring that this only works on positive ids
missed it
Interesting
isn't the random one in cruel blinds
man, even starting lua is confusing to me. ill come back once i learned a bit tho, and thanks
I am once again asking for help with this
cryptid 2 when
When balatro 2 happens
you could use the config, just like any other joker with a numeric value
Atleast he's trying
One of my installed mods is causing the game to close if streamlabs tries to capture the window, any ideas as to why?
The mod replaces some texture files and has a edited en-us.lua for custom joker names etc
Update in case someone else has this problem:
The main lua file of the mod was named main.lua I tried renaming it something else and the problem is gone now
wh a t
Having a rough time debugging this code rn
Error log
Idk what causes the issue but here is the init code:
SMODS.Joker{
key = "5_coren",
loc_txt = {
name = 'Corens Potluck',
text = "Test"
},
config = {
extra = {
Xmult = 2,
chips = 150,
food_check = false
}
},
loc_vars = function(self, info_queue, card)
return { vars = { card.ability.extra.Xmult, card.ability.extra.chips } }
end,
rarity = 1,
atlas = '5_coren',
pos = { x = 0, y = 0 },
cost = 4,
calculate = function(self, context)
if SMODS.end_calculate_context(context) then
-- Check if food item is true
if self.ability.extra.food_check then
return {
-- Return bonus message and apply bonus
chip_mod = self.ability.extra.chips,
Xmult_mod = self.ability.extra.Xmult,
message = "Food!",
card = self
}
end
end
end
}
Any pointers in the right direction would be very appreciated
*log
end_calculate_context is a 0.9.8 thing
do context.joker_main
if SMODS.context.joker_main(context) then
As such?
struct rightDirection {
int *ptr = NULL
}```
forgot everything i know about C because i never made anything functional but this is functional code right 
pffft
Thank you
Honestly, first time I've touched the code side of this game so this is prolly why I am totally lost lmfao
Especially since Steamodded's documentation is awfully confusing atm due to it being in an alpha limbo for the next version
Apologies for the ping but could you please give some additional context? Which is to say, what exactly do I need to do here with the calculation context?
if SMODS.context.joker_main then Like so?
if context.joker_main
+the calculate arguments are self, card, context you're leaving out context (and treating card as context)
self refers to the center (used to generate that card), card refers to the actual card object
correct
Do I need to use the card parameter
yup
okay ill let cg help you because phone is ass
if context.joker_main then
-- Check if food item is true
if self.ability.extra.food_check then
return {
-- Return bonus message and apply bonus
chip_mod = self.ability.extra.chips,
Xmult_mod = self.ability.extra.Xmult,
message = "Food!",
card = card
}
end
end```
Like so then
click on my profile
god fucking damnit

I appreciate all the help either way lolol
looks about right
ah yes
Ahhh thanks
yeah not self
wuh
wuh
oh
in loc_txt text needs to be a table
Is it not a table?
it's not in that code
Damn I thought the curly braces was how you'd define that--
text = {"test"}
ya
it's okay dw 😭
Programmer's dilemma
Debug an entire system
Broke it due to a single period
OH MY GOD IT BOOTED
YAY
🔥
Thank you both so much
np!
Before I go to finish this out on my own
I have some logic for checking for certain cards
I have remove and add to deckref
Does it work any differently now on the newer version of steamodded?
no different
Cool
function Card:add_to_deck(from_debuff)
if not self.added_to_deck then
if self.ability.name == "Gros Michel" or self.ability.name == "Ice Cream"
or self.ability.name == "Cavendish" or self.ability.name == "Turtle Bean"
or self.ability.name == "Diet Cola" or self.ability.name == "Popcorn"
or self.ability.name == "Ramen" or self.ability.name == "Seltzer" then
-- Check for Coren Joker
for _, v in pairs(G.jokers.cards) do
if v.ability.name == "5 Coren" then
-- Update Coren Joker variables
v.ability.extra.food_check = true;
end
end
end
if self.ability.name == "5 Coren" then
-- Check for food jokers
for _, v in pairs(G.jokers.cards) do
if v.ability.name == "Gros Michel" or v.ability.name == "Ice Cream"
or v.ability.name == "Cavendish" or v.ability.name == "Turtle Bean"
or v.ability.name == "Diet Cola" or v.ability.name == "Popcorn"
or v.ability.name == "Ramen" or v.ability.name == "Seltzer" then
self.ability.extra.food_check = true
end
end
end
end
add_to_deckref(self, from_debuff)
end```
Awful code but
This is how I wrote it
. yeah that is Not Good
Figures as much lmfao
ideally you would want to check for key instead of name
iirc cryptid has an implementation of this function that you can copy
Ye I was gonna change this
slash study
Oh do link
I'd love to read it
and for the coren check you can use SMODS.find_card(key) which returns a table of cards with that key
i can't link where it is exactly in the code bc not on pc but https://github.com/MathIsFun0/Cryptid
Thank you!
okay i found the function i was thinking of, turns out it was smth different
so nvm
Yeah I checked
In fact they do the same awfulness I'm doing
if
self.ability.name ~= "cry-happyhouse"
and self.ability.name ~= "Acrobat"
and self.ability.name ~= "cry-sapling"
and self.ability.name ~= "cry-mstack"
and self.ability.name ~= "cry-notebook"
and self.ability.name ~= "Invisible Joker"
and self.ability.name ~= "cry-Old Invisible Joker"```
in typical cryptid fashion
🔥
check how Cryptid.food is populated
i can't myself without poring through the code on mobile
ah it's just
local jokers = {
"j_gros_michel",
"j_egg",
"j_ice_cream",
"j_cavendish",
"j_turtle_bean",
"j_diet_cola",
"j_popcorn",
"j_ramen",
"j_selzer",
}
if Cryptid.enabled["Misc. Jokers"] then
jokers[#jokers + 1] = "j_cry_pickle"
jokers[#jokers + 1] = "j_cry_chili_pepper"
end
if Cryptid.enabled["Epic Jokers"] then
jokers[#jokers + 1] = "j_cry_oldcandy"
jokers[#jokers + 1] = "j_cry_caramel"
end
if Cryptid.enabled["M Jokers"] then
jokers[#jokers + 1] = "j_cry_foodm"
end
if Cryptid.enabled["Spooky"] then
jokers[#jokers + 1] = "j_cry_cotton_candy"
jokers[#jokers + 1] = "j_cry_wrapped"
jokers[#jokers + 1] = "j_cry_candy_cane"
jokers[#jokers + 1] = "j_cry_candy_buttons"
jokers[#jokers + 1] = "j_cry_jawbreaker"
jokers[#jokers + 1] = "j_cry_mellowcreme"
jokers[#jokers + 1] = "j_cry_brittle"
end
for i = 1, #jokers do
Cryptid.food[#Cryptid.food+1] = jokers[i]
end
minor text wall mb
true
guh
So I can prolly do sm like
local jokers = {
"j_gros_michel",
"j_egg",
"j_ice_cream",
"j_cavendish",
"j_turtle_bean",
"j_diet_cola",
"j_popcorn",
"j_ramen",
"j_selzer",
}
local add_to_deckref = Card.add_to_deck
function Card:add_to_deck(from_debuff)
if not self.added_to_deck then
if self.key == jokers[self.key] then
I didn't know Lua could do this so easily since this is my first direct exposure to it. I'm used to every other language
not quite this creates an integer indexed table
so trying to index with the key will always be nil
yeah instead do something like ```lua
local jokers = {
j_gros_michel = true,
--...
}
i love lua for this
table ....
tables...

I knew Gmod used LUA but I was too young to understand code lmfao
So again, first time exposure for me
my lua experience came from roblox exploiting mostly
Oh that's hilarious
i was so into that shit when i was 13
my ass was on every shitty simulator game trying to break em
but it was fun
side note nobody on roblox knows what they're doing ive seen some absolutely abysmal practices
Oh you're younger than me by quite a bit... I was into Roblox more back when they still had things like Tickets
So...
I loved logging on everyday to get more free tickets and I have some stuff from back in the day that you can't even get anymore as a result
Apparently there's demand for the 2009 summer hat on the market so that's funny
the little lua I knew was from configuring neovim
I know lua pretty well now but I also know little, if nothing at all
local jokers = {
j_gros_michel = true,
j_egg = true,
j_ice_cream = true,
j_cavendish = true,
j_turtle_bean = true,
j_diet_cola = true,
j_popcorn = true,
j_ramen = true,
j_selzer = true,
}
local add_to_deckref = Card.add_to_deck
function Card:add_to_deck(from_debuff)
if not self.added_to_deck then
if jokers[self.key] then
-- Check for Coren Joker
for _, v in pairs(G.jokers.cards) do
if v.key == "5_coren" then
-- Update Coren Joker variables
v.extra.food_check = true;
end
end
end
if self.key == "5_coren" then
-- Check for food jokers
for _, v in pairs(G.jokers.cards) do
if jokers[v.key] then
self.ability.extra.food_check = true
end
end
end
end
add_to_deckref(self, from_debuff)
end
-- Function for when Jokers are removed
local remove_from_deckref = Card.remove_from_deck
function Card:remove_from_deck(from_debuff)
if self.added_to_deck then
if self.key == "5_coren" then
-- Reset Coren value
if self.ability.extra.food_check then
self.ability.extra.food_check = false
end
end
if jokers[self.key] then
-- Check for Coren
for _, v in pairs(G.jokers.cards) do
if v.key == "5_coren" then
-- Check if any food is still present
for _, b in pairs(G.jokers.cards) do
if jokers[self.key] then
b.ability.extra.food_check = true;
else
b.ability.extra.food_check = false;
end
end
end
end
end
end
remove_from_deckref(self, from_debuff)
end```
Sorry for wall
But I rewrote it
Whoops noticed a mistake
Fixed it tho
when using steamodded, how do i replace a default sound with my new one?
like music1
you just put replace = 'music1' in your sound object
Hmmm
So now I have reached the phase of debugging
Seems like the joker card check doesn't return true
if jokers[self.key] then
With a dict of local jokers = { j_gros_michel = true, j_egg = true, j_ice_cream = true, j_cavendish = true, j_turtle_bean = true, j_diet_cola = true, j_popcorn = true, j_ramen = true, j_selzer = true, }
function Card:add_to_deck(from_debuff)
if not self.added_to_deck then
sendDebugMessage("Joker Added", "MyDebugLogger")
if jokers[self.key] then
sendDebugMessage("Found food", "MyDebugLogger")
-- Check for Coren Joker
for _, v in pairs(G.jokers.cards) do
if v.key == "5_coren" then
sendDebugMessage("Found Coren", "MyDebugLogger")
-- Update Coren Joker variables
v.extra.food_check = true;
end
end
end```
For fuller context
it plays nothing
here's the code
as in, it longer plays the track at all? or does it just keep playing music1
no longer plays the track at all
no music1, no neut1
here's the file structure, but i just did as steamodded said to do
hm
i don't think i ever really tested support for wav files, i just assumed it would be supported. Not so sure now, nothing else seems to be wrong
then ill try converting them to ogg using ffmpeg in a bit and update
will update if it works or not since steamodded 1.0 is still beta iirc
wild guess, but try music_neut1 as the key
will try in a second!
holy shit it worked
without converting files
to be fair, steamodded does not document what "key" does 😭
i dont know WHY it worked but it worked
because bgm needs to have "music" in the key
it's something thunk did iirc
nope
oh lmao i forgot about that, sorry
it's even in the docs i sent but i didn't spot it 😭
only music and ambient need that
😭😭😭
and that's with those being my docs 💀
if you wanted to make a joker only activate when another joker is there, can you do something like card.ability.name = "Jimbo" to check if its there?
generally using names is discouraged, keys are better. Also it's not that simple, but there's a function for it
wait like you wrote them???
if next(SMODS.find_card('j_joker')) then ... end
yep
dude 😭
im gonna presume it still needs to be in a "check the joker slots" loop? raisedcateyebrow~2
no
please add examples to the functions, itll make them so much better
oh thank god 😭
we have example mods
wait that mod already existed? 😭
oh lmao sorry i didn't realize that's what you were doing
lmao??????
can this be extended with something like:
if next(SMODS.find_card('j_joker', 'j_joker2', 'j_joker3')) then ... end
so it can effect multiple jokers?
GOODLORDWHATISHAPPENINGINTHERE~1 in the SMODS.find_card or doing one for every single joker it should effect?
do you know how lua works 😭
if next(SMODS.find_card('j_joker1')) or next(SMODS.find_card('j_joker2')) or next(SMODS.find_card('j_joker3')) then ... end
something like 'j_joker1' or 'j_joker2' or 'j_joker3' as the argument would just evaluate to the first string
im not good with instructions 😭 but that is exactly what i was asking, thank you
is there a way to make my blind always trigger (for testing it)?
im trying to make a boss blind
iirc with debugplus you can press (ctrl+)3 on the blind in the collection while on the select screen
same, its usefull to know, ty!
btw how do i add a debuff?
the docs show this but it is not clear at all
maybe have a look at the vanilla bosses
they'll may be of help
or look at other mods
i cant really find any other boss blind mods that use this
not in steamodded example mods, not on awesome-balatro...
Ah… so is the next keyword only for the joker adjacent to the one that is initiating the search, or is it for another function?
I ask merely to make sure that I don’t need to perform a loop
next is a function that takes a table and (ignoring unnecessary detail) returns a truthy value if the table has a value, else returns nil
SMODS.find_card just searches through your entire joker lineup
Huh, wonder why it’s called next
here's an example of it used for looping https://www.lua.org/manual/2.4/node31.html
basically it returns the next value and index given an index into a table
Yeah thats what I was going to say
Like I thought it would be used for that
iirc its technically supposed to be an iterator that gets the next index, it's just lua treats any value as true, and nil as false so it can be used for a check like this
SMODS.find_card returns a table of all joker with the specified ID, it can have more than one if you have more than a single copy of the joker (eg. from showman, invisible etc)
So then it would only take a single line to get what I need then (assuming I only need to find one joker)
oop i'm too slow
yeah just the next(SMODS.find_card("whatever"))
Sweet
Thanks
I know you weren’t helping me but this was actually related to what I was doing
I did it the old terrible way (attributes)
That being said, how would I retrieve the key from the self argument for when a joker card is added or removed
In other words, a function like
local add_to_deckref
it's actually also not needed or recommended to use function hooks for things like add_to_deck or remove_from_deck. you just put a function in the joker object when registering
Ahh I did it that way since the only way I saw people do it online was with the function hook
the arguments are slightly different, self in the original function is the second argument and usually called card, while the first argument self is just the prototype. the key is then just self.key (or card.config.center_key)
that's the old way
See I tried that originally but it returned nil
self.key specifically
Yeah this code isn’t the same as what I ended up with in the end but it’s similar
I guess now that I can decouple the logic from the argument hook, I can probably just run a simple Joker search to see if I should trigger the Joker or not
Instead of needing a Boolean value
And this junk
oh you're not doing add effects of a specific joker? what i said doesn't make too much sense in context
it's basically the second option of what i said above then
self.config.center_key
or self.config.center.key, funnily enough both of these work
What I’m doing is:
Pull from a list of jokers (in this context, all vanilla food jokers)
If player has a joker in that table, then allow this modded joker to trigger its effect (2x mult 150 chips)
I got it to work but only in the old attribute and argument hook way, so at least now I can move it to key
yeah function hooking is actually the most straightforward option in that case because it's not bound to one specific joker
Alright I’ll prolly just update my code with this then and make it way better if I ever, for some reason, wanted to localize the mod (even though I did it as practice for a friend, lol)
now that i come to think of it, this probably isn't the best way to implement what you're doing anyways
you should just check for food jokers in your calculate function
Yeah that’s what I was originally thinking of doing
But I thought “oh but it’s more efficient to do it this way”
When I could honestly just cut down on almost all of the logic I had to write
that's what we call premature optimization
Lmfao yeah
also it's not strictly more efficient
Yeah I just thought it would be better to use a Boolean flag and call it a day
Rather than check every time
When I’m still checking every time lol
In retrospect, not the brightest idea
fair 'nuff
I’ll take a crack at it again later
Now that I have a better idea of what I can do
Thanks
thinking about making some pulls on cryptid for bugfixes
there should be some way to have a speed above 4 for trains like what i have rn
this shit gonna take FOREVER
dude i'm still on the third card
go ahead, it looks like you need to update your install though
Talisman comes with Cryptid, and Nopeus can also increase game speed and reduce animations
HOLY SH-
talisman could do it???
maybe
i'm on mac tho
wait how do i change the speed for talisman what
Not speed, but it can disable the scoring animations
Mods > Talisman > Disable Scoring Animations
ohhh
oh wow that's so much better wth
wait i think i lowk crashed the game with that hand
with a new hand i mean
i think i crashed the game @mellow sable
guess not
good god
it is very normal to crash the game with cryptid btw
btw jawbreaker has a sprite now in latest version
huge
Is there a way to intercept a function call debuffing a card to prevent it from doing so?
context: I am trying to make a seal that prevents a card from being debuffed
Yes, by creating a hook. You store previous function into a local variable and then override the function, if debuff needs to be cancelled, you return from the function, otherwise you call the function with the same parameters
So uh
Dumb question
How do I make a hook
local oldFunc = G.this.function
function G.this.function(arg1, arg2)
if condition then
return
end
return oldFunc(arg1, arg2)
end
Would that not just recurse infinitely
Ok
also note that this can have side effects of an argument isn't passed and you're hooking a, say, C function that insists on a certain type for it's values
also keep in mind that declaration like function Controller:do_something(arg1) is short for function Controller.do_something(self, arg1)
^
so you'd need to pass self into the old function manually
Lua's patterns of reference saving versus value saving hurt my Java/Python brain
yeah it's certainly not intuitive
yeah, it's weird
shoutout copy_table
LUA looks like someone ran over Python with a monster truck and scooped the remains into a sack.
running over garbage just leaves you with more garbage
I didn't say ran over Java
🗿

egg
i used a lovely patch to do this
though if we can just hook the existing function i might do that instead; lovely patching kinda scares me :v
lovely patching like that would just cause incompatibility if another mod tries to patch the exact same thing
but mostly because that's a bit unoptimal to do full function replacement, you can just add one check after this line
I mean logic wise it'd behave differently, now that I think of it
in this case it'd probably make more sense to override instead of patching
well, yeah Ig, with extra check for pareidolia
I'll probably redo the thing after work today
if i can take it out of lovely patching entirely I'd prefer that. but if i can't do that then at least i can make it less awkward
this ain't lovely patching this is just fancy function overwriting
on a technical level, it's still lovely patching, it just sucks :v
but now that i know function hooking exists I'm gonna try that instead
this should also be useful for another thing i was trying to figure out. probably
lovely is a last resort, other options are usually better ones
true, but i couldn't find the better options back then
I'd love it if my next update let me delete lovely.toml out of my mod entirely :v
that's the spirit 
First two definitely shouldn't be done as lovely patches. Third one might actually be cleanest as lovely patch 🙃
i think all three would be relatively simple, based on how it looks like function hooks work
but I'll have to test it and find out. after work
ctrl is unessicary on spawning keybinds
Currently trying to adapt Inscryption Sigils into Seals
They obviously won't work 1-1
But
I am trying
i wasn't sure as i actually haven't updated yet, hence the parens
fair enough
the tab menu, collection number keys, save states and the console don't need ctrl
good to know
Alright, im trying to make a joker reduce the cost of all jokers and buffoon packs in the shop.
Ive does the injection in the lovely.toml below and the discount will not apply
#Add discount for Limp Bizkit
[[patches]]
[patches.pattern]
target = "card.lua"
pattern = "if (self.ability.set == 'Planet' or (self.ability.set == 'Booster' and self.ability.name:find('Celestial'))) and #find_joker('Astronomer') > 0 then self.cost = 0 end"
position = "after"
payload = """
if (self.ability.set == 'Joker' or (self.ability.set == 'Booster' and self.ability.name:find('Buffoon'))) and #find_joker("LimpBizkitSec") > 0 then
self.cost = self.cost * 0.5
end
"""
match_indent = true
Anyone know why the discount would not be applying?
I just put it after the code for Astronomer since they pretty much do the same thing
with after won't it be in the if statment for astronomer
also you should probably use SMODS.find_card with your joker's id
the if-statement ends on the same line so I don't think that's the issue
i used this and changed it to before and it worked, thanks
oh yeah I'm blind
lts isnt really a thing unfortunately
lol
then youre on latest
i literally have lts
how do i make a deck that starts with no cards and with tags? my attempt just didnt remove any cards and made 13 tags every frame
your event needs to return true or else it's re called
ah thanks the packs work fine now
what about the 0 card deck?
does balatro/steamodded have a console/log so I can test events and see if they are activating properly?
whoops i cant read apparently, its literally all in the wiki
P_CENTER_POOLS tables are integer indexed
what does that mean
OH SHIT
G.P_CENTER_POOLS.somePool = {
1 = <center>{..., order = 1},
...
67 = <center>{..., order=67}
}
I JUST GO TIT TO WORK
gg
wait a sec i might have not
not gg
you just go What
i ment i got it to work
weekly DebugPlus shill (it lets you see the console in game and also has a bunch of other handy stuff)
Does DebugPlus let me spawn jokers for testing?
or c
How do I set a card enhancement's name in steamodded 1.0? Setting it in loc_txt adds the name above the description, but doesn't change the badge. Custom rarity didn't seem to work either
with latest update Ctrl C 
Did something change with how mod icon are loaded?
Nvm didn't see the metadata changes
Hey friends, I'm new around here. I'm a programmer by trade but never touched Lua.
I have a run I started yesterday that exceeded naneinf, so I installed my first mod yesterday - talisman - to keep playing the run and see my hand scores.
Unfortunately Talisman won't play nice with vanilla saves and my e308+ hand scores "Infinity" instead of vanilla "naneinf", and an "Infinity" does not beat a blind, so I am stuck at ante 39.
I am super attached to this run and hyperfixated on keeping it going, so I want to either patch talisman to work with my save, or patch my save to work with talisman.
Guess my questions are - how do you get started on this? I read up on https://learnxinyminutes.com/lua/ enough to know what I'm reading.
What now? I tried looking through the mod code to find either the save format or the scoring function but if I understand correctly, these functions are part of Balatro source code, and the mod just patches them?
Should I be looking through the source code? Running with a runtime memory editor? How do I get started working on this?
Thanks in advance from a hyperfixated noob
pretty sure math is working on patching talisman to be compatible (one-way at least) with vanilla saves
until then there's not much you can do, there's the option of simply starting a new run with the same seed and using debug to get back to where you were
@lofty socket I made a small change, try seeing if it makes your save work when loading with this version
Please do make a backup though in case I screwed something up
how does voucher lvl 2 only appear in shop after lvl 1 has been bought?
if it's not documented in smods just look at how it's defined in the original game.lua center list
very likely the same thing
pools r complicated lol
Yep
anyone got the code to abandoned deck? still trying to make a 0 card deck and i just realized abandoned deck's code could be useful since it removes cards
for k, v in pairs(self.P_CARDS) do
local _ = nil
if self.GAME.starting_params.erratic_suits_and_ranks then _, k = pseudorandom_element(G.P_CARDS, pseudoseed('erratic')) end
local _r, _s = string.sub(k, 3, 3), string.sub(k, 1, 1)
local keep, _e, _d, _g = true, nil, nil, nil
if _de then
if _de.yes_ranks and not _de.yes_ranks[_r] then keep = false end
if _de.no_ranks and _de.no_ranks[_r] then keep = false end
if _de.yes_suits and not _de.yes_suits[_s] then keep = false end
if _de.no_suits and _de.no_suits[_s] then keep = false end
if _de.enhancement then _e = _de.enhancement end
if _de.edition then _d = _de.edition end
if _de.gold_seal then _g = _de.gold_seal end
end
if self.GAME.starting_params.no_faces and (_r == 'K' or _r == 'Q' or _r == 'J') then keep = false end
if keep then card_protos[#card_protos+1] = {s=_s,r=_r,e=_e,d=_d,g=_g} end
end```
i think this is it, but there might be some patches or smth (game.lua)
the self.GAME.starting_params.no_faces line
... oh
yeah it's the starting_params.no_faces
so like i'd add to the "_r == 'K' or _r == 'Q' or _r == 'J' " part with all the other types of cards and it'd start with no cards?
you could lovely patch in there I suppose
might also be able to pretend your deck is actually a challenge (the _de parts)? that might have some unintended side effects though lol
or just manually remove cards on apply similarish to what checkered deck does (see back.lua:240)
from my low understanding all i can see checkered deck doing is changing 2 suits into 2 others, nothing about adding or removing cards
you could probably destroy all cards instead of change suits
won't you just instantly lose if you have 0 cards in the deck?
i think its supposed to be jou get a bunch of standard packs
yeah thats what i want it to do
you start with no cards but you make your own deck with 13 mega standard packs
yeah so instead of changing the suit you delete the card
but maybe have 1 card left if this is the case
here's a deck I coincidentally have for testing
SMODS.Back {
key = "test",
loc_txt = {
name = "testing",
text = { "removes all but 12 cards" }
},
apply = function(self)
G.E_MANAGER:add_event(Event({
func = function()
local i = 1
while i <= #G.playing_cards do
local v = G.playing_cards[i]
if i > 12 then
v:remove()
else
i = i + 1
end
end
return true
end
}))
end
}
oh so like "if v.base.suit == 'diamonds'
destroy.card" (i know thats now what the destroy card code looks like but ill make it better later)
(and also do this for all 4 suits)
theoretically
or without the suit check
you'll run into a fun programming issue where you're modifying the size of the list (table) you're iterating which can cause all sorts of whackiness
if you remove all cards
ah
yeah watch out for this
which is why I manually keep track of the index i in my code instead of the for k, v in pairs()
it's very easy to simply
local i = 1
repeat
if <condition> then
cards[i]:remove()
else
i = i + 1
end
until not cards[i]
preferred solution for me
doesn't need a break
you could also do the same exact thing with a while loop and it'd function the same but regardless
assuming there's always at least one card in the list (if there isn't repeat would be prone to breaking here)
hm, trying to remove every card with this code only removes all cards until 1
how does abandoned do it
like this
which i do not understand at all
both of the jokers in context.end_of_round proc wayyy more often than they should and i feel like theres an obvious solution to this i dont know
end_of_round is called for each individual card
elseif context.end_of_round then
if not context.blueprint then
if self.ability.name == 'Perpetual Stew' then
if G.GAME.blind.boss then
self.ability.extra.h_size = self.ability.extra.h_size + self.ability.extra.bonus
G.hand:change_size(self.ability.extra.bonus)
card_eval_status_text(self, 'extra', nil, nil, nil, {message = localize('k_upgrade_ex'), colour = G.C.MONEY})
elseif self.ability.extra.h_size - self.ability.extra.h_mod >= 0 then
self.ability.extra.h_size = self.ability.extra.h_size - self.ability.extra.h_mod
G.hand:change_size(-self.ability.extra.h_mod)
return {
message = localize{type='variable',key='a_handsize_minus',vars={self.ability.extra.h_mod}},
colour = G.C.FILTER,
card = self
}
else
return {
message = localize('k_eaten_ex'),
colour = G.C.FILTER,
card = self
}
end
you need to check against context.individual
thank you
The important part for Abandoned I imagine is:
if self.GAME.starting_params.no_faces and (_r == 'K' or _r == 'Q' or _r == 'J') then keep = false end
I'm guessing the game automatically deletes the cards that are marked to not be kept
Not quite—it seems that if keep is false it doesn't add the card to the list of card prototypes
so you probably want something like
if self.GAME.starting_params.MY_MOD and self.GAME.starting_params.MY_MOD.MY_PARAM then keep = false end
probably as a patch
elseif context.end_of_round then
if context.individual and not context.blueprint then
if self.ability.name == 'Perpetual Stew' then
if G.GAME.blind.boss then
self.ability.extra.h_size = self.ability.extra.h_size + self.ability.extra.bonus
G.hand:change_size(self.ability.extra.bonus)
card_eval_status_text(self, 'extra', nil, nil, nil, {message = localize('k_upgrade_ex'), colour = G.C.MONEY})
elseif self.ability.extra.h_size - self.ability.extra.h_mod >= 0 then
self.ability.extra.h_size = self.ability.extra.h_size - self.ability.extra.h_mod
G.hand:change_size(-self.ability.extra.h_mod)
return {
message = localize{type='variable',key='a_handsize_minus',vars={self.ability.extra.h_mod}},
colour = G.C.FILTER,
card = self
}
else
return {
message = localize('k_eaten_ex'),
colour = G.C.FILTER,
card = self
}
end
elseif self.ability.name == 'Experienced Joker' then
self.ability.mult = self.ability.mult + self.ability.extra.mod
end
end
that procs less often but still too often
i tried checking for individual first, putting end of round in the existing individual check, and that seemed like it would never check for end of round after beginning the individual check so that didnt work
not sure how im supposed to be checking it
changing the < to <= might just work?
otherwise this should work
while #G.playing_cards > 0 do
G.playing_cards[#G.playing_cards]:remove()
end
changing the < to <= worked, thanks so much!!!
the deck is now fully functional lets gooooo
always important to know whether you're working with less-than or less-than-or-equal nodnod
im still not that good at coding so i cant really tell whats wrong with my code most of the time 😅
how do you make some joker code triggerif the number its going to become is a number you want it to do something on? currently working on a joker of mine and it doesnt trigger on the hand where it reaches the desired number, it triggers after which is irritating 😭
calculate = function(self, card, context)
if context.after and not context.repetition and not context.blueprint then
card.ability.extra.chips = card.ability.extra.chips + card.ability.extra.chips_gain
card.ability.extra.mult = card.ability.extra.mult + card.ability.extra.mult_gain
return{
message = "Cooking!",
colour = G.C.CHIPS,
card = card,
}
end
if context.joker_main then
if card.ability.extra.chips >= 20 then
SMODS.eval_this(card, {
message = localize{type = "variable", key = "a_chips", vars = {card.ability.extra.chips}},
chip_mod = card.ability.extra.chips,
colour = G.C.CHIPS,
})
if card.ability.extra.chips >= 20 then
card.ability.extra.chips = 0
end
end
if card.ability.extra.mult >= 20 then
SMODS.eval_this(card, {
message = localize{type = "variable", key = "a_mult", vars = {card.ability.extra.mult}},
mult_mod = card.ability.extra.mult,
colour = G.C.MULT,
})
if card.ability.extra.mult >= 20 then
card.ability.extra.mult = 0
end
end
end
end
(image for reference)
oh! its because you have your actual increase context set to "after" which means the number is only going to go up after the joker has been scored
ooooooh GOODLORDWHATISHAPPENINGINTHERE~1
I'm confused, isn't the current behavior in-line with your joker's description? or will you change that too?
i'd prefer it to give it when it hits 20 (in the same hand), not after the hand where it reaches 20
but yeah right this is also just what your joker behavior, is-
ah so you'll be changing the description to match, I see
you can probably change that description then
yeaaaa
but also, so
how do you let a card stay on screen, like that one glitch where cards persist on screen and you can move them around
you can either move the 'cooking' code to inside the joker_main thing
or make it context.before
isnt after used for after a hand is played? so if its not in a after context, wouldnt it not work how its supposed to work? /genq
could make it context.before like Luna said yeah
skdfjhsdfjh uh--
okay, after is used for effects that happen after everything is scoring, like how ice cream and seltzer lose stuff after it happens
Not sure. I'm guessing the card just doesn't get "cleaned up" properly. You just need the card to be in the middle of the screen
but you want the trigger to happen on the same turn it increases, so you can use context.before so that it increases after the hand is played but bot after its scored
(also, you should probably fix your indentation)
like i want a friend, its being weird though
good idea
think effects like space joker or spare trousers
LMAO
"bye"
how do i fix this
He will escape through the monitor.
sorry im just insanely stupid, where should the context.before go in the code? i do apologise 😭
if context.after -> if context.before
i think my joker is emplaced in joker and G.play???
is it the superposition joker
(cuz superposition means it's in 2 places at once)
i spawned regular jimbo and i cant sell any of them
i think that the central one is a jimbo, and the one near the jokers is my joker
if G.play then
G.play:emplace(card)
end
end,```
why cant i sell my jokers
what is this
set_ability is run when the joker appears in the shop or collection???
yea i think sp
no i know that's what it is
card is a variable that you declared in set_ability so
the card is spawning itself?
if you wanted to create jimbo here
you'd do it with G.jokers not G.play
here's the code that would actually create a jimbo
local card2= create_card("Joker", G.jokers, nil, nil, nil, nil, "j_joker")
card2:add_to_deck()
card2:set_edition({negative = true})
G.jokers:emplace(card2)
i included the set edition line as an example if you wanted to do that
that's how you set editions when you do this
he doesn't want to create a jimbo in the joker slots
ahhh
i think bettma's mobile joker does that if it's placed in the hand?
also i don't think you can sell them because they're not being made as jokers?
you'd probably just do the same thing as up here without the G.jokers:emplace
I'm working on a fully featured, robust save editor for Balatro. Is there a list of all joker, planet, tarot, etc cards by their names in the code? e.g. j_perkeo j_hanging_chad etc
game.lua:368 and everything below it
I suppose you're already aware of https://balatro.shorty.systems/?
Perfect, this is even better than I hoped for
I am, I haven't seen a save editor for putting in new vouchers, jokers, etc. Or deleting them for that matter so I started with that and I'm continuing to add more stuff
sounds good 👍
How can someone start modding Balatro?
regardless of if you mean playing or creating mods, probably you want to start here: https://github.com/Steamopollys/Steamodded/wiki/01.-Getting-started
thanks
all planet cards, all seals, and most spectral cards refuse to change textures and i don't know why
i changed every texture to pure red for demonstration
i don't get how it can happen when they're on the same atlas
do you have any other mods installed?
nope
i had one but i deleted it
and i sent it to a friend who never had any mods so it can't be that
@frosty dock @hardy viper Thanks for the advice and help, it works now, and I cut down the logic from 130 lines of code to about 70 lines of code from cutting out the function hook, and doing everything solely within the calculate function
(Oh and it uses keys now, and not ability name)
I wonder how hard it would be to make a little "mini ante" with custom blinds
Yeah I kinda stopped working on that stuff cause DebugPlus was just much simpler and works nicer with mods
Iirc I have some incomplete card manipulation for my save editor
Not sure if it was ever pushed or what
YESSSSSSSSSSSSSSSSSSSSS tysm aaaaaaa ;-; can finally get past ante 39
Saved my run!!!
I do still have a backup in case something goes wrong, I'll let you know. Thanks so much!!
yw :)
On another subject, is this an appropriate place to ask if I run into lovely errors?
My game consistently crashes when I try to rearrange my planet cards, I believe this was happening before I started using Talisman as well
ya share those errors here
some spectral cards are part of the "spectral" sprite sheet, and others are part of the "tarot" sprite sheet iirc
Discord didn't let me paste the whole thing lol so here's the error https://pastebin.com/C4Pe4WpB
My save is also attahced. To reproduce: try to rearrange planet cards. I sometimes get this error just for hovering over them too.
Pastebin.com is the number one paste tool since 2002. Pastebin is a website where you can store text online for a set period of time.
can you provide the log file in Mods/lovely/log?
st+ is being mid idk 
I'm more interested in what functions/common_events.lua:2957 looks like
oh also while you're in there Mods/lovely/dump/functions/common_events.lua
Which one? I got a whole bunch named stuff like
lovely-2024.12.11-14.06.21.log
lovely-2024.12.11-14.07.33.log
lovely-2024.12.11-14.54.45.log
lovely-2024.12.11-14.56.45.log
lovely-2024.12.11-14.59.52.log```
open them and find the one matching the error you're getting i guess
they're timestamped so
Oh oh the thing after the dash is a timestamp
I believe this should be it. I have several mods in my Mods directory as indicated by the logs but only Talisman is loaded.
this would be helpful too
there ya go friend
cheers
2957: localize{type = 'descriptions', key = _c.key, set = _c.set, nodes = desc_nodes, vars = loc_vars} 🤔
wait your error line moved around???
wdym?
first time it was 2957, now it's line 2960
This might not be the exact correct log then
2960: G.GAME.hands[cfg.hand_type].level,localize(cfg.hand_type, 'poker_hands'), G.GAME.hands[cfg.hand_type].l_mult, G.GAME.hands[cfg.hand_type].l_chips, this one seems more likely for it to crash on
Went in and triggered the crash again, here's the new error and new log https://pastebin.com/mZtuiSWL
Pastebin.com is the number one paste tool since 2002. Pastebin is a website where you can store text online for a set period of time.
This time they should match I hope
yeah now they both point at 2960 which makes more sense anyway
(and 2957 also points to this line on my local copy with only steamodded+talisman)
I'm not sure why this happens, but I can fix it
Spoken like a true programmer
try putting this in a random folder in Mods
as given
Can I append it to an existing lovely.toml in one of the mods?
if you prefer, sure
(minus the header)
Lol i was just about to say it wouldn't start. Removed the header and now it starts
Yup no crash now!!
Weird. Just for my information, what are the versions of your:
-balatro
-lovely
-steamodded
-talisman
?
(normally this is shown in the crash log but since that also crashed...)
Balatro 1.0.1m-FULL
Steammodded 1.0.0-ALPHA-1206d-STEAMMODDED
Talisman 2.0.2 but with a change math made for me yesterday to allow me to play a vanilla save, zip [here](#💻・modding-dev message)
Lovely 0.6.0
Now I'm curious, why is that weird? Could you not replicate the crash on your setup?
No, I could
Honestly it might just be due to my fucky save, I started it on vanilla and installed talisman midway through
but it seemed like an error that should've popped up constantly by anyone playing balatro
so I'm guessing it's because you continued a save with talisman midway yeah
Thank you anyway :))) I'm really attached to this run lol this discord is helping me keep it alive on a breathing machine and IV
local Jok1 = pseudorandom_element(jokers, pseudoseed('BerkanoChooseDup'))
local Jok2 = pseudorandom_element(jokers, pseudoseed('BerkanoChooseDbf'))
if #G.jokers.cards ~= 1 then
repeat
Jok2 = pseudorandom_element(jokers, pseudoseed('BerkanoChoose'))
until (Jok1 ~= Jok2)
end``` is there any edge cases i havent considered?
let me test this first
it might fuck up when having no jokers
the case where there are 0 jokers? since 0 is not 1, the repeat would go on forever comparing nil to nil
(or just crashing on Jok1)
it can only use when 1
can_use = function(self, card)
return (G.STATE == G.STATES.SELECTING_HAND) and (G.jokers.cards) and (#G.jokers.cards > 0)
end,
(yes its a consumable)
is there a list of states somewhere, by the way? I've cut a few corners in my foree into modding and haven't actually put state checks into my consumables yet
globals.lua
steamodded defines a few more
examples being the one for custom booster packs
(it is one state, not one per consumeable type)
Oops! The game crashed:
functions/misc_functions.lua:267: bad argument #1 to 'pairs' (table expected, got nil)
uh oh
how do i get a list of all jokers
oh im just an idiot
ok i think this is good
noqw
dbf and dupe
thanks!
i've got planets and spectrals now, but i don't know what the key for seals is
dont tell me.....
do i really have to put all lovely patches in one big lovely.toml?
also, how do i log stuff to the lovely console?
you can split them up into separate .toml files if you put them all into a lovely/ directory
print() is the easiest way
the dump?
Mods/lovely/dump
you can also use steamodded functions for logs if you need actual logs and not just debugs
i am not modding balatro, i just dont know of another place to talk about lovely lol
[manifest]
version = "0.0.1"
dump_lua = true
priority = 0
[[patches]]
[patches.pattern]
target = 'src/menu/mainmenu/mainmenu.lua'
pattern = "Programming art and sound effects - Noba"
position = 'after'
payload = '''
SwitchMod by teesh3rt
'''
match_indent = true
this is my patch, it dosent show it as a regex mismatch but nothing is happening! is there something wrong?
this is the way i saw steamodded doing things so im just doing it like that
ah, lovely does have own discord / thread
there's #1214591552903716954 message but it's not as active
I think lovely doesn't give any warning if path is incorrect
so if file doesn't exist
is this a patch for steamodded...?
i don't think you can do patches like that
read message above the one you replied to
no, it's a patch for a different game
ah
the lovely dump should have everything post-patches so you can check if it was applied there
the strange part about it is that lovely dosent even produce a dump
even though i tell it to dump_lua
pretty sure dump_lua doesnt do shit
iirc files deeper than 2 folders aren't considered by lovely
it's always true
my file structure is:
Mods/
switchmod/
lovely/
core.toml
lovely/
log/
game file
not your file
in other words you can't do anything until it gets fixed for lovely
oh god darn it
wait, really?

balatro never has this issue
meth knows about it, right?
ask em
beatblock is made with love2d???
well there isn't an issue for it on github so uh will do
how'd you not know that
you're making an issue on github? otherwise we can just tag him
I left a message on discord
but feel free to create an issue, will probably work better as a reminder
an issue would be best
is there a lovely discord i don't know about?
lmao
hi meth
Seems to be the way things are heading /shrug
do you just magically know when people talk about you or what
make sure that PR is updated with any changes made to master and I'll give it a legit review
I think it's time to merge that feature since I haven't made much progress on the manifest feature
woo
wait I thought this issue
iirc files deeper than 2 folders aren't considered by lovely
was talking about thetargetbeing more than 2 folders deep
while this issue
https://github.com/ethangreen-dev/lovely-injector/pull/73
seems to be about thelovely.tomls being more than 2 folders deep
woooo
ah alright
so are these 2 seperate (confusingly similar) issues or did I misunderstand?
yes
I used "target files" specifically to distinguish from that one, but I guess it still caused confusion
latter, there's never any need for double nested lovely patches i don't think