#💻・modding-dev
1 messages · Page 223 of 1
info_queue[#info_queue+1] = G.P_CENTERS.c_hanged_man in loc_vars
Aure'll know 😋
At work, we do 👑 emojis when someone helps a lot
yeah but it's going through malverk APIs, which I don't know the internals of
right, thanks again though
I'd check all the file names and confirm with malverk docs to start
okay, ill look through it
It's my first time making an edition, which context window woudl you recommend I use for scoring and applying xMult? I was going to try context.individual and context.cardarea == G.play
what file would the sets be in?
if context.post_joker or (context.main_scoring and context.cardarea == G.play) then
because if i remember correctly, theres a file that has them listed
the sets are correct
oh
Man DebugPlus is AMAZING. I was able to tweak my shaders so much today using the shader watch command.
how do i make mods for balatro with this https://github.com/art-muncher/Example-Mod
have a look at steamodded docs and example mods, these have more in-depth explanations on things
other than that, it depends on what you level of knowledge in lua and/or coding in general is
do you have any programming experience at all?
so like 6months
Hey John that was totally the right window, thank you!
Do you see some other error? It isn't apply the xMult
you haven't answered my question
I'd say lua is a fairly easy first language to pick up, but I do recommend taking at least some time to learn the basics and concepts before jumping into mods. there's a lot to learn from the code of other mods too, but it's important that you learn to understand that code and don't just end up copying it mindlessly
do you havee some suggestions
you can do something like this to learn those basics: https://www.codecademy.com/learn/learn-lua
-# note: I haven't used this and can't say anything about the quality of this particular course, but I've used the platform before
oh thank you
this can also be useful alongside testing things as you write code: https://www.lua.org/pil/contents.html
it's more in-depth and you don't need to understand it all
if you need help at any point or need someone to explain something to you, please feel free to ask
how did the make it go backwards?
i don't see anything backwards, it's just right-aligned
it was a bunch of spaces
Hi guys, running into an issue getting my custom editions to apply mult or chips.
Here's an example of what I am doing. We do hit the log message, but the edition's special perk does not apply.
that's not how you reference edition config values
it'd be like card.edition.extra
because of course editions are extra and need to do things differently 
i honestly have no idea whats causing the crash, ive replaced all the broken code with another and it still works, im gonna scream
wait
So I bet that if I want to increment a value, I would not do it like this
What does your crash say?
holy shit
i found it
in all the code it calls for 'Planet' and for some reason, i need to call for 'planet'
now its the keys that are crashing
fuck it, we arent doing planets
I know it doesn't fit at all but I love this lol
How do you replace the textures for the default 8bitdeck?
ideally you don't do that and use a DeckSkin instead
dam
change T:t_hanged_man to T:c_hanged_man
that gives you the tooltip when you hover over "Hanged Man" (no galdur) or next to the deck description (with galdur)
yay
should also colour code it ngl
oh yea
How do you make a balatro mod?
long
thx!
this good?
OH! it uses lua?
yes
I'd {C:tarot} the hanged man
Man, i only know python. Guess I'm using lua now
its not too different
theyre like second cousins
cool mod idea btw
Does anyone know what to do about this?
download loader api version 1.0 or higher
how to add another context
as in create one?
replace it with a ,?
Where do I find that? I just searched it up on Google and it comes up with Steamodded
Okay using the DeckSkinTemplate how do I have it show regular/number cards that comes with it? Currently its just on the default
add
chips = 0,
mult = 0,
``` to the return, i find that sometimes it doesnt listen to chips/mult = otherwise
no just remove it
you dont need anything there
no, its a function it doesnt need anything after lines
k
change the display_ranks
idk
show code
if context.discard and
not context.other_card.debuff
then
card.ability.extra.chips = card.ability.extra.chips + card.ability.extra.chips_mod
card.ability.extra.mult = card.ability.extra.mult + card.ability.extra.mult_mod
return {
message = "Guts Harvested",
colour = G.C.CHIPS,
card = card
}
end
if context.joker_main and card.ability.extra.chips > 0 and card.ability.extra.mult > 0 then
return {
message = localize { type = 'variable', key = 'a_chips', vars = { card.ability.extra.chips } },
chip_mod = card.ability.extra.chips,
message = localize { type = 'variable', key = 'a_mult', vars = { card.ability.extra.mult } },
mult_mod = card.ability.extra.mult,
colour = G.C.CHIPS}
end
end```
my terrible
Ah I see thx for the help 👍
indentation
that seems a lil over powered
yea but x2 per card??
2x mult is still a ton
$2 per destroyed card is already almost as much as trading card gives too
yeah, ok needs workshoping
okay something weird is going on with my joker
why is the chips value false in the game??
do you have your chips variable set to a non-integer value?
if it's anything other than a number I think it defaults to false
could be misremembering tho
i got chips_mod=3
my joker is kinda like the castle
except with +mult too
might get rid of the mult part and only make it chips + money
to make it balanced
hiya!
m
so i can't check how an SMODS Gros Michel would work, since SMODS removed its examples
Hello good people! I have come here to ask where does the info_queue of any given card get stored.
so, how do i remove a card from the pool when sold, and add a different one to the pool?
?
o7 thanks :D
help maybe?
no
hi squid
hi
how is your balatro modding experience going?
^
holy fuck
3 fucking hours.
can anybody help me with this?
dang
Hey that page looks pretty good
yea
Can we take a look at the code?
ty
Include warcrimes
holy moly
why is there chip_/mult_mod and message
wait
Can you send over the whole joker?
oh sure
ty
for some reason text components hate to stack vertically so uh...
key = 'TheRats',
loc_txt = {
name = 'The Rats',
text = {
"This joker gains {C:chips}+#1#{} Chips",
"and {C:mult}+#1#{} Mult",
"per discared card",
"{C:inactive}(Currently {C:chips}+#3#{C:inactive} Chips)",
"{C:inactive}(Currently {C:mult}+#4#{C:inactive} Mult)",
"Gut Harvesting go BRRR"
}
},
atlas = 'TheRats.png',
pos = { x = 0, y = 0},
config = {extra =
{ chips = 0,
mult = 0,
chips_mod = 3,
mult_mod = 4}
},
loc_vars = function(self, info_que,card)
return {
vars = {
card.ability.extra.chips_mod,
card.ability.extra.mult_mod,
card.ability.extra.chips,
card.ability.extra.mult
}
}
end,
calculate = function(self, card, context)
if context.discard and
not context.other_card.debuff
then
card.ability.extra.chips = card.ability.extra.chips + card.ability.extra.chips_mod
card.ability.extra.mult = card.ability.extra.mult + card.ability.extra.mult_mod
return {
message = "Guts Harvested",
colour = G.C.CHIPS,
card = card
}
end
if context.joker_main and card.ability.extra.chips > 0 and card.ability.extra.mult > 0 then
return {
message = { type = 'variable', key = 'a_chips', vars = { card.ability.extra.chips } },
chip_mod = card.ability.extra.chips,
message = { type = 'variable', key = 'a_mult', vars = { card.ability.extra.mult } },
mult_mod = card.ability.extra.mult,
colour = G.C.CHIPS}
end
end
```
alr
I wrap 'em in another UI component thing.
SMODS.Joker {
key = 'TheRats',
loc_txt = {
name = 'The Rats',
text = {
"This joker gains {C:chips}+#1#{} Chips",
"and {C:mult}+#1#{} Mult",
"per discared card",
"{C:inactive}(Currently {C:chips}+#3#{C:inactive} Chips)",
"{C:inactive}(Currently {C:mult}+#4#{C:inactive} Mult)",
"Gut Harvesting go BRRR"
}
},
atlas = 'TheRats.png',
pos = { x = 0, y = 0},
config = {extra =
{ chips = 0,
mult = 0,
chips_mod = 3,
mult_mod = 4}
},
loc_vars = function(self, info_que,card)
return {
vars = {
card.ability.extra.chips_mod,
card.ability.extra.mult_mod,
card.ability.extra.chips,
card.ability.extra.mult
}
}
end,
calculate = function(self, card, context)
if context.discard and
not context.other_card.debuff
then
card.ability.extra.chips = card.ability.extra.chips + card.ability.extra.chips_mod
card.ability.extra.mult = card.ability.extra.mult + card.ability.extra.mult_mod
return {
message = "Guts Harvested",
colour = G.C.CHIPS,
card = card
}
end
if context.joker_main and card.ability.extra.chips > 0 and card.ability.extra.mult > 0 then
return {
message = { type = 'variable', key = 'a_chips', vars = { card.ability.extra.chips } },
chip_mod = card.ability.extra.chips,
message = { type = 'variable', key = 'a_mult', vars = { card.ability.extra.mult } },
mult_mod = card.ability.extra.mult,
colour = G.C.CHIPS}
end
end
To better format it with colour for me to better see stuff.
this is wrong on so many levels
return {
message = { type = 'variable', key = 'a_chips', vars = { card.ability.extra.chips } },
chip_mod = card.ability.extra.chips,
message = { type = 'variable', key = 'a_mult', vars = { card.ability.extra.mult } },
mult_mod = card.ability.extra.mult,
colour = G.C.CHIPS
}
color = true
-- This stuff has color now!
now i know it seems bad
in this house we just
return {
chips = card.ability.extra.chips,
mult = card.ability.extra.mult,
}
yeah
Okay I tried making another deck skin but it is showing up as blank?
Not sure what exactly I messed up
local atlas_b = SMODS.Atlas {
key = "skin_b",
path = "skin_b.png",
px = 71,
py = 95,
}
local atlas_a = SMODS.Atlas {
key = "skin_a",
path = "skin_a.png",
px = 71,
py = 95,
}
local icon_a = SMODS.Atlas {
key = "icon_a",
path = "icon_a.png",
px = 18,
py = 18,
}
local icon_b = SMODS.Atlas {
key = "icon_b",
path = "icon_b.png",
px = 18,
py = 18,
}
SMODS.DeckSkin {
key = "a",
suit = "Diamonds",
loc_txt = "a",
palettes = {
{
key = 'lc',
ranks = {'2', '3', '4', '5', '6', '7', '8', '9', '10', 'Jack', 'Queen', "King", "Ace",},
display_ranks = {'2', '3', '4', '5', '6', '7', '8', '9', '10', 'Jack', 'Queen', "King", "Ace",},
atlas = atlas_a.key,
pos_style = 'deck',
suit_icon = {
atlas = icon_a.key,
},
},
{
key = 'hc',
ranks = {'2', '3', '4', '5', '6', '7', '8', '9', '10', 'Jack', 'Queen', "King", "Ace",},
display_ranks = {"King", "Queen", "Jack"},
atlas = atlas_b.key,
pos_style = 'deck',
colour = HEX("9734f0"),
suit_icon = {
atlas = icon_b.key,
},
},
},
}
bruh
But you don't have to worry about it too much for now.
i was following the castle example
that's for the joker_main block
yes thats how return{chip/mult} works
it does not include the upgrading
oh
but the upgrading part looks fine to me in your code
-# also no idea. I haven't dealt with deck skins like, ever
just the joker_main is off
-# just so you know you aren't being ignored
so i replace everything in the joker_main
Yeah you don’t need the greater than 0 checks either
oh
Better calc is indeed magic
what was the difference between old_calc and better_calc?
Are you using a fresh copy of the joker?
bump idk
idk what you mean by that
if you mean how to add any given card to info queue, that works like info_queue[#info_queue+1] = G.P_CENTERS.j_bla_blablabla
But where the fuck does that get stored in the card?
where does what get stored
Yes.
I need to access that specific thing.
...and figure out a way to not make it recursive.
where does what get stored?
the info_queue is a local variable in generate_card_ui
info_queue {
"something",
"something else",
"you get the idea",
"(...)"
}
it is used only to make recursive calls back into generate_card_ui
idk
and hence it does not exist outside of it
well sh*t
maybe this would be more productive if you said what you actually want to do and not some vague description of what you think you need to get there
I need to like, make so a card contains the information of another card and the other card contain the information of the first card.
Problem is:
A: I want to automate this process via a function
B: It is recursive so the game freezes.
check for not card.fake_card i think
well you have access to info_queue when you're adding the tooltip
either you can display it only on main descriptions and do what N' said
or you can check if it's already in info_queue and only add it if it isn't
Probably do the second one.
errr...
-# oh god it is almost 2 am already. Probably it is not a good idea to try to learn this stuff this late, oh well here we go
local is_in_q
for _,v in ipairs(info_queue) do
if v == G.P_CENTERS.j_bla_theothercard then is_in_q = true; break end
end
if not is_in_q then info_queue[#info_queue+1] = G.P_CENTERS.j_bla_theothercard end
you really should go to sleep, its unhealthy to stay up that late
-# totally not me last night
I need to somehow overwrite or well, extend the loc_vars function to account for automatically adding the info queue thing to every playing card.
hi bepis
hi peak
The key for the other card I can do that with other stuff I have ready.
You don't know how stuff goes in spain.
is there a way to check if a probability triggers?
If it's not 8 am, you are not that late.
hey so ive been trying to hand over my mod to my lady so she can help test it out, ive installed lovely and smods correctly, and they work until i add my mod
once i add my mod it does not desire to find things properly, with console outputting this
INFO - [G] file not found: main.lua: No such file or directory
INFO - [G] file not found: main.lua: No such file or directory
INFO - [G] line not found
INFO - [G] file not found: main.lua: No such file or directory
INFO - [G] file not found: main.lua: No such file or directory
INFO - [G] 2025-03-08 19:41:32 :: ERROR :: StackTrace :: Oops! The game crashed
[SMODS DMODS "Dilatro.lua"]:4285: attempt to index field 'jokers' (a nil value)
but its the exact same as the build that is working on my system
did you make a main.lua file??
Put that thing an assert(t) thing, first.
Second, can we see the code?
any difference in setup, like smods version, game version, etc?
how do i check if the blind defeated is a boss blind or not
also a real crash log would be great
one second ill provide the crash file
wait
cooking
nvm
never enter the kitchen again
hahahaha\
infact never touch food again
is that your self insert legendary joker.
yes they fucking did the what the hell
engine/text.lua:188: attempt to index a nil value
You can put a not before G.GAME.blind.boss if you want.
replace this with context.main_eval
why in the heck am i getting this
you messed up somewhere
-# uh... niof
i tried with both latest smods, and the smods version i have
i eblieve everything else is the same as my sys
what code is there around the line where it errors?
what all card areas are there
its justa joker i haveto increase the debt limit the player has, this line specifically is this
in_pool = function(self)
local has_credit_card, has_gold_card, has_platinum_card = false, false, false
for _, card in ipairs(G.jokers.cards) do
if card.ability then
if card.ability.name == "Credit Card" then
has_credit_card = true
elseif card.ability.name == "j_dilatro_gold_card" then
has_gold_card = true
elseif card.ability.name == "j_dilatro_platinum_card" then
has_platinum_card = true
end
end
end
with the line specifically being
for _, card in ipairs(G.jokers.cards) do
looks like that's getting called at the start of a run before the jokers area even exists
iuts strange that i wouldnt have experienced this crash myself though no?
cause it does not occur on my system at all
you should change G.jokers.cards to G.jokers and G.jokers.cards or {}
this is my first time doing suit specific stuff, I'm trying to do something similar to what castle does, but it adds chips when a heart is scored, instead of when a randomly selected suit is discarded, I think I'm missing something with the ```lua
context.other_card:is_suit
```lua
if context.individual and context.cardarea == G.play then
if context.other_card:is_suit('Hearts') then
return {
card.ability.extra.chips == card.ability.extra.chips + card.ability.extra.chip_mod
}
end
end
the cap of the pepper bottle was loose.
does anyone know what I should be doing different?
and i didn't notice.
uh oh
welp, im not wasting any food though
...that's the context for when a card is played
its doing exactly what its supposed to do 😭
it don't be doing anything when a heart is scored tho
yeah, i can see why
you are returning wrong
return{
chips = (how many chips you want it to give),
}
nice :D
imagine needing to atlas joker sprites manually
so just cutting out the first part like this?
return {
card.ability.extra.chips + card.ability.extra.chip_mod
}
you forgot the "chips ="
I've got another part for actual scoring
chips = card.ability.extra.(something) should work
this is just for increasing the chips variable using the chip_mod
you don't?
yeah, you only really use return when telling the joker to give mult, chips, and some other niche use cases
you should handle that outside of the return{} instead
fuck
DUDE THIS IS ME YESTERDAY
Still been trying to figure what I messed up in the code for the 2nd deck to cause it to become blank
Here's the full code it incase the initial snippet of the code I sent didn't include the issue causing it
😭
noted, I'm gonna test it rq
yk the braincell thing might be true
automatically shows every stat debuffs attached to a card changes
- it evenly distributes the whole string to 2 different lines
it works! tyyy
minmoo be chippin
oh, thats cute
it's probably the pos_style
you should probably use 'suit' in place of 'deck'
eat the axlotol
nah

i jst gotta finish this up
EAT IT
we do not eat the minmoo, we respect the minmoo
EATETH IT

IT IS VERY CHEWYYY
Oh yup that fixed it thx 👍
Btw how do you set up the code to have a deck which covers all the suits?
due to how the menu is laid out, you need to create a skin for each suit
Ah thought so thank you again for the help though
is there a way to check if a probability fails?
check if it succeededs, then just invert that
not like a joker's own probability, like any probability
ah
Need some help with UI code for anyone more familiar with it. I'm making a joker that predicts what's in an upcoming booster pack, and I want the display to just kind of be somewhere around the joker, but I'm not 100% certain what happens with the generate_UI function when you add nodes to it
-- boilerplate code to wrap loc_vars
if card.config.center.discovered then
-- If statement makes it so that this function doesnt activate in the "Joker Unlocked" UI and cause 'Not Discovered' to be stuck in the corner
full_UI_table.name = localize{type = 'name', key = self.key, set = self.set, name_nodes = {}, vars = specific_vars or {}}
end
localize{type = 'descriptions', key = self.key, set = self.set, nodes = desc_nodes, vars = self.loc_vars(self, info_queue, card)}
-- my actual code to try to attach the cardarea with the desc_nodes
if not card.config.center.discovered or card.area.config.collection then
return
end
if card.ability.predict_cards then
desc_nodes[#desc_nodes+1] = {create_UIBox_generic_options({
minw = nil,
padding = nil,
infotip = nil,
no_back = true,
contents = card.ability.predict_cards
})}
end
end```
It ends up putting them in the top left corner and I was under the impression it would just kind of append them below/above the description?
not really then
context.end_of_round
value = 0
thanks
I suppose it'd also make more sense to just put them above the packs it's inspecting too
uh I think I'd approach this slightly differently
prob card.ability.extra.value = 0 then
okay
adding an object node with a card or CardArea inside the description box seems reasonable
card.ability.predict_cards is a CardArea, if it helps
It just creates, populates, and holds it as long as it's hovering over the pack
you don't even need generate_ui for that, you can just return a ui element as main_end in loc_vars
Oh, interesting!
Hey friends, where can I find the logic for leveling up a poker hand? I took a look at burnt joker as reference but didn't take away much from it. Was hoping I could find a planet card in card.lua but didn't go so well either.
that element need not be some UIBox, it can just be a simple container that holds the object node
e.x. ```lua
{n=G.UIT.R, config = {align = "cm", colour = G.C.CLEAR, r = 0.0}, nodes={
{n=G.UIT.C, config = {align = "cm"}, nodes={
{n=G.UIT.O, config = {object = cardarea}}
}}
}}
And then just return that whole UI element?
return { vars = {...}, main_end = {<the UI element>} } in loc_vars
think it needs an extra set of {}, oops
Gimme a sec to try this
i should note that if you do ever need a custom generate_ui, you should probably base it off the base implementation steamodded provides, or call back into it if you're just extending it
because this would be highly inconsistent with the specification of loc_vars
Assuming it updated correctly (I just closed and reopened the game with the changes), it works basically identically. But thanks!!
Does the transform position of the object itself matter in the context of the UI box? Or would it take them as relative coordinates?
Because I am creating this at 0, 0, but I was under the assumption that it would be relative
uh huh
can i see that code again
are you creating the cardarea in a wider scope than the description? you should probably be recreating it on each loc_vars call
Yes, I would usually just create it once if possible
this is creating the card area, so the actual transform coordinates are the origin (this is called from the calculate function)
0,
0,
(pack.ability.extra * G.CARD_W) * 0.75, (G.CARD_H * 1.5) * 0.5,
{
card_limit = pack.ability.extra,
type = 'title',
highlight_limit = 0,
card_w = G.CARD_W * 0.7
}
)```
And this is loc_vars, currently
```function jokerInfo.loc_vars(self, info_queue, card)
if card.ability.predict_cards then
local ui_box = {
n = G.UIT.R,
config = {align = "cm", colour = G.C.CLEAR, r = 0.0},
nodes = {{
n = G.UIT.C,
config = {align = "cm"},
nodes = {{
n = G.UIT.O,
config = {object = card.ability.predict_cards}
}}
}}
}
return { vars = {}, main_end = {ui_box}}
else
info_queue[#info_queue+1] = {key = "artist_coop", set = "Other"}
end
end```
I can definitely recreate it each time in loc_vars if needed, but I'm not 100% certain that's the issue since it'd still be being given the same values?
if the area just continues to exist, it will be rendered in its real position without any influence from loc_vars
loc_vars is doing nothing related to that card area being rendered in fact, so long as it's not being called. Try and see what happens when you show the description of the joker?
Just shows the regular description
a working example of card areas inside descriptions are polyminos in Bunco, and they most definitely work by creating a new card area whenever loc_vars is prompted
figured as much, the area is already being rendered elsewhere
either way I think it's preferable to store the raw information instead of the card area because objects in ability tables tend not to play nice with saving
center keys would be the rawest information I can think of
if you track other information like editions, throw that in
anything that lets you construct the card you want to display
I mostly went with cards because the SMODS changes in Pack:open expect still being able to return a card outright from whatever booster's create_card function (including a comment lamenting that fact), so I guess I can just destroy it if need be
-- due to SMODS, I have to support creating an actual card here. hopefully pack creators
-- don't have it materialize before it leaves the pack
card = _card_to_spawn
else
card = SMODS.create_card(_card_to_spawn)
end
pack_cards[i] = card```
Then I guess i'll just grab the center, destroy the card, and waggle my finger at whoever gives me a card from the function
how are you not advancing the pools?
I just thought about that
display_size
how do I check if a hand is the final hand played in a round? the method I have been using is no longer working suddenly
Very hacky change to the pseudoseed function to store advancing seed values as long as a "mode" is set to only return predicted values rather than actually set the main G.GAME.pseudorandom table
local _pseed = 0
if not G.GAME.pseudorandom.predict_mode or not G.GAME.pseudorandom.predicts[key] then
_pseed = pseudohash(key..(predict_seed or G.GAME.pseudorandom.seed or ''))
G.GAME.pseudorandom.predicts[key] = {
value = _pseed,
pos = 0
}
end
if G.GAME.pseudorandom.predict_mode then
_pseed = math.abs(tonumber(string.format("%.13f", (2.134453429141+G.GAME.pseudorandom.predicts[key].value*1.72431234)%1)))
G.GAME.pseudorandom.predicts[key].value = _pseed
G.GAME.pseudorandom.predicts[key].pos = G.GAME.pseudorandom.predicts[key].pos + 1
return (_pseed + (G.GAME.pseudorandom.hashed_seed or 0))/2
else
_pseed = math.abs(tonumber(string.format("%.13f", (2.134453429141+_pseed*1.72431234)%1)))
return (_pseed + (pseudohash(predict_seed) or 0))/2
end
end```
Hacky because it's all built around maintaining the one (1) time vanilla uses the predict_seed parameter to find the first legendary spawn in the run, and the code is only build to predict the first value of any given seed by default since the vanilla code sets it to the starting value every time if you pass it in
Which is why it only ever uses it right after creating the seed the first time
it's in the docs
default is { w = 71, h = 95 }
it goes on the center and you can change these values to scale the display size
e.g. display_size = { w = 71*0.7, h = 95*0.7 } for something wee-sized
Hey y'all, where is the code for the effects of challenges? (eg. X-ray Vision making 1 in 4 playing cards face down)
bump
G.GAME.current_round.hands_left == 0?
ooh
aka the hand you beat the blind with
that would require the game to know that hand would win
so uh
youd have to make that yourself
clash royale grrr sfx
if it's a joker:
Is there a reset_game_globals but after each hand? or do I need to start patching and/or hooking
at any point in the calculate function, you can use hand_chips * mult to get the current value of chips and mult during the full effect triggers, because AFAIK they're globals in the actual vanilla/smods functions
So at the point the joker triggers, you should just be able to compare G.GAME.chips + (hand_chips * mult) >= G.GAME.blind.chips to know if the current hand will win the blind. Position depend of course, if you have any other jokers in the context that check for it
this calls a global “joker” and crashes
did i mess something up?
the problem seems to be that joker is a global for some reason
and not the variable referencing the joker you're changing
would the variable in question just be the id of the first joker?
like a j_prefix_joker thing
this is already the method i was using
and it's not working
if context.after and (G.GAME.chips + hand_chips * mult) > G.GAME.blind.chips then
does not pass
no, it's the joker card
I have a similar context and I'm like 95% sure this isn't bugged
card.ability.extra.chips = card.ability.extra.chips + card.ability.extra.chips_mod
return {
message = localize{type='variable',key='a_chips',vars={card.ability.extra.chips}},
chip_mod = card.ability.extra.chips,
colour = G.C.CHIPS
}
end```
omg the og
so what do i put there?
Instead here I'm just checking if the score catches fire rather than beating the blind with cumulative chips
yeah idk what to say it's just not passing
joker is the card you're changing
the key in P_CENTERS is the key of the joker you want to change into
wwwait
like the same way i formatted the CENTERS?
are you doing this inside calculate?
should i not be
no, that's fine
inside calculate use card instead of joker
ohhhhhhh
ok i’ll try
OH
UM
does it just change or is there a way to like make it
flip?
yk what i mean?
you need to do the animation yourself
Flipping is a very easy event
oh ok
i fixed it
just tested it, but it changes too early? how do i order it so it does the first joker’s effect THEN transform (currently it does the opposite)
how would it work? never done it before
hell I guess I just hook play_cards_from_highlighted but i don't know how right that is
Oh right I'm probably going to have to call loc_vars manually, huh
Look at how the enhancing tarots do it
you probably need to put the code in a return func
the same return with the triggered effect? or a separate return
same return
yeah
#1346716313934102598 <- Please give me ideas here
should be
func = function() card:set_ability(G.P_CENTERS["j_hpfx_ijiraq"]) end
ohhhhh
yeah?
missing an end
i think it's correct but I've used func like once
Please give me ideas for my mod I only have 1 more day to develop it and I also have to complete it 🙏
that sounds awful
When using add_joker, how do you give it enhancements, seals or editions?
gahhh I can't just hook the hand play function
hmmm im not sure then
is updating a global after a hand played something I really have to lovely patch
fix
ed
also darn
ill try and mask it with the flip then
when do you need to reset it? does context.after work? because you can hook calculate_context if so
Replying to this because of chat overtaking the previous one
is it the function Card:flip() thing in card.lua?
https://discord.com/channels/1116389027176787968/1155557846805643434
https://discord.com/channels/1116389027176787968/1210670452716994600
https://discord.com/channels/1116389027176787968/1341137401464229939
https://discord.com/channels/1116389027176787968/1330588575334535178
https://discord.com/channels/1116389027176787968/1335608541196582913
None of these are about consumables which I need the most
oh is it a jokerdisplay problem?
it's run in real time so just save the hand in a joker_display_values field until the hand is not played anymore
that's what I've done at least
sorry what would that look like
how do i turn played cards into an enhancement/suit
is there some global variable I can reference?
This will keep the previous hand until a hand is not played anymore
card.joker_display_values.display_hand = next(G.play.cards) and card.joker_display_values.display_hand or card.ability.extra.current_hand
(replace that for whatever the current hand field is)
ohh thank you
Oh! You still here? I still need more ideas. Only 4 out of 50. And I have to finish the mod by tommorow.
you have to?
Well yeah.
okay I realized it's so much simpler if I just start with if next(G.play.cards) then return end
also yeah
you plan to code 50 consumables by tommorow?
don't tell me this is your chemistry class homework
i want to satisfy the ever increasing demand for more balatro mod content
maybe
meanwhile its been 2-3 weeks and ive only gotten 13+ jokers done
:3
it's been a month and ive only gotten 129 jokers done
and I'm making 170 more at least
I've finalized my mod concept. I'm just stuck on a name.
i mean i joke about it but every 10 jokers in my mod is like 1 in other mods so it's not that much difference
quick question, would this be possible (i am the only coder in this mod project so asking in advance)
you won't with a mod made in 2 days
quality over quantity is always more pleasing
yeah, i always try to make my jokers like that
i feel like at this point, i can make an API for rpg in balatro
😭
yes, they all sound relatively easy
role-playing game?
gun
yeah, i added stats, buffs and debuffs, stats visualisers for both jokers and playing cards
role-playing gun?
I'm stuck between the names Chipcraft and Hexadecimal.
what's the mod about?
honkai star rail
sounds possible
i like names that are not just one regular word because i like ego-searching
im seeing that you need to take ownership of some jokers
btw it's easier to make bloodstone 0.5 in 2 than 1 in 4
card.config.center.key
card.config.center.key
User's name: Ralsei
looks inside
Homestuck pfp
Bruh.
ty

the curse of homestuck
It's themed around Witchcraft. Hexes and spells and stuff.
chipcraft is better
but to uhh, be more specific:
my mod adds jokers which have their own stats and equipment slots, as well as effects which scale on them
i added gacha system in shop
yeah, equipment slots
their effects are unique too :3
you equip them to a joker from my mod, and they will start giving chips/mult equal to whatever is on there
on top of their existing effects
and uh how do i do the little wiggly animation when a card activates
:juice_up()
at end of hand?
bad phrasing if you ask me
this?
yea
ty
true, its from the early days of my mod
"during main scoring" or "during joker scoring" would be better
jokers can also destroy other jokers of the same name if they are in the joker arwa
area
to gain additional buffs
and there are a ton of other interactions between jokers too, allowing for synergies
I tried making a custom consumable type and its crashing when I click the consumables section of the collection. Anyone know why that might be?
The error message isn't helping to much it's just telling me ui stuff isn't working which I kind of already got
funny thing i made a skill trees mod, might just make some cross-mod skills for this just for the rpg mod synergy, would be funny
that would be really cool :3
woop
idk if I'm able to help but please post the code and crash log
ignore that
I'll probably start working on my mod soon-ish tbh. I'm making dinner, but I want to get started as soon as possible.
that was for another friend
SMODS.ConsumableType {
key = "Element",
primary_colour = "FFFFFF",
secondary_colour = "000000",
loc_txt = {
name = "Element",
collection = "Elements",
undiscovered = {
name = "Not Discovered",
text = {
"Purchase or use",
"this card in an",
"unseeded run to",
"learn what it does"
}
}
},
collection_rows = {6, 6}
}
-- Helium
SMODS.Consumable {
key = "e_helium",
set = "Element",
loc_txt = {
name = "Helium",
text = {
"Gain a Juggle Tag"
}
},
atlas = "test_mod",
pos = { x = 1, y = 0 }
}```
all this stuff is pretty much just placeholders idk what I wanna make yet
just trying to see if I can make a new consumable type
welp, with playing cards finally showing debuffs
guess i can continue finishing the jokers
okay so
can I see how you define the atlas?
sometimes i question my past self for using this
pela exposed??
like, it should be 1.2 instead of 20
she's been cancelled
naww 💔
im making a joker that activates whenever a card is bought. i want to target the bought card, but using "card" targets the joker itself.
how do i make it target the bought card?
I don't think the atlas should be the issue cause I use it for other stuff that works but here it is:
key = "test_mod",
path = "TestMod.png",
px = 71,
py = 95
}```
I have no idea sadly
really????
Well I appreciate the help anyways
inside context.buying_card?
yes!
context.card
oh.
that.
makes sense
thanks!
also
how do i check whether a card is a joker or not
now that i check back how i made the uis
card.ability.set == 'Joker'
i actually dont know wtf i did lmfao 😭
oh uhh also, is there any fast way to remove this, Ice suggested using a hook before but i hope thats not the only option...
freaky joker
its a joker mimic
oh, that makes sense
it turns into the next joker you buy
id honestly go with a design where its face is literally melting, if i were to ever add one of those shapeshifter jokers lol
i think it looks alright, though it doesnt seem that interesting if i have to be blunt
I can barely read the upside down text. Only real nitpick
i fixed the text... and also made it look a little fancier
gotta love actual life and responsibilities getting in the way of me working on modding 🙃
i bought that one
not that funny
:(
ik this is gotta be so easy to fix but uh 
you have #2# but not the second var in loc_vars
you need to return one more value in vars that is the current mult
so it doesnt know where to look at
its looking at a wall and determining numbers from that rn
yes, add another var to loc_vars so that it knows where to read for the (Current X(n) Mult) part
I figured it out :D
When I looked up stuff about the colors it said it should take hex codes normally but I guess you have to use HEX() or it doesn't work
how do i do the hovering effect that's done in hologram and the legendaries?
they are different
legendaries use Soul to get that floating sprite
editions use shaders
But the hologram's floating sprite is still using soul_pos
My next joker might be the Yun office
yes
Or brotherhood of iron
Yea
oh yeah, the one which increases xmult when a playing card is added
i forgot
i thought you were talking about the edition
sorry, its still soul
oh ok
why is it using card.ability.extra.mult in the calculate instead of card.ability.extra.e_mult?
i haven't modified it yet
thank you!
i definitely did not see this coming
The more I read about lua’s metatable the more BS it feels towards Talisman’s un-comparable table numbers.
This may sound impossible, but I need to know so I know whether it is possible or not.
I currently have an idea that joker1 will allow joker2 to be stocked into shops in the current run if joker1 destroys itself. Similar to Gros Michel and Cavendish.
How can I make this happen so that joker2 can be put into shops now when joker1 is destroyed?
i would advise looking at moddedvanilla for an example, that may help
https://github.com/Steamodded/examples/blob/master/Mods/ExampleJokersMod/ModdedVanilla.lua
gros michel and cavendish both are in here
Thanks
is there a context for when a joker is added to your build, that triggers on the joker being added?
actually wait i did this already
yes
add_to_deck = function()
end
mhm
i just forgot
also, hi yme :D
can i define a custom function on a joker and then call it?
what do you mean by that
i mean i did it
nice job aiko :3
like how you can define a load function
load = function(self, card, card_table, other_card)
which is then called elsewhere
YES
i'd like to do the same thing but call the function in the joker's calculation code
kinda
if not possible ig i could just make it a local function, but more annoying
i defined the functions outside lol
yea i guess that works
and besides, if you are gonna use it in calculation anyways then you can just define a function outside, its less work
bumpalump
for enhancement, its
card:set_ability(G.P_CENTERS["enhancement key here"],nil,true)
i dunno about suits though
oh yeah
check the tarot cards code
hi
probably? you will need to check whether they have hooks and patches for that too
-# theres definitely misprintize-related patches, i remember seeing one
Why does this assertion fail?
i know how to spawn a random joker with SMODS.add_card, but how do i spawn a specific one?
The doors are open real wide for ya now. Welcome to the fun part 
I am once again having ui troubles 😔. I was advised to use this pattern to display a custom UI using loc_vars, so circumstantially it can return main_end with a UI element displaying a cardarea
if info_queue then
info_queue[#info_queue+1] = {key = "artist_coop", set = "Other"}
return {main_end = {}}
end
if card.ability.current_hover then
return {main_end = {get_pack_ui(card, card.ability.current_hover)}}
end
end```
However, it works on hovering over a booster pack, so I have to call loc_vars manually whenever the hover context gets fired, and I can't seem to make the cards disappear after the first call, they just linger
Add a ‘key= ’ field
thx !!
i get this crash message
Show the code rq
im trying to spawn the joker from the second image
Your key input is wrong. The correct key would be, in your case, j_[MOD PREFIX]_ulti
why is banned_keys not working here
nvm i figured it out i think banned_keys literally only works in challenge decks and nowhere else
gotta use no_pool_flag instead
i think
anyway
Are consumables typically the same size as Jokers or are they a different size?
i think they are the same size but i can verify it rq
they are a different size but seperated the same distance on spritesheets
consumables are 63 x 93 while jokers are 69 x 93 but every "grid" on their sprite sheets are 71 x 95
Got it
there are consumable templates somewhere (if its an existing type that is) in this server so you dont rly gotta worry about recreating it from scratch
like searching (x) template in the search bar youd probably find it
no_pool_flag doesnt work either
i'm at a complete loss
i'm guessing no_pool_flag only works on jokers and i wasted my time trying to use it on a booster pack
how the fuck do i make it not spawn ive spent three goddamn days trying to figure it out
banned_keys seems to be coded to only work for challenge decks and no_pool_flag seems to only work on jokers
CHAT AM I COOKED
What would the IF Context combination be if I need the Joker to destroy a certain card, but after scoring.
This is just basic as I need to get the main functionality working beforehand. I also did context.after and it was not triggering at all. "Working1" is supposed to be printed if it does find the correct context
help
that wasn't it either
you know what i give up
Is it possible to give Decks rules from Challenges? I'm wanting to make it so that no Jokers spawn in the shop but I can't figure out how to add no_shop_jokers to the Deck
If you can then I have been unable to because I've been trying to ban a specific booster from appearing on a modded deck and it literally refuses to work
Damn I've been trying for a while and can't figure it out
ive been trying for like three days
I did just start learning this today though so I'm not surprised lol
You can absolutely use banned keys
im not sure what im doing wrong then
ive tried with and without "p_" in front
they still appear
wait
How do I make it so a card can be enabled by having, for example, a Bonus card or a Mult card? My current implementation gives the following error.
key = 'empowered',
loc_txt = {
name = 'Empowered',
text = {
"Retrigger all {C:attention}Bonus{}",
"and {C:attention}Mult{} cards"
}
},
config = {},
rarity = 1,
atlas = 'MASS',
pos = { x = 4, y = 1 },
cost = 5,
enhancement_gate = {'m_bonus', 'm_mult'},
loc_vars = function(self, info_queue, card)
return { vars = {} }
end,
calculate = function(self, card, context)
--Replay the bonus and mult cards!
if context.repetition then
if context.cardarea == G.play then
if SMODS.has_enhancement(context.other_card, 'm_bonus') or SMODS.has_enhancement(context.other_card, 'm_mult') then
return {
message = localize("k_again_ex"),
repetitions = 1,
card = card,
}
end
end
end
end
}```
??????????
Shader code?
Encountering a previously considered but strange design question when it comes to this card:
Having a tool to predict card packs is cool, but it does inherently "peel back the curtain" in a way on the pseudorandom values that drive most of the game's logic, so for example both of these standard packs as shown as having identical contents, when that's inherently untrue (I just can't simply predict which pack the player will open first if they open both). It also means that if a player passes on multiple of the same pack type in a row in different shops, the seeds will never advance, regardless of what other cards are bought, showing multiple shops in a row as having "identical" contents in their boosters
So the solutions are... one, probably make the joker unable to be found before a specific ante to make it likely that the player has economy to skip packs less, two, pull some bull to show seed advancement multiple times to show packs as having different contents and then manipulate the sprites when you open them to match what they saw with the pack they picked
The latter is a ton of work though
The loc_vars mentioned in the error is the loc_vars here
Hey y'all, I get a crash "attempt to index field 'extra' (a nil value)" because of the code below. Why does this happen?
config = { extra = { can_tag = 1 } },
calculate = function(self, card, context)
if context.after then
card.ability.extra.can_tag = 1 --crash occurs first at this line
end
if context.end_of_round and G.GAME.blind.boss and card.ability.extra.can_tag == true then
add_tag(Tag('tag_ethereal'))
card.ability.extra.can_tag = 0
end
end
When/ What timing does it crash?
right before playing cards are scored
I have an unlikely guess about what could be the issue.
Is it crashing during a run you continued on?
yes
And at the moment that run started, is can_tag already defined in extra?
okay starting a new run stopped the crashing, ty!
calling for backup here! I'm trying to make a Joker that gains X0.25 mult whenever a specific hand is levelled up, and I have this so far
-- Global events hooks
local CommonEvents_luhRef = level_up_hand
level_up_hand = function(self, card, hand, instant, amount)
sendInfoMessage(hand)
CommonEvents_luhRef(self, card, hand, instant, amount)
if to_big(amount or 1) > to_big(0) then
SMODS.calculate_context({ mstg_level_up_hand = true, mstg_level_up_hand_name = hand })
end
end
And I think I've done everything right, but for some reason, while it does detect the context, it just...doesn't pass along the name of the hand. And my little sendInfoMessage bit returned nothing!
The levelling up and everything still works, but I kinda need to get the hand information. Any assistance? Thanks in advance!
i've also tried doing this as a lovely patch, but still no cigar
i'm extremely puzzled
Update: Nevermind, I fixed it. Apparently I got too used to typing "self" in my hooks, and that ended up confusing the code and making it register nothing
What am I missing?
just made this post on smelly reddit and then remembered that the discord exists
try set_badges
assuming you're trying to make a special planet
just change the existing planets
ohhhh
assuming thats harder
as in like change localizations or just change one specific planet
how would i format that in like the main.lua
oh right sorry
would i have to do that for each individual planet i want to change
basically yea
ill give it a shot
for the SMODS.Joker: bit do you know if it would be .Planet or .Consumable
and if not how would i check
smods.consumable
awesome
its throwing up an error for this code about not closing the curly brackets
SMODS.Consumable:take_ownership('saturn',
{
badges[#badges + 1] = create_badge(localize('k_planet_q'),card_type_colour, nil, 1.2)
},
true
)
that code is not inside of any function
its in function SMODS.INIT.TexturePackTemplate()
oh wow i never changed the name of that from the template
that's not what I mean
it is directly inside of a table
you don't need a SMODS.INIT function at all btw
huh ok
SMODS.Consumable:take_ownership('saturn', {
set_card_type_badge = function(self, card, badges)
-- the code
end,
})
mobile wtf
would 'the code' just be the thing i wrote inside the other one
specifically the line where you create the badge
I'm not sure what the true is supposed to be doing
definitely not like this
right it's outside not inside, just looked weird on mobile
you don't need it
it just makes it so it doesn't add your mod badge to what you're changing
sorry I just woke up haha
so im trying to store the first discard of a round before destroying it, and then when a consumable is used create new playing cards with the same suit/rank but with added enhancements, i have no clue what i'm doing when it comes to creating the new cards themselves sadly
right now it throws this error:
okay i forgot about P_CENTERS, now the crash log is different
development resumes tomorrow
i had suit and rank the wrong way around 🤦♀️
okay so this happens right before the crash should i be concerned
i'm following how base game uses the create_playing_card func but i don't know if steamodded changes something about how this func is used
have the exact same problem lol
is anyone familiar with the Booster:take_ownership_by_kind() function cause i cant get this code to work
SMODS.Booster:take_ownership_by_kind('p_celestial_normal', { atlas = 'boosters_owp' })
SMODS.Booster:take_ownership_by_kind('p_celestial_jumbo', { atlas = 'boosters_owp' })
SMODS.Booster:take_ownership_by_kind('p_celestial_mega', { atlas = 'boosters_owp' })```
its not throwing an error or anything it just isnt overriding the atlas
you're using it like it's regular take_ownership
i havent been able to find any examples so idk how its meant to be used
take_ownership_by_kind takes a booster "kind" instead of a key and applies to all of that kind
So SMODS.Booster:take_ownership_by_kind('Celestial', {...})
woah holy shit that worked thank you
hello aure smart smods man may i have your assistance
no
crying
||I jest, of course||
been struggling w this since yesterday :L
hold on it looks li8ke this now
at a glance, you're setting seals and editions wrong
newc:set_seal(...)
newc:set_edition(...)
Raking my brain for almost two hours. How do you give the player a tag from a joker? More specfically, the Ethereal Tag?
add_tag(Tag('tag_ethereal')) iirc
i had it like this but i changed it for some reason i forgot 😭
either way i'm getting the same error, i think the issue is in create_playing_card
what's the error again
but it's hard to say because the crash log points to a base game script
this
can I see what's in your file dumps around the line where it crashes?
it's this func
no, it's a table of numbers when it should be a table of tables of numbers
bruh
aight let me try it now
no way that was literally it
works like a charm
thank you but like damn how am i this much of a goofball with syntax 😭
br
br
When a booster pack is openning, how do I check if its a specfic booster pack? The four(?) Spectral packs to be precise. Currently making it so that the joker earns Xmult if Spectral packs are opened
when context.opening_booster (i think that's the name) you can access SMODS.OPENED_BOOSTER and check if the booster is a spectral pack
is there way to check fir a card with no enhancements?
i have NO idea how im gonna do this
yup, time to dig through that mess
orrrr you can ask aikoyori for reference
@tall wharf hi
their edition halves the values of cards
doubling joker values is luckily not too difficult, I found. It only gets hard if you wanna be clever like me and exclude certain values from the multiplication
but you can just store the pre-multiplication values for safekeeping, then iterate through their ability.extra and x2 every value
hi alex
oh, really?
i find it easy for vanilla jokers, but idk if its possible for modded jokers too
modded may have the problem that certain values or intended behaviours break
since my guess was that you go through a number of vars like "mult" and such in the card.ability.extra to multiply that up
how do you half the values of a card
this is the function i https://github.com/Aikoyori/Balatro-Aikoyoris-Shenanigans/blob/be85d506a47699061dc442916f2166dd42acf5a3/modules/misc.lua#L383
So it's really gonna depend on what your approach to compatibility is
orrr wait, are you just multiplying all the values in card.ability.extra?
I think Cryptid only multiplies values with chips or mult in the name? Or has some exceptions? I haven't checked that code in a while
I think cryptid straight up doubles every number value, honestly
so i guess you should multiply the nominal value
not really
I'm checking now just to be sure, because I remember there being so many checks, haha
Hi chat. I'm debating making my mod a generic dumping grounds mod because I have so many ideas
do you guys think it would be interesting for certain jokers in my mod to synergize with vanilla jokers, like having literal effects saying "If (x) is to the Joker's right, (y)"
it just checks to see if the number isn't one of a few values you don't wanna multiply, right?
If you commit to it, yes. I'm finding that it's less fun if those synergies are rare enough that vanilla jokers feel more like a burden than an element of the mod
ehh, i dont think i will ever put Rare jokers in the mechanic if im really gonna do it
mostly just common/uncommon jokers
I've been playing around with it, because I like some synergies between my jokers and the vanillas, but the vanilla jokers, because they aren't movie jokers, are inherently weaker because they can't earn you explicit Synergies from my synergy system, so no joker slots or bonus value.
for now, im intending to make Literal Trash synergize with Joker, giving both of them x mult for example
Referencing specific jokers also gets weaker the more jokers there are ofc
since both are early game jokers, i think what it does is allowing them to become more useful after their intended phase
How do I give a Joker two enhancement_gates?
