#💻・modding-dev
1 messages · Page 83 of 1
This is definitely outdated Balatro, this is crashing at deck skin API which iirc wasn't added until 1.0.1g
1.0.1m seems to be avalible?
Not the API, but the vanilla functionality for it
if you're getting into modding balatro, I'm assuming you already spent quite some time playing the game, you should probably go buy it
I bought it on other platforms, I only pirated on pc because I wanted to mod it...
yeah it absolutely sucks that you have to pay for it on every platform
I apriciate the game a ton especially because im obsessed with cards and I've played it on my switch, Ive been meaning to get it on my phone too I dont usually pirate that the reason why I did
I wouldn't disclose that on here
do you think 1.0.1m with the same steps would work here?
what letter would work best there seems to be alot..?
Sorry man, doesn't feel right to openly discuss this any further in this server
You should be able to figure out how to proceed from here though, there should be enough breadcrumbs in this chat for you
I understand, I believed you've helped alot, thank you for everything so far(:
if you wanna support the game further when youre low on cash, perhaps wait for a sale, thats when I got it on both switch and steam (which i currently cant play lol i dont have a pc rn)
I only thought about getting it on Switch as I didn't know this game had a modding scene
same with Inscryption I think
Hi! New modder here; How could I get a joker to run code for each card discarded? I got this code working for each card played; just unsure how to get it working for discards instead. Here is the code I am using (I am using steammodded)
calculate = function(self, card, context) if context.individual and context.cardarea == G.play then -- run code end end
there should be some sort of context.discard, see https://discord.com/channels/1116389027176787968/1247703015222149120
I was looking for this thread; ty!
Got it working by using context.discard if anyone is wondering in the future
the reason this wasn't working was because i didn't return true at the end of my event call… 😤
don't disable ping next time but thanks
ping disable is instinct
hope this can save someone some time: got an undisable slash enable boss function working
Why Steamodded-1103a process .vscode folder?
Is it not possible to just create a SMODS.Shader alone without an edition for it to be used in Card:draw_shader? Either there's an issue with it or I got the path wrong, can't find a mod to cross-reference (Cryptid does it in an unusual way)
nvm I forgot the prepend key again..
having some issues with the code - it works all fine, shows the message at the end of the played hand, etc - but it doesnt add the chips to the actual score? i have no idea why, i presume im missing something trivial but no clue 😭
Try mod_chips instead of chips
for all the .extra.chips or?
context.joker_main's return
ah, gotcha
BOO SURPRISE I'M BACK TO MAKING JOKER ART FOR ORIGINAL SOUND
I know it's not much but at least i'm back
i tried all three locations just to be sure, it either does the exact same as before or the message just says Nil 😭
🫂 so am i
now i wonder which joker to do next... tbf i almost forgot what i DID have...
i wanna be absolutely sure, do you mean the chips = card.blah.blah.blah to turn into chip_mod? just so i dont have to test it mulitple times
chip_mod = card.ability.extra.chips,
cool, jsut making sure
ty 
it works!
ty
is that the same for mult and the like? mult_mod? 
Am i not able to make my own values in the config? i get an error when i do math with the steel value
config = {extra = {mult = 20,chips = 50,mult_gain = 5, chip_gain = 25,Xmult=2.5,secAbility = false, steel = 0}},
--math below
card.ability.extra.steel = card.ability.extra.steel + 1
where's your calculation code going?
its in a calcuate function and is used when a steel card is scored in a straight flush
if context.individual and context.cardarea == G.play and not context.other_card.debuff and not context.end_of_round and --Activates secert ability
context.other_card.ability.name == 'Steel Card' and next(context.poker_hands['Straight Flush']) and not context.blueprint and not card.ability.extra.secAbility then
card.ability.extra.steel = card.ability.extra.steel + 1
if card.ability.extra.steel >= 5 then
card.ability.extra.secAbility = true;
return {
message="Secert Ability Active!"
}
end
end
i have it in the loc_vars section too
not context.end_of_round and Activates secert ability?
i dont want it to fire if this already happened
I mean, is the Activates secert ability supposed to be in a comment?
yeah lol
yeah it wraps on the next line
the function is function(self, card, context) right?
yes
how are you testing?
i was using debug plus and i played a straight flush of all steel and got the error
try spawning the card in fresh
Im not getting an error but the code isnt working either
can you send the entire function?
calculate = function (self,card,context)
if context.individual and context.cardarea == G.play and not context.other_card.debuff and not context.end_of_round and --Activates secert ability
context.other_card.ability.name == 'Steel Card' and next(context.poker_hands['Straight Flush']) and not context.blueprint and
not card.ability.extra.secAbility then
card.ability.extra.steel = card.ability.extra.steel + 1
if card.ability.extra.steel >= 5 then
card.ability.extra.secAbility = true;
return {
message="Secert Ability Active!"
}
end
return {
message = "Steel!"
}
end
if context.individual and context.cardarea == G.play and not context.other_card.debuff and not context.end_of_round and
context.other_card.ability.name == 'Steel Card' and card.ability.extra.secAbility then
return {
message = localize { type = 'variable', key = 'a_xmult', vars = { card.ability.extra.Xmult } },
Xmult_mod = card.ability.extra.Xmult
}
end
if context.joker_main then
return {
message="Fence!",
mult_mod = card.ability.extra.mult,
chip_mod = card.ability.extra.chips
}
end
if context.before and next(context.poker_hands['Straight Flush']) and not context.blueprint then
card.ability.extra.mult = card.ability.extra.mult + card.ability.extra.mult_gain
card.ability.extra.chips = card.ability.extra.chips + card.ability.extra.chip_gain
return {
message = "Charge!",
card = card
}
end
end
try lua return { extra = { message = 'Secret Ability Active!' } }
there's nothing that just handles a plain message return in this context from what I can see on my phone
wait no
ignore that
can you throw some print commands in there and see where it's getting to?
yea
its running all of it just not returning the message
i placed a print before the if and before the return and both printed something
huh
worth taking a look at the lovely dump of state_events to see where its returning to
where excatly is that?
mods/lovely/dumps/functions
then search for individual = true and it'll be one of the eval_card calls it brings up
it found it in 3 different spots which one is it
whichever one is evaluating G.play
this it?
local eval = G.jokers.cards[k]:calculate_joker({cardarea = G.play, full_hand = G.play.cards, scoring_hand = scoring_hand, scoring_name = text, poker_hands = poker_hands, other_card = scoring_hand[i], individual = true, callback = function(card, eval, retrigger)
yeah
what do i do with it then?
look in the bits below to see how the eval table is used
I dont see anything that would explain why it isnt sending a message
probaly because i dont know what im looking at lol
let me grab my dev machine, hold on
ight
try the extra thing I sent earlier

alternatively if that doesnt work, you can use card_eval_status_text
What mod interface is this using?
I'm assuming this isnt aure or anyone else here?
I think this is the repo https://github.com/Rizwanelansyah/ezmod
seems to be loaded using ony lovely as far as I can tell
i'm working on my mod, but the code is quite tough to manage with it being all in the same file
could i get some help with this?
you can use SMODS.load_file("path/to/file.lua")() to load other lua files
does that do anything other than just loadfile(path)
haven't we been over this before? 🤔
dotn remember
oh maybe it was someone else then
you can check the code here https://github.com/Steamopollys/Steamodded/blob/main/loader/loader.lua#L550
ya
all it seems to do is name the chunk after the mod calling it and use the mods directory as the working directory instead of the typical one
idk any more than you do 🤷
yeah I think it's better at showing the mod that caused an error?
instead of being a path that's cutoff
If you wanted to use loadfile you might as just well use love.filesystem.load anyways
that function is an exact equivalent of loadfile just with love restrictions so
+one of them is shorter to type so 
most stuff seems to use SMODS.load_file
I get paid by the character I code though, so 
SMODS.load_file does all the path work for you and has better crash info 🤷♂️
works, thx 🚶
👋 actually, is there anything that needs to be done for lovely patches?
virgin if statement vs chad logical operation ...
won't somebody think of the readability 😩
to be fair its readable in this instance
youre right that readability does usually become an issue though
I do want to clean up SMODS code at some point, mostly just afraid of how much it'll break all the forks and PRs 
lol fair
sorry to butt in, but having an issue with math.min - after adding it in, it now just wont add anything? no matter what i play, it just stays at 0 
(im gonna presume im just missing something trivial, but no clue)
aight i got it: just needs to be in a subfolder called lovely
either named lovely.toml or in a subfolder named lovely yeah
(should say that somewhere on the lovely github)
you've set mult and mult_gain in config?
mhm! it works fine without the math.min, i just want to impose a limit on how much it can gain
you don't need your own mod path and also it adds proper debug info for crash logs
Mult and mult gain are both 0 lol
It’s not gonna increase at 0 :p
do yall have golden ticket's code? I need to build off of it for a joker im working on.
you can extract the games code from the exe using 7zip then open card.lua and search for golden ticket
that will clearly crash when id is nil?
quick question, do you guys know how I could add an audio clip to play when a specific joker triggers?
specifically for popcorn & baseball card (referencing a joke amongst friends)
oh nvm I guess lua doesn't do that
also, how do i change the images for the base jokers? i tried to use like the collage thing within the games files but that didnt change anything
would be a disaster if it did lmao
does anyone know of a good way to change joker descriptions in the middle of a game? ive been putting a descrption in the extra array but no formatting works
like changing the entire description?
just a part of it
could you give an example?
i have a specail ability that activates on a joker when a condition is met and i want to change the hint on the description to the effect of the ability
I dont want to intrude so please do finish helping out shado first, I am interested in learning how to mod this game. I have some familiarity with Java and that is about it. Where do you all recommend me starting to look in terms of modding the game?
i just read the example mods on under the steamodded folder
it gives a good explanation on some of the basic stuff
Thx, gl with coding
Ah, I see the issue yeah. You're trying to put a variable within a variable right?
yes pretty much
yeah I doubt that'll work
dam
you should be able to manually insert it yourself though
am i able to just refernce loc_txt.text and append it?
vscode give a blue underline and yells at me when i did that
so i didnt try it
technically you could but you'd have to re-parse
I meant why don't you do something like this
loc_vars = function(...)
local ability_text = normal .. "/" .. odds .. " chance to add a random edition to a played card"
return { vars = { maxretrig, normal, ..., ability_text } }
end
How dumb would it be for me to attempt to piece together what is given in example mods and attempt to make a mod myself without knowing lua?
Cause I have done something similar with origins mod in minecraft but this seems like a whole other can of worms
if you don't like this you could also reparse the localization, or use a different localization key
If you're familiar with programming it's not that bad. If you've never coded before I beg you to please study lua programming first
I have a few years expirence in Java through college courses but I still am not the best at it
Probably good enough to start. At least you won't be wondering what a for loop is, only how to format it 🙃
Only problem is the syntax looks so foreign to me lol
Is there a compiler that is recommended to use or does that not really apply for modding games?
It's Lua so it's jit compiled anyway. All that's built into the game
Welp time to start learning ig lol
Anyone have any recommendations on what I should try to make first? Like baby's first mod?
probably a joker or deck or smth
that sounds like a good idea
Oki
Would anyone mind hopping in a vc with me in a lil to guide me while I start, kinda like training wheels, if not it's totally fine
I suggest you just check out the steamodded documentation and examples
and possibly also other mods on github, and how they do stuff
Oki thank you all
Oh hey there is already a deck of 4s in example mods lol
I am seeing the word Atlas alot what does that meanm
Also sorry in advance for the biblical flooding of questions that is about to commence
Oh wait nvm
I see now
SMODS.Back{
name = "Deck of fours",
key = "fours",
pos = {x = 1, y = 3},
config = {only_one_rank = '4'},
loc_txt = {
name ="Deck of fours",
text={
"Start with a Deck",
"full of {C:attention}Fours{}",
},
},
what fuction does the pos variable have?
pos is the location in the picture
so the image for the deck is the first pic on the third row
ooooh for when I implament a texture file?
yeah
is it required to have a texture out of curiosity?
SMODS.Atlas {
-- Key for code to find it with
key = "ModdedVanilla",
-- The name of the file, for the code to pull the atlas from
path = "ModdedVanilla.png",
-- Width of each sprite in 1x size
px = 71,
-- Height of each sprite in 1x size
py = 95
}
i would do one
also ignore what i said about atlas i didnt realize that it was just referring to a modded joker example
rn I am looking to understand how to make a deck
I am gonna make a wee little deck
basically you have only 2s, and if I can learn how to do it, start with a wee joker
so for when I do make an image for the deck what coordinates would be the first image?
okay thanks
for a second I thought that was a reaction not coords lol
so I assume the only_one_rank config is used to set all card ranks to a specified number?
yes
apply = function(self)
G.E_MANAGER:add_event(Event({
func = function()
for _, card in ipairs(G.playing_cards) do
assert(SMODS.change_base(card, nil, self.config.only_one_rank))
end
return true
end
}))
end
what does this do?
i dont really know, havent made a deck yet
fair
is there any comments with it?
nope
i love undocumented code
its so great (sarcastic)
I wonder how hard it is to make a suit that is classfied as wee lol
i might add it once I get this all figured out somewhat
anyone that is more knowledgeable on decks mind explaining this to me?
wait nvm I figured it out
kinda-ish
Not sure what hit mean exactly as 'classified as wee' but smods.suit is pretty easy
bascially make a custom suit that is just called wee
Bascially I wanna make a dumb little stupid mod that revolves around the wee joker and similar concepts
only problem is I dont know lua
I know a decent amount of java so I am just trying to apply some of that gen coding logic to this
I mean I'm working on a mod wget suits she I hadn't done coding since basically two introductory programming classes, one python one c++ over 5 years ago
gl with that btw, I believe in ya
Thank you :3
I made the icon for my wee little mod
ok so what all do i need to put in my wee mod folder for it to work?
cause I have no idea what it needs for me to start testing stuff
cause I like to test stuff as I am coding not just code the whole thing then test it
This is how you set up one
SMODS.Atlas{
key = "modicon",
path = "path_to_modicon.png",
px = 34,
py = 34,
}
SMODS.Back {
name = "A Wee Little Deck",
key = "twos",
-- pos = {x = 0, y = 0},
config = {only_one_rank = '2'},
loc_txt = {
name = "A Wee Little Deck",
text = {
"Start With a Deck",
"full of {C:attention}Twos{}"
},
},
},
apply = function(self)
G.E_MANAGER:add_event(Event({
func = function()
for _, card in ipairs(G.playing_cards) do
assert(SMODS.change_base(card, nil, self.config.only_one_rank))
end
return true
end
}))
end
}
here is what I have so far
where would I put that code?
Anywhere like any SMODS object (preferably in your main lua file)
okay
is adding the atlas object necessary or is that just part of the example provided
For the mod icon yes
okay
If you try to refer to a spritesheet you usually use SMODS.Atlas
I only have one image as of rn, it isnt really a sprite sheet
Doesn't matter
.
Above or below, if it's for your modicon it doesn't matter
If you try to load your back atlas tho it will be above all other SMODS.Back objects
also sorry if ya have to repeat yourself or answer dumb questions. this is my first time with Lua
what is px and py?
with Lua or with coding in general?
The size of your image in the spritesheet
oki
thx
SMODS.Atlas{
key = "modicon",
path = "path_to_modicon.png",
px = 256,
py = 256,
}
SMODS.Back {
name = "A Wee Little Deck",
key = "twos",
-- pos = {x = 0, y = 0},
config = {only_one_rank = '2'},
loc_txt = {
name = "A Wee Little Deck",
text = {
"Start With a Deck",
"full of {C:attention}Twos{}"
},
},
},
apply = function(self)
G.E_MANAGER:add_event(Event({
func = function()
for _, card in ipairs(G.playing_cards) do
assert(SMODS.change_base(card, nil, self.config.only_one_rank))
end
return true
end
}))
end
}
is anything else needed for my deck for it to run?
the example mod for the deck doesnt give much to go off of
The path of your SMODS.Atlas is wrong, it doesn't have to literally be this
oh okay
thank you
It has a SMODS.Atlas reference in it
So the game will accept high res textues. but pixel art will probably look better. It does weird things to bigger imsges
For references 34x34 is the default
got it
^ for modicon
Some atlases uses different dimensions
They pasted the atlas path as it was written as so I'm taking precaution lol
oh wait
I am dumb I just realized my mistake in doing that haha
I blame the hours of hw I had to do today
college is killer
-- Width of each sprite in 1x size
px = 71,
-- Height of each sprite in 1x size
py = 95
so is this the default size?
Yes, for jokers/decks/consumables etc
okay thank you
i'm trying to check if the selected joker has a sticker, and the code i've tried doesn't seem to work
for k, v in ipairs(SMODS.Stickers) do
if G.jokers.highlighted[1].ability[v.key] then
return true
end
end
so the key for the atlas seciton of the code will be the name of the mod folder right? or am I reading it wrong?
For modicon only, the key needs to be "modicon"
so i dont need to do that because i am using atlas right?
Don't need to do what?
And for everything else is just the name of whatever the png is
Modicons need to be their own image
key = "",
path = "wee_icon.png",
px = 71,
py = 95,
}
SMODS.Back {
name = "A Wee Little Deck",
key = "twos",
-- pos = {x = 0, y = 0},
config = {only_one_rank = '2'},
loc_txt = {
name = "A Wee Little Deck",
text = {
"Start With a Deck",
"full of {C:attention}Twos{}"
},
},
},
apply = function(self)
G.E_MANAGER:add_event(Event({
func = function()
for _, card in ipairs(G.playing_cards) do
assert(SMODS.change_base(card, nil, self.config.only_one_rank))
end
return true
end
}))
end
}
I am confused, here is what i have so far
you need to create an assets folder, then put 1x and 2x in it, then put your image in each folder
Basically the atlas png name is whatever you want it to be. Add is the key I just mozpoke
1x is the normal size and 2x is double the size of your image
Replied to the wrong message
Except the key for modicons is modicon
Also it's a folder called 'assets'
Yea not sure why you made your atlas key empty
Oops 2am moment 😅
oh you're Spanish not latino
How are you assuming I'm Spanish?
'Traduction' though that might be other romance languages too
Wow that example is from last month
Right the correct term is translation
nods
Idk my brain thinks "traduction" sounds english enough 🤷
They sound very alike too, i'll try to avoid doing the mistake again
It's not a big deal. And yeah when you spell it like that it does seem very English
i got the 1x and 2x in my asset folder
what else is needed for me to start testing?
it's called "asset" or "assets"? Needs to be the latter
assets
Good
Did you fix the empty key in your atlas too?
I dont know what to put there
modicon
What did you call your art file in both 1x and 2x?
What
*modicon
wdym
Icon made me think modicon
So I'm confused. You have it set up as the back sprite., but you're talking about modicons
Aren't they trying to make an icon for their mod?
I dunno, I am just copy pasting what is on the template
Are you trying to make art for your deck or for your mod icon?
But I bet it applied as the deck sprite
I am trying to make a deck
But are you trying to set up the image for the deck itself or for the mod icon?
I think so?
Also you have the atlas pos commented out on the deck
Which are you trying to modify?
modicon is optional
oh then ill do that later
Then yeah just Jake sure your 1x image is actually 71x95 and uncomment the pos
Also your SMODS.Back object needs to have an atlas = 'your_atlas_key'
(replace your_atlas_key by the key you've put in your atlas)
so as my code stands rn is the image I have in assets being used for the deck art or mod icon?
SMODS.Atlas{
key = "modicon",
path = "wee_icon.png",
px = 71,
py = 95,
}
SMODS.Back {
name = "A Wee Little Deck",
key = "twos",
atlas = ''
pos = {x = 0, y = 0},
config = {only_one_rank = '2'},
loc_txt = {
name = "A Wee Little Deck",
text = {
"Start With a Deck",
"full of {C:attention}Twos{}"
},
},
},
apply = function(self)
G.E_MANAGER:add_event(Event({
func = function()
for _, card in ipairs(G.playing_cards) do
assert(SMODS.change_base(card, nil, self.config.only_one_rank))
end
return true
end
}))
end
}
Deck art
Waot
Neither
Well it is used as the modicon
But it's the wrong shape
It should be square for that
what dimentions do i need for deck art
They did?
I am gonna ignore it for now since I want to get to testing my deck first
then i will add the mod icon since yall said it is optional
functionality over flavor
Holy shit troubleshooting at 2am is such a bad idea
until it works that is
So to make it not the medicine just give it a different key
If you keep the key as "modicon" it will be for the mod icon, you need to rename it
And include the key on the deck object
Lmao medicine strikes once more
what is the naming convention
oki
ill just do d_art cause it is deck art
SMODS.Atlas{
key = "d_art",
path = "wee_icon.png",
px = 71,
py = 95,
}
SMODS.Back {
name = "A Wee Little Deck",
key = "twos",
atlas = 'd_art'
pos = {x = 0, y = 0},
config = {only_one_rank = '2'},
loc_txt = {
name = "A Wee Little Deck",
text = {
"Start With a Deck",
"full of {C:attention}Twos{}"
},
},
},
apply = function(self)
G.E_MANAGER:add_event(Event({
func = function()
for _, card in ipairs(G.playing_cards) do
assert(SMODS.change_base(card, nil, self.config.only_one_rank))
end
return true
end
}))
end
}
thius good?
should be
ill try it rn
I forgot if SMODS.Atlas preprend the mod prefix
Yes but you should probably do wee_deck or smth. Just so it's clear what it is
oki
The key doesn't need to match the filename?
Right they need to match the path
Though it is convention
Sleep well
so is the key in atlas just for sprite work or is it used for more stuff?
The atlas key is just for the atlas. Other things have keys too
okay
SMODS.Atlas{
key = "wee_deck_art",
path = "wee_icon.png",
px = 71,
py = 95,
}
SMODS.Back {
name = "A Wee Little Deck",
key = "twos",
atlas = 'wee_deck_art'
pos = {x = 0, y = 0},
config = {only_one_rank = '2'},
loc_txt = {
name = "A Wee Little Deck",
text = {
"Start With a Deck",
"full of {C:attention}Twos{}"
},
},
},
apply = function(self)
G.E_MANAGER:add_event(Event({
func = function()
for _, card in ipairs(G.playing_cards) do
assert(SMODS.change_base(card, nil, self.config.only_one_rank))
end
return true
end
}))
end
}
this good?
or do i need to change size proportions for my image?
darn
my mod still isnt showing up in mod list
what else do I need?
oh wait
I accidentally saved the code file as a text doc not a lua file
let me fix that
damn didnt work
Does your mod have a header?
wdym
--- STEAMODDED HEADER
--- MOD_NAME: Edition Examples
--- MOD_ID: EditionExamples
--- PREFIX: edex
--- MOD_AUTHOR: [Eremel_, stupxd]
--- MOD_DESCRIPTION: Adds editions that demonstrate Edition API.
--- BADGE_COLOUR: 3FC7EB
--- DEPENDENCIES: [Steamodded>=1.0.0~ALPHA-0905a]
this?
I thought this was just comments and was not needed...
ill add one
Yeah it's needed
imma try again
nope
wait I might not have saved
let me try one more time
--- STEAMODDED HEADER
--- MOD_NAME: A Wee Little Deck
--- MOD_ID: WeeDeck
--- MOD_AUTHOR: The #1 Erratic Deck Lover
--- MOD_DESCRIPTION: Create a wee little deck that only contains 2s!
--- DEPENDENCIES: [Steamodded>=1.0.0~ALPHA-0812d]
here is my header
yeah it aint showing up on mod list
Why dud you turn the dependent down? Are your still on that old smodded version?
Yes that is required
I just copy pasted
Ah I see. It's just different than the other thing you pasted
You don't need that line at all tbh
so i can delete dependancy line?
Yeah
what table should i use to get a list of all stickers?
You have an extra }
The two in a row there
You're not trying to close the whole object there right? Apply is part of it
found it
okay time to run it back
okay I am so lost I tought i fixed it but i didnt
do you mind deleting the curly bracket for me?
or wait imma try one last thing
SMODS.Atlas{
key = "wee_deck_art",
path = "wee_icon.png",
px = 71,
py = 95,
}
SMODS.Back {
name = "A Wee Little Deck",
key = "twos",
atlas = 'wee_deck_art'
pos = {x = 0, y = 0},
config = {only_one_rank = '2'},
loc_txt = {
name = "A Wee Little Deck",
text = {
"Start With a Deck",
"full of {C:attention}Twos{}"
},
},
apply = function(self)
G.E_MANAGER:add_event(Event({
func = function()
for _, card in ipairs(G.playing_cards) do
assert(SMODS.change_base(card, nil, self.config.only_one_rank))
end
return true
end
}))
end
}
That was the one I meant
But there might be other bracketing issues
thank you
ill try this then attempt to fix any others that pop up
yeah i cant figure out where that extra bracket is
im sorry for all this heh heh
Oh you're missing a comma
On the atlas line
On the back object
Ayyy
now to see if it actually functions
The Wee came out better than I thought tbh
woooooo
okay now to figure out how to make a wee suit
and then the stupidity can really begin
actually what is easier, making a custom suit or having the deck start you out with a negative eternal Wee joker?
if ya want I can shoot you over the mod folder as I update it
can't imagine either would be that tough
I'm not at my computer or I'd accept
Yeah both should be pretty straightforward
i'm getting this crash when attempting to view a joker description
All in the same Lua file right?
okay so I see how to add new jokers but I am confused on how to add a vanilla joker to the starting hand of the deck
should just drop it into the apply function to add the joker
i've resolved this btw
I have no idea on where to even begin looking to find out how to make a custom suit
look at some mods that add custom suits
I can make heads or tales of them
I only started modding balatro today
Also I have never touched lua before
just going to leave this here in hopes to get a follow-up
SMODS.stickers? Just a guess
this is the code i have btw
would I put custom made jokers before or after the back object
doesn't matter
oki
so, is there a way to prompt the game to restart if it detected a mod config option changed after the config tab is closed?
i'm figuring out that i simply can't have on-the-fly joker modification, and i'd really hope there's a way to at least have the game automatically restart for the user so they don't have to do that themselves.
how much should i make a joker that makes all scored 2s trigger again and what should its rarity integer be?
seeing if a config changed is trivial, running that check when the config tab is closed should be a doable with a steamodded patch
i forget the exact syntax for patching a steamodded file tho
you should probably look at "hack" for that; and as for rarity? i'd say common would be fine, given that one is uncommon and covers three additional ranks
I think I know my mistake, it is a problem with sprite placement correct?
what coordinates do I put when accessing a second image in a sprite sheet?
here is what I have so far
cause I just have a deck and the card that repeats all played 2s
anyone working on procedurally generated content? I don't just mean "random haha", I mean unique independent jokers, bosses, etc
okay
so the Wee Mirror would be 1,0 got it
thanks
I got this error again
oh! I found where I went wrong
let me fix that rq
accidentally put a pathway isntead of the key
okay
I have obtained the card without crashing
now lets see if it works as intended
how do I check if a card is a two?
cause I tried replacing is_face with is_2 like a dumb dumb and that didnt work
I am suprised I have gotten this far seeing as I know 0 lua
the closest I know of is RNJoker from Cryptid, which randomizes into completely different joker effects every ante
SMODS.Joker {
key = 'wee_mirror',
loc_txt = {
name = 'A Wee Mirror',
text = {
"Retrigger all",
"played {C:attention}Two{} cards"
}
},
config = { extra = { repetitions = 1 } },
rarity = 1,
atlas = 'wee_deck_art',
pos = {x = 1, y = 0},
cost = 4,
calculate = function(self, card, context)
if context.cardarea == G.play and context.repetition and not context.repetition_only then
if context.other_card:is_two() then
return {
message = 'Again!',
repetitions = card.ability.extra.repetitions,
card = context.other_card
}
end
end
end
}
I just ripped this from the sock n buskin template and I just need to modify the if statement to check for 2s but i dont know how to do that
oh wait i found it
now i hope this workds
SMODS.Joker {
key = 'wee_mirror',
loc_txt = {
name = 'A Wee Mirror',
text = {
"Retrigger all",
"played {C:attention}Two{} cards"
}
},
config = { extra = { repetitions = 1 } },
rarity = 1,
atlas = 'wee_deck_art',
pos = {x = 1, y = 0},
cost = 4,
calculate = function(self, card, context)
if context.cardarea == G.play and context.repetition and not context.repetition_only then
if context.other_card:get_id() == 2 then
return {
message = 'Again!',
repetitions = card.ability.extra.repetitions,
card = context.other_card
}
end
end
end
}
it didnt crash but i dont understand why it didnt repeat when i played a 2 while testing it
oh i am dumb scoring animations are off
it works!
nice!
well, if anyone knows how to patch a steamodded file, or similarly help me figure out how to enable and disable my rebalanced jokers... i'd appreciate it!
I wasn't sure if I was supposed to put it in here or modding-chat, but I'm having trouble with a playing card mod, it was working like a week ago, but now it only shows a fourth of the card skin on each card. I just took a mod someone else made and just replaced the textures. Like I said it worked fine for about a week and then just stop working. Any ideas?
@halcyon fjord what are the dimensions of your card sprites?
the cards individually? or the entire image?
the image
if the image for your playing cards is larger than 923 x 380, that's the problem
oh yeah its literally double that lol
i changed the dimensions to 923x360 and it fixed, tysm
...you mean 380, right?
just making sure, that's all.
yeah i just typed 360 on accident
is this actually a thing?
yeah, every asset in the game is broken up into 71 x 95 tiles.
yeah i know that but i didnt know like the atlas couldnt be bigger than 923x380
i think thats what you're referring to right
no, it can be. it's just that the playing card asset is 923 x 380
so making it bigger or smaller leads to... problems
oh right right
does having it at a different size just completely break it or does it appear bigger in game
i feel like if its higher it just cuts off the edges
but what if its smaller does it just look messed up
you can change the px and py variables of the joker and it'll work fine
?
it works if you use one image for an atlas
pretty sure
ive never had issues with it
fair. you can do that... but that requires knowledge of coding
oh wait i said under the joker i meant under the atlas aha
key = "example",
path = "example.png",
px = HERE,
py = HERE
}):register()```
defines the dimensions of each joker
then under the joker you can use the variable pos to define where in the atlas it is
pos = {x = 3, y = 0}
yeah, but again... this is way more effort than shrinking it down
especially if you aren't using all the pixels of your new size
depends on the desired resolution of jokers
some people could want pretty high res joker art
for example i think SDM_0's Stuff has some pretty high res jokers
for i = #G.P_CENTER_POOLS["Center"], 1, -1 do
local entry = G.P_CENTER_POOLS["Center"][i]
if string.find(entry.key, "c_bunc_the") then
table.remove(G.P_CENTER_POOLS["Center"], i)
end
end
Apparently I did something wrong here
i have no idea what you are trying to do
Remove a bunch of consumables that all have a full key name starting with c_bunc_the
remove them from your consumable slots or from the item pool
Pool
theres probably way easier ways to do it than what you are doing then
theres a variable you can use thats just called in_pool
To be honest I don't know what I am doing
yeah tbh picking up literally any knowledge for modding this game is a pain
the documentation is unfinished and the best way to learn how to do things is just to look at other peoples mods
which is a pain
This is the snippet I know works, which removes booster packs
if (SMODS.Mods["Bunco"] or {}).can_load then
for i = #G.P_CENTER_POOLS["Booster"], 1, -1 do
local entry = G.P_CENTER_POOLS["Booster"][i]
if string.find(entry.key, "p_bunc_virtual") then
table.remove(G.P_CENTER_POOLS["Booster"], i)
end
end
i see
i dont think ive ever referenced anything from bunco so i have no idea how they work their stuff
i also have no idea if the main pool is called Center so
cant help too much on this
):
I am trying to get it to also remove the consumables
Thanks for the reply nonetheless
best of luck
Replaced "Center" with "Consumable" (again, don't know much what I'm doing) don't work too
I can't check source code right now, but in the code consumable is always referred as consumeable
missing the e
thunk cant spell 🔥
I don't think center pools use that though, but I could be wrong
i have literally no idea
times like this the documentation would be very nice to be able to refer to
There is barely any documentation for the source code, but there's plenty for Steamodded :)
have they updated the steamodded docs?
last time i checked it was bare bones asf
oh it looks like it has been updated
at least somewhat
what was updated 
oh maybe not
half the pages have like
2
nevermind last updated sep 14 😭
WE NEED MORE DOCS RAHHH
ZEUSSS, DROP ACTUAL DOCUMENTATION FOR STEAMODDED AND MY LIFE IS YOURS‼️
Still need help ; (
probably bunc_polymino
in the last time since ive moded this game my lovely patches have seemed to magically stopped working
i moved from lovely version 6 to version 5 but they still come up in the dump file
is there anything i need to do to get them to work now
i mean first of all use latest lovely not beta6 or beta5 and second of all use the format described on the lovely readme
idk if it ever changed but
is latest lovely not v0.6.0
the format seems to be the exact same also
try regex if normal patterns arent working
would also help to see the .toml file that isnt applying in question
version = "1.0.0"
dump_lua = true
priority = 0
# evaluate_poker_hand, this is a really awful way of doing this idc
[[patches]]
[patches.pattern]
target = "functions/misc_functions.lua"
pattern = 'function evaluate_poker_hand(hand)'
position = 'after'
payload = '''
local has_doctor_house = next(find_joker('Dr House'))
print(has_doctor_house and "true" or "false")
print("anything?")
'''
match_indent = true```
it still modifies the dumped file but this patch doesnt apply
iirc steamodded overrides that function now, so even if the patch hits, it won't do anything?
there's simply no reason to do any of that when you can just switch to using steamodded's poker hand api
But now collection look like this
why does lua use "nil" instead of "NULL" anyways
is there an actual reason or was it just to be different
How do I remove the category
makes sense
i assume it wouldnt be very easy but i wouldnt know exactly
i would guess that SMODS adds the category itself
can the poker hand api let you modifiy the conditions for vanilla hands
yes
ah my b. I just assumed it'd have the prefix, like the poker hands and stuff do
if you want a joker to display two messages, one after another, can you just put two messages = x in the same return?
finally want to get into modding balatro :) anyone have a starting guide or something? :0
https://github.com/Steamopollys/Steamodded/wiki heres a good starting point
however, the documentation is a little.. sparse
so the game files, this channel and other mods will be a big help 😭
👍 thanks so much
np
Anyone have a solve to this
I’m not 100% where this is populated, but try removing Polymino from SMODS.ConsumeableTypes
Can you elaborate on that
I believe ConsumableTypes are stored in SMODS.ConsumableTypes, so in theory doing something like SMODS.ConsumableTypes['Polymino'] = nil would remove it
quick question: is there something specific you need to do when you have 2 messages? i cannot get mine to work 😭
Do I add it anywhere in a Lua file?
wherever you put the other bit should work
Then it's not working
Does anyone know of the function used to make the player lose the run? Is it just lose_game() or something?
you can also look at the game's code, although ocasionally we have SMODS methods designed to replace the game's version of something
I'd argue otherwise. Lovely patches are generally more compatible with things, and they only really fail in cases like this where another mod completly replaces the function (which doesn't happen much). The same issue with something replacing your functon can happen with you hooking methods. I also find in general, people often mess up lua hooks and are more likely to not run the original code as often.
yeah i dont think that was a lovely fail that was an api changing making stuff i wrote before obsolete
which happens its alright
is there a way to force a modded object to show up with a different mod badge?
probably but I don't think theres a proper api for it
hack their computer and remove the object from their mod and then put it in yours
it's my mod
could you have the other mod register the object but only conditionally if the other mod is present
the other mod is also my mod
i just want it to visually look different
and they're actually the same mod
yeah i was going to do that
ideally it would be a lovely patch but i've forgotten the syntax for patching another mod
uhhh if you have beta7+ you should be able to target =[SMODS _ "utils.lua"] I belive
oh it might be =[SMODS _ "core/utils.lua"]
also as a note that there won't be a dump for that patch
btw @gaunt thistle are you aware of that
it fails to write due to invalid filename
show error
oh hmmm
I've had it fail before but it didn't panic for me
ERROR - [♥] Failed to write patched buffer to "C:\\users\\shorty\\AppData\\Roaming\\Balatro\\Mods\\lovely\\dump\\=[love \"wrap_Event. lua\"]": Os { code: 123, kind: InvalidFilename, message: "Invalid name." }
but no vrash
this is with dump_lua = false btw
does dump_lua do anything?
I mean it is patching at least
ooooh
it's because there is a slahs in the name
so the parent folder is invalid
ah
where my patch just the filename is invalud
I can make a fix, but your patch would only work on the next lovely version
no it needs to match the buffer name
it's kinda just screwed
the buffer name is arbitrary
so it can be whatver
well if it starts with =
the issue is if you start removing stuff then it can have conflicts
but idealy I think just removing invalid characters is fine
so =[SMODS _ "core/utils.lua"] becomes SMODS _ coreutils.lua or smth
I don't remebr the invalid characters off the top of my head
I don't know enough rust to properly handle this
could you do <mod folder>/whatever/it/is.lua?
so this would become Steamodded/core/utils.lua in the filesystem
well the issue is the name is arbitratry
I could make a buffer that has the name =hi mom
ah
I can do my best to fix it but it definitely needs an opinionated solution. I'm thinking that lovely won't attempt to patch targets that don't follow the =[PREFIX _ "file/path.lua"]
If it follows that schema then I can parse it super easily.
so im starting to mod and im using this as a guide and im confused on what i put in for main_file in the json. is that even required
I think it should still patch them but I think it would be fine if it didn't dump them. Maybe we could specify an override to the dump patch to allow dumping of incompaible formats. Also the _ can be any stirng (SMODS uses it for the mod id (_ is for internal stuff) and lovely uses it for the module name). Also you should support loves format that has a prefix but no middle bit, just the path name
also is there documentation of every function for a joker. i have some ideas but idk how id excute them
you can extact the games code using 7 zip and look in card.lua
oh i didnt know that
they aren't created in the same way as modded jokers but there behaviours should still work
does it have to be 7zip or can i use win rar and uh what do i extract
You can use win rar, just extract the balatro.exe
oh i see ty
calculate = function(self, card, context)
if context.repetition and context.cardarea == G.play and not context.repetition_only then
local suits = {
['Hearts'] = 0,
['Diamonds'] = 0,
['Spades'] = 0,
['Clubs'] = 0
}
for i = 1, #context.scoring_hand do
if context.scoring_hand[i].ability.name ~= 'Wild Card' then
if context.scoring_hand[i]:is_suit('Hearts', true) and suits["Hearts"] == 0 then suits["Hearts"] = suits["Hearts"] + 1
elseif context.scoring_hand[i]:is_suit('Diamonds', true) and suits["Diamonds"] == 0 then suits["Diamonds"] = suits["Diamonds"] + 1
elseif context.scoring_hand[i]:is_suit('Spades', true) and suits["Spades"] == 0 then suits["Spades"] = suits["Spades"] + 1
elseif context.scoring_hand[i]:is_suit('Clubs', true) and suits["Clubs"] == 0 then suits["Clubs"] = suits["Clubs"] + 1 end
end
end
for i = 1, #context.scoring_hand do
if context.scoring_hand[i].ability.name == 'Wild Card' then
if context.scoring_hand[i]:is_suit('Hearts') and suits["Hearts"] == 0 then suits["Hearts"] = suits["Hearts"] + 1
elseif context.scoring_hand[i]:is_suit('Diamonds') and suits["Diamonds"] == 0 then suits["Diamonds"] = suits["Diamonds"] + 1
elseif context.scoring_hand[i]:is_suit('Spades') and suits["Spades"] == 0 then suits["Spades"] = suits["Spades"] + 1
elseif context.scoring_hand[i]:is_suit('Clubs') and suits["Clubs"] == 0 then suits["Clubs"] = suits["Clubs"] + 1 end
end
end
if
suits["Hearts"] > 0 and
suits["Diamonds"] > 0 and
suits["Spades"] > 0 and
suits["Clubs"] > 0 then
card.ability.extra.repetitions = math.min(card.ability.extra.repetitions + card.ability.extra.repetitions_gain, 10)
return {
message = "Again!",
repetitions = card.ability.extra.repetitions,
card = card,
}
end
end
end
sorry for the super long message, but im having some trouble making card.ability.extra.reptitions only equal 1 after a hand with all 4 suits is played - with this code it immediantly jumps to 4
and if i put, for example, card.ability.extra.repititions - 3, 10), it makes it equal -4?
you made it double itself
wait no
what is extra repetitions set to
¯_(ツ)_/¯
fair enough 😭
my best guess is that it's counting them more than once somehow
probably triggering for multiple contexts
(here is the rest of the code, if you are interested)
...thats a thing? 
oh your if statement does have pretty specific requirements
try printing anyway to check I guess
i mean, the contexts there are also what is used in the example jokers, so idk - but printing? 
should i put a print in the context if statement or?
you check the entire hand on every card
yes, so that the joker knows if all 4 suits have been played
yeah but if you do that on every card, you do it 4 times
no, I mean you run this block of code on every card, and each time you check all the cards
OH
my bad 😭
so what should i do instead, because this is the only way i know of checking for multiple suits (iterating over every card 😭 )
you need to change your context
shouldn't this trigger when the joker is scoring? instead of when the cards are?
no idea, all the other jokers i've made with this same "setup" (play X thing, gain +Y of Z) have been using context.individual and context.cardarea == G.play - since this is a repititon joker though
it uses context.repititon and not context.repition_only (everything else is just me guessing 😭 )
you arent making those spelling errors in your code right
no, i just type too fast for my hands and fuck up often
in code i usually use the prompts given by VSC anyway, so 
what does the joker do?
when a hand contaning all 4 suits is played, it gains 1 retrigger, which maxes at 10
the joker gains the retrigger, like how runner gains chips
I'd evaluate your retrigger gains in this context
Maybe try using context.after as well in your if statement, no? That way it'll only do the thing once during the after context (after scoring)
i was eyeing that one up specifically, currently trying it out
i've been using context.joker_main so far for my other jokers so that their gained bonuses are played in the next hand (because context.after didnt work for them) - i can try it again with this one though? it might work
then I don't remember how retrigger api works properly
Remeber, you can have multiple if staments in yoru calculate. As such you can have a different context for increasing your value, and retriggering cards
oh i know, i abused the fuck out of that for my last joker with the same core concept - i just didnt know how to make it check for all 4 suits, and so was told to yoink flowerpot
and thats essenitally all this one is 😭 flowerpot checking with its return changed for repetitions, and the math.min wedged in
yeah you should just be able to move that to a different check
not srue wheich one
do you mean like, a different type of iteration over the played cards?
no just don't run it in the repitition context
(instead of using flower pots way of doing it)
OH
correct me if im wrong, but doesnt repetitions need that context to function?
well you don't do your incrementing in that context
just giving the repition
you also arent retriggering the cards
oh, wait
i think i get what you mean now
i mean it was, but for some reason it was incrementally increasing the amount of retriggers each card got, so the leftmost got 1, next got 2, etc
(which honestly, is a joker idea in itself)
didnt you say you want the joker to retrigger though?
i realised how that sounded now - the joker gains a retrigger (like runner gains chips), but the cards are retriggered
oh right
this is what it currently does, it just gains the amount of retriggers equal to the amount of cards played
so yeah, do your iteration in before, then return it in the context you have here
at the moment, you check the first card, see you have met the condition, increase retriggers to 1, send 1 as repetitions, move to 2nd card, see you have met the condition, increase retriggers to 2, send 2 as repetitions, etc...
😭 amazing
okay, so, wanna be sure - the checking is outside of the context.repetition.. if statement, but the return{ is inside that context statement?
you want to make 2 if statments
You probably want to use this context (#1247703015222149120 message #3) for the check to increment the repititions
and then the context you currently have to add repitions to cards
ah, thank you
(that is what the error was calling for)
okay, so, wanna be absolutely sure - is this essenitally what i need?:
if context.scoring_hand then
-- checking stuff
end
if context.repetition and ..
-- math
return{
--repetition stuff
}
im sorry this is a me thing, but do you mean just if context.before then, if context.before and context.scoring_hand then, or 
first one
ty
i remeber you were able to view souce code for balatro, where was that?
view it, as in not on your own .exe file?
as in you could view like UI.lua and game.lua or something, and it would show it
yeah you can unzip the exe with apps like 7zip
yeah you do
well regardless of what you remember unzipping it is probably the easiest and most up-to-date way to view it
you can view the lovely dump but that doesn't have all the files and also has patches from mods applied
mods/lovely/dump
how do i see what cards are in your hand?
as in what variable is it?
yea
G.hand.cards
also, is there any function that gets ran everytime the held cards change? (adding/removing cards, discarding, playing, changing cards)
most that stuff is handled by the global draw_card function, which is used to move cards between different areas of the screen
it contains parameters for where cards are coming from and going to
among other things
What are you trying to do?
show if you have a straight or other hand, sometimes i miss it because im going for a flush
it's ok tbh, i have a joker in my mod which was already implemented in another one
sloghtly different xmult values tho so ha
i remember seeing a joker somewhere that made it so discards roll over to the next blind does anyone know what mod its from
that's just the old version of Merry Andy
merry andy is a goat with yorick and mail-in
not anymore
that was its old effect
now it gives you +3 discards in exchange for -1 hand size
oh right
which is a pretty good deal i think so
yeah
im just looking for a joker that gives temporary discards that carry over so i can reference it for my code
unfortunately i am not a guy who knows enough about modding to help you with this
if anyone knows tell me in #1298849744864677948 so i see it please
Does anyone know how to check what seal is on a card? This is what i have rn
context.other_card.seal.name == 'Blue'
would that be subject to localization
Working on picking up modding, running into an odd issue.
When trying to load a joker.lua (Learning from other mods) It throws an error stating it is trying to call a nil value.
The loading code:
line 36: SMODS.load_file('data/jokers/testJoke.lua')()
The error:
I'm not sure what I'm doing wrong here
try changing it to assert(SMODS.load_file('data/jokers/testJoke.lua'))()
but my guess is minor spelling mistake
testJoke.lua > testJoker.lua
No, the lua file is testJoke.lua
Well, this fixed the loading issue. Thank you.
that shouldn't have fixed the issue but glad it did
Is there a way to add a joker to the next shop? So far I got
if context.selling_self then
G.E_MANAGER:add_event(Event({trigger = 'before', delay = 0.0, func = function()
local ccard = copy_card(card, nil, nil, nil, nil)
ccard:start_materialize()
ccard:add_to_deck()
G.shop_jokers:emplace(ccard)
return true end }))
But G.shop_jokers does not exist.
It's supposed to add a copy of itself to the next shop when sold.
.
i've tested and it seems that SMODS.Stickers has a size of 0
you'll probably want to store something in the game object soemwhere and then modify the function for spawning jokers
take a look at how the rare joke r tag works
does SMODS.Stickers have integer keys?
iirc no, the only place stickers are stored is there.
Forgot to add one

its keys are the internal names of the stickers
just switched ipairs to pairs and now it works perfectly
Does anybody know where midas mask effects are in the code?
Im trying to base a similar effect on it (polychrome instead of gold)
card.lua line 3444
if self.ability.name == 'Midas Mask' and not context.blueprint then
local faces = {}
for k, v in ipairs(context.scoring_hand) do
if v:is_face() then
faces[#faces+1] = v
v:set_ability(G.P_CENTERS.m_gold, nil, true)
G.E_MANAGER:add_event(Event({
func = function()
v:juice_up()
return true
end
}))
end
end
if #faces > 0 then
return {
message = localize('k_gold'),
colour = G.C.MONEY,
card = self
}
end
end
Ah juice_up, good old well named functions
getting this error when trying to view a blind i've created in the collection
so apparently blind sprites MUST have their atlas type set to animated
is it possible to check if the blind you enter is a boss blind?
did you register your atlas?
lets see the part of your code where you declare your atlases
oh, i can use if G.GAME.blind:get_type() == 'Boss' then
how would i make my own mod?
best place to start is coming up with ideas for things you'd implement
ok
or a general idea for the theme of the mod
i had an idea for like eets jokers
for example theres a pokemon mod and stuff
is it possible to re-enable boss blinds after they have been disabled by a joker?
Chicot will murk you
nuh uh
im just trying to make a card that disables the boss for a couple hands then it reenables
but idk if its possible
I like that idea tbh
It ought to be possible
idk if your idea is possible but I like it
Saying it can be disabled while active
it'd be possible i should imagine but theres no function for enabling blinds
The opposite should be true
Might be a lot of work then yeah
we have G.GAME.blind:disable() but theres no alternative for enabling
i might just have to change my idea then );
Can't it just reroll the blind to be the same one and not disable it?
Might be feasible
if you need to, maybe make it where it disables the boss blind after two or three hands instead?
it just doesnt work on the needle though
The 'first hand' will be the first what is enabled for
And that's when it'll set it to 1
Pretty sure
yeah looks like coonies idea of just setting it to the same blind you're playing on
yea u get 1 disabled hand
then boss activates
similar to my idea xdd mine was its disabled for 2 hands
Yeah it seems to work too
Np :3
whats the function for it is it G.GAME.set_blind or is it like G.GAME.blind:set_blind()


