#💻・modding-dev
1 messages · Page 403 of 1
that will add 4 mult to the score, exactly as the basic +4 mult joker does
thx guys, i will read more
dw about func its not used very often
How did you get it to appear?
get what to appear?
what jokers usually use?
The joker
like, the hiker?
can you show a screenshot of your mod folder
of what's inside it
It's only used for jokers that don't return so they can be retriggered.
I thought func was only used in return
And what’s the achievement code rn
does your mod show up
Like SpadeAceBlade.json

yeah change the metadata file
this is the achievement code rn
SMODS.Achievement{
key="touch_grass",
atlas="achieve",
-- hidden_text = true,
pos={x=1,y=0},
hidden_pos={x=0,y=0},
unlock_condition = function(self,args)
if args.type=="touch_grass" then
print("Came without the prefix")
end
if args.type == "touch_grass" or args.type == "SPL_touch_grass" then
print("unlocked with the prefix")
return true
end
end
}
all my other jokers show up idk why this one decided to dip
Yes, it is.
Iiin which mode?
wdym "which mode"
At this point I have no idea
metadata file is the .json
Like adding or removing something
I meant jokers that wouldn't return normally.
rename it
I'll check if it does show up
They would be put in a func in a return.
Nope
show us whats inside the metadata file
it can be any name for the json file
wait rlly?
so func would be like a return for those jokers that can't use it?
eh good practice regardless
No, it would be in the return.
but it's whatever
im lost
delete everything inside the [] in dependencies
you're missing commas
This would be cartomancer for example:
@solid mesa what kind of joker do you want to make
I saw that it was j for jokers
Probably like "sab" for "Space Ace Blade", but you just want to be absolutely sure its unique
Yay made some progress
my joker doesn't show up for some reason (its not cause of the files i have other jokers in the same file that show up)
loc_vars issue?
or is it the whole thing since its also missing art
Now I'll check if I can make it so it shows the "art" and text
nvm i just reset balatro and it works fine now
so you put this structure the many times you want retrigger?
G.E_MANAGER:add_event(Event ({
func = (function()
--content
return true
end
for art use:
atlas = "<your-atlas",
pos = "{ x = <some-val>, y = <someval2> },
for text use:
loc_txt = {
name = "<your-jokers-name>",
text = {
"separate lines",
"like this"
}
}
text can also be done through localization files
there is no step by step guide on how to make a joker
the way a joker is made depends entirely on its intended effect
for retriggering cards, use context.repetition and return { repetitons = number )
not like the "idea", but im learning lua too
by card you mean anything in the game?
I actually wanted to make a video about my journey making Deckception (my mod) that's sort of a modding guide for beginners
playing cards
jokers have a special retrigger that you need to activate through SMODS
i feel like you're just confusing them more and more
Kay
but that well be like jokers in cards, what about jokers in jokers?
-# if you dont mind im doing that reply ping thing again
-# heres the message link to the achievement code if needed
-# #💻・modding-dev message
put something like this in your main.lua:
-- Opt-in to SMODS features
SMODS.current_mod.optional_features = {
retrigger_joker = true
}
this activates the ability to retrigger a Joker
dont put ? in me, im more lost of how i start asking things XDDD
i was abt to reply
take out the either or stuff and just leave it as the modprefix version of the args
What is a "Joker in a Joker"?
yes this is not what they're asking about
nah that's too advanced for me already
they don't even know lua apparently
so saying all of this isn't really helping them
-- Context to use when retriggering jokers
if context.retrigger_joker_check and
-- Makes sure it doesn't retrigger copies of itself
context.other_card.config.center_key ~= self.key then
--- Code
end
does anyone know why my joker does nothing
calculate = function(self, card, context)
if context.before and context.cardarea == G.play and not context.blueprint then
print("a")
if context.full_hand[1]:get_edition() == "e_base" then
print("b")
context.full_hand[1]:set_edition('e_negative')
card.ability.extra.hands = card.ability.extra.hands - 1
return {
message = localize('para_k_transformed'),
colour = G.C.ATTENTION
}
end
elseif context.after and card.ability.extra.hands <= 0 and not context.blueprint then
para_consumefood(card)
print("c")
return {
message = localize('k_eaten_ex'),
colour = G.C.ATTENTION
}
end
end
none of the print statements trigger
you have jokers that retrigger playing card, and have jokers that retrigger another jokers, and even jokers that retrigger himself
It wouldn't retrigger copies of itself by default if that's the only thing it does.
welp i did that
still didn't work for some reason.
Jokers can't retrigger jokers that retrigger jokers.
better to have the extra security imo
boredom?
does boredom retrigger chad?
jokers can do anything you want and they're limited by your knowledge of lua and creativity
Jokers can retrigger the part that retriggers playing cards but not jokers.
new joker where i become the us president
Yes.
Jokers can retrigger jokers that retrigger playing cards.
boredom can retrigger boredom
(at least that's what I interpret when I see them play)
no chad from cryptid not hanging chad
note that
Yes, but only the part that retriggers playing cards.
Then no.
ok its like commom sense or stucks in scoring, but sometimes it looks like that

Remove the card area checks.
I feel like i'm getting closer
Not just Jokers... but you can pretty much do more the more "advanced" you go.
-# Like me spending ~8 consequtive hours trying to make cards score forwards and backwards nicely and still not fully getting it right. :c
-# And you can see my suffering in https://discord.com/channels/1116389027176787968/1307810407389593630 --
pos = { x = 0, y = 0}, is that what the line looks like
can you show me what that looks like
you accidentally put a quote (") where it doesn't go
in the pos = blah blah line
what do you mean by that exactly
if context.other_card.edition to check if an edition exists.
Got it
Getting more errors
after you changed it
if you want to check if it doesn't have an edition do if not other_card.edition
e_base
but anyway for something like this you're probably gonna wanna use generate_ui instead
-- Achievement
SMODS.Achievement{
key="touch_grass",
atlas="achieve",
-- hidden_text = true,
pos={x=1,y=0},
hidden_pos={x=0,y=0},
unlock_condition = function(self,args)
if args.type == "SPL_touch_grass" then
print("unlocked with the prefix")
return true
end
end
}
-- Joker
SMODS.Joker{
key="grass_joker",
rarity=1,
cost=3,
atlas="grass",
pos={x=0,y=0},
loc_vars = function(self,info_queue,card)
SparkLatro.touched_grass = true -- actually not really used but
check_for_unlock({type="SPL_touch_grass"})
end,
}
The more I try to analise and think of smt the more my brain breaks
I'm cooked chat 🥀
you just have syntax errors in your code
ok then yeah use generate_ui instead of trying to do it in locvars
are you using vscode
Like unnecesary {}
yup
the error says you're missing a } somewhere
well i changed it to generate_ui and it still did not unlock
....send the code
first one
SMODS.Joker{
key="grass_joker",
rarity=1,
cost=3,
atlas="grass",
pos={x=0,y=0},
generate_ui = function(self,info_queue,card,desc_nodes,specific_vars,full_UI_table)
-- yes the variables are not going to be used its fine
SparkLatro.touched_grass = true
check_for_unlock({type="SPL_touch_grass"})
end,
calculate = function(self,info_queue,card)
end
}
is there a way to check if you're playing balatro in windowed mode vs. fullscreen
define your atlas before your joker
So after the smods.joker it goes the atlas then the joker
bump (currently center, not card, but still having the error)
key is just a string
can be anything you want to name it
and when you use the atlas in a joker or in any other object you use the key that you put
does anyone know the vanilla chances for each rarity in the shop
common is 75%, uncommon is 20%, rare is 5%
it is in weights
nobody knows what the weights are from what i can tell
oh, well then thank you for giving it to me in percentages
but those are the chances
is there any way to get loc_vars from an arbitrary joker?
only if you have an instance of that joker
weights?
i do, how do i get it?
send a log message to see if it's running
yeah, the joker rarities are expressed in the code as weights, not percentages
first you should check if it even has a loc_vars function, vanilla ones don't
if joker.config.center.loc_vars
tf, explain that
and then you should be able to call it with joker.config.center:loc_vars({}, joker)
I'm not 100% sure if this will work btw
just an educated guess
like the "em" for pixels?
will it work on vanilla jokers then? or no?
vanilla jokers don't have the loc_vars function
generate_ui = function(self,info_queue,card,desc_nodes,specific_vars,full_UI_table)
print("hi yes we are generating the uI")
-- yes the variables are not going to be used its fine
SparkLatro.touched_grass = true
check_for_unlock({type="SPL_touch_grass"})
end,
so theres no way for vanilla jokers. ok
like the percent chance is 75% but that might be expressed as 1.5 in the code, it may be expressed as 20, it might be 700
the loc_vars of vanilla jokers are in Mods/lovely/dump/functions/common_events.lua, and search for "loc_vars"
they're all inside a generate_ui function that is common to all cards
hard coded basically
ah, fair enough
how you can put american metric system in programming? jesus
i didnt make balatro, dont ask me 🤷♀️
ok cool it runs fine! in that case can you send the achievement code setup?
agreed
explain
It's the only way you can really create a chance-based picking system while still allowing unlimited additions
i dont think ive changed it but here it is
SMODS.Achievement{
key="touch_grass",
atlas="achieve",
-- hidden_text = true,
-- reset_on_startup = true, -- TODO: remove once you've actually finished the mod lol
pos={x=1,y=0},
hidden_pos={x=0,y=0},
unlock_condition = function(self,args)
if args.type == "SPL_touch_grass" then
print("unlocked with the prefix")
return true
end
end
}
first time i heard that
truth
oh so you just remove the coma?
for a common, what value of n is fair in
1 in n chance to give Xn Mult
?
im wishing i could make a custom rarity but since i have no clue what the vanilla weights are i can't really do that
its probably just the percent numbers tbh
oh sumatorias
like just straight up 75, 20, and 5?
probably
No, it's all relative. An item of weight 2 will be chosen 2x as often as an item of weight 1
i found this on the smods doc idk if you already found it lol
i did not
interesting
so they are not chances anymore, they are situations?
Imagine you have a pool of items where each item has its own weight, you can interpret the weight as the amount of copies of that item in that pool, so items with more weight (aka more copies) are more likely to be drawn
i put in .75, .20, and .05 in my code and that did not work at all lol
This is on the create card in utility functions
speaking of, if I wanted to create a card a la The Fool how would I do that?
how would i detect if a blind ended and i didn't lose?
context.end_of_round and not context.game_over
but you dont have 0 n 100, all relative to all weights of the objects?
i'm not sure what you're asking
I understand it, I just need to interpret it.
weights are the only system or smods have another?
is the achievement already unlocked?
smods uses weight
nope
how would i detect if i was saved by a joker? (ex: mr bones)
no
?
wait how do you see that as not PC?
obv theres a reason but idk what sticks out there
wh@t
I saw what they deleted.
what
oh they deleted smth
see what? the rule?
does this image show something that makes it not PC?
im just curious
or is it smth they posted and deleted
the previous one
the previous one had volumen bar
Does context.game_over persist?
crazy work
it should be working then
are you sure it isnt unlocked?
mr bones works in context.game_over
yeah but so does actually losing
its not unlocked
and the imagen above have wrong pc width, if you are asking that
is there a rule against modding non-PC balatro cause you have to do some weird stuff that youre not supposed to do in order to make it moddable
this is how the round eval checks
at least on mobile you have to do a lot of workarounds
no, its just because its against platform TOS
i havent modded mobile balatro before but there's a reason it isnt possible
yea so stuff youre not supposed to do
piracy surely
anyways
I have managed to create an invisible, uninteractible neptune
no, just any modding not necessarily for doing "weird stuff"
bump again
against google play store TOS probably
how do you even know it's there then
not that I know what exactly
its not negative
how can you tell it's neptune
prob bc thats the function of the card
you guys can't see it?
looks like neptune to me
emplaced a neptune
yeah i can see the
personally i prefer
anyways i want my neptune to be usable 😭
btw, what do to that dude? 😭
tis what i was doing.
eval G.consumeables.cards[1]:use_consumeable()?
returns nil
returning nil is not unexpected, but did it use it
yeah it returns nil because it doesnt have a return thats normal
still 1/2
maybe just kill it and try again
D:
what did you do to emplace it
uhhh
don't save card objects in your ability tables
you will break your save file
oop
what should i do then?
. save it as a variable outside the card..
somehow, forgot that was an option
lol
are you trying to replicate the fool behaviour
if only there was a mod that replicates every tarot in an smods friendly way
damnit!!
vanilla remado my beloved
i fumbles
how can i make an enhancement replicate the card played next to it, regardless if it's being scored or not?
context.full_hand
conte- you guys are just demons i swear
then this should be easy
but how do i
you want to get the effects the card next to it would have had if it was scored?
yes
it replicates it thrice
yes, but i want to do more than just tarots and planets
you can keep the key saved instead of the card
honestly that sounds very complicated and probably requires a lot of lovely patching in my mind
how would I acess that? I tried card.key
guh
card.config.center.key
A blueprint for playing cards?
kinda!
I think you would just eval_card it but change the card area to G.play temporarily.
more like chad, but just right, not rightmost
hm? could i see a place where i would find an implementation for this
for the time being i have just disabled achievements in the mod
https://github.com/Somethingcom515/SealsOnJokers/blob/allinone/main.lua#L1366 But change context.cardarea to G.play before the eval and change it back after.
is 1 in 2 chance for X4 Mult too OP?
on what
idk
alright
chances for XMult at all feel pretty weak because of how unreliable they are
oh nice, i didn't think of that, was overcomplicating it
why doesn't this prevent me from being saved by mr bones
elseif context.end_of_round and not context.game_over and ((to_big(G.GAME.chips) - to_big(G.GAME.blind_chips)) < to_big(0)) then
G.STATE = G.STATES.GAME_OVER
G.STATE_COMPLETE = false
end
I've been trying to do a card that makes specific played cards retrigger, but that's not happening for some reason. Does it not work when the id its being compared to is a variable?
card.ability.extra.marcVal
not just marcVal
where main_eval
wdym
Ah, that's right. Thank you!
one rarity higher than bloodstone since its better than bloodstone in 2 aspects
is it on a jonkler or a playing card though
because jonklers dont trigger as much
and context.main_eval
(also you should probably move the number comparison to a separate conditional)
they were asking for rarity
holy shit youre right
without retriggers, this is better than bloodstone
unless its 1 in 2 chance after hand is played
wdym after hand is played
like when does it trigger
context.joker_main
but, it is technically better than bloodstone unless you have retriggers
if it triggers off of cards then yes bump, if not keep it same rarity as bloodstone
yeah it's not really better than bloodstone in that aspect
elseif context.end_of_round and not context.game_over and context.main_eval then
if ((to_big(G.GAME.chips) - to_big(G.GAME.blind_chips)) < to_big(0)) then
G.STATE = G.STATES.GAME_OVER
G.STATE_COMPLETE = false
end
end
``` does not work
once you get retriggers its worse
just like in the game its from, first few antes joker (i mean, early game thing in that game but same premise)
the only buff a joker that has 1 in 2 chance of scoring x4 mult in context.joker_main can have is from oa6s
is it supposed to be like mr bones
its based on the Eoka Pistol from Rust
it kills you even if bones saves you
and polychrome
i think this joker makes a LOT more sense with that info
but doesn't kill you if you beat the blind normally
shouldnt it run in the same context as mr bones then
which is?
just make it same rarity as bloodstone since a joker that doesnt trigger off of scoring cards can't be upgraded as much as one that does can
its meant to be early game so i kinda want it to be common
cause mr bones operates in game_over (who wouldve guessed)
doesn't work
id say reduce the effect then because loyalty card which has the same effect in a slightly worse activation way is uncommon
loyalty card is not something i want to be balancing based on
ignore everything i say then
im not balancing a joker based on one of the worst in the game
oh wait shouldnt the forced game over be an event
like E_MANAGER event
idk
does nobody know how to fix this
Soo finally made it load without crashing the game
-# Darn I need it so it triggers with spades, make it load the art cuz even with the atlas stuff it dosen't load and make the spade part be dark blue
First I'll lock in and check if it works
what do you mean by the atlas stuff
The art
no, your issue with it
my neptune is real now ^^,
joker 2
visible neptune? preposterous
you dont need the second atlas in that code
also
what does your joker call for as the atlas
hush they have art im just too lazy to actually put it in thw atlas
Srry did not understand
your joker code
it has atlas = somewhere in there right?
nope
put in your joker code atlas = 'ae',
OMG TY
I'll figure a way to do something myself, it's a personal nitpick
alr
elseif context.end_of_round and context.game_over and context.main_eval then
if ((to_big(G.GAME.chips) - to_big(G.GAME.blind_chips)) < to_big(0)) then
G.STATE = G.STATES.GAME_OVER
G.STATE_COMPLETE = false
end
end
why doesn't this prevent mr bones from saving me
finally, n't
æ
Yo, I need help with something, anyone able to?
just ask your question
don't ask if you can ask something
XD???????
bump
reinstall lovely
another one
I have, 3 times
reinstall steamodded and lovely
Still didn’t work
what mods do you have
Cryptid and Pokermon
okay her backsprite is a bit fucked up (I guess its too dark?) buuuut thats my second joker almost finished up.
Anyways enjoy literally just my username lol
do you have talisman
Yeah
reinstall everything
bump
Where did you install it to? It should go in the Balatro installation folder (usually at C:\Program Files (x86)\Steam\steamapps\common\Balatro), not in the Mods folder with the other mods
It’s still not working? Idk what’s going on
Also make sure your Balatro is updated to version 1.0.1o
ok, so someone was playing my mod and got this error when they played a Royal Flush
Is this a joker? Also your lines don't match it seems because extra is not present.
What does that line look like on their side?
yes
It’s loading
bump
Do you want to prevent all jokers that save or just mr bones?
all jokers
You should probably just patch where saved is checked.
where is that?
about the exact same
The problem is you need to check context.other_card.ability.extra and type(context.other_card.ability.extra) == "table"
like this?
Yes.
awesome
Is this not correct for displaying a negative tooltip?
"{C:dark_edition,T:e_negative}negative"
tooltips are only for decks btw
if your not using it for a deck then you need to use loc_vars "info queue" system
I've done them on jokers too, but I guess vouchers are not that easy?
I didn't expect it to work for jokers
but yea I would still reccomend doing the info queue stuff
Yeah, that worked, thanks!
trying to make a new consumable type, but I need to make a pool for it it seems
SMODS.ConsumableType {
key = "tboi_reversed",
default = "c_tboi_r_fool",
primary_colour = HEX("89093a"),
secondary_colour = HEX("89093a"),
collection_rows = { 5, 6 },
shop_rate = 2.5
}
I pretty much copied this code from the VanillaRemade consumable for regular Tarots, so is this where I put the pool for my consumables?
Is there some good documentation for taking ownership?
How would I check if the player has a specific tag?
Iterate over G.GAME.tags and check tag.key
how can i make a joker add a card to your hand?
Try looking at Certificate?
Although the request has been resolved, wondering what a tooltip with a negative color would look like, or act like. Likeeee, edition shaders would be applied on the tooltip itself.
i'll try that thanks
Hi, I think I may have gotten a grasp on how to get things started with SMODS documentation. I also am about to start making my first joker, but I am running into a problem. Whenever I type in SMODS , there's a red line under it. Is there anyway I can fix those? I'm using VSC
Include the Steamodded folder in your workspace, if you're using VS Code or some IDE like that
You'll also need to make sure your file has the .lua filetype - this means naming it sunny.lua, not sunny.lua.txt like it is now
another way to include workspace libraries with lua is creating a .luarc.json file at the root of your project and adding the path to whatever other library you're using under "workspace.library"
bump
hi, i asked before how to make a joker add cards to your hand and i was told to look at certificate so i copied the part of its code that creates the card but for some reason its creating like 20 cards and i dont know why ```lua calculate = function(self,card,context)
if context.discard then
if #context.full_hand == 4 and context.full_hand[1]:get_id() == 6 and context.full_hand[2]:get_id() == 6 and context.full_hand[3]:get_id() == 6 and context.full_hand[4]:get_id() == 6 then
for _,playing_card in ipairs(context.full_hand) do
SMODS.destroy_cards(context.other_card)
card.ability.extra.happen = true
end
end
end
if card.ability.extra.happen then
card.ability.extra.happen = false
G.E_MANAGER:add_event(Event({
func = function()
local _card = create_playing_card({
front = pseudorandom_element(G.P_CARDS, pseudoseed('seed')),
center = G.P_CENTERS.c_base}, G.hand, nil, nil, {G.C.SECONDARY_SET.Enhanced})
local seal_type = pseudorandom('seed')
if seal_type > 0.75 then _card:set_seal('Red', true)
elseif seal_type > 0.5 then _card:set_seal('Blue', true)
elseif seal_type > 0.25 then _card:set_seal('Gold', true)
else _card:set_seal('Purple', true)
end
G.GAME.blind:debuff_card(_card)
G.hand:sort()
return true
end}))
end
end,
context.discard runs everytime a card is discarded, afaik
i think context.pre_discard is for every discard
i'll try that
You need to check for context.individual
Dun think other_card exists in every context
What are the keys for the different editions?
e_foil, e_holo, e_polychrome and e_negative
ok that worked, thanks everyone
context.individual instead of context.other_card?
huh
my code might just not be working then
hold on
No, you check for it when you check the card area.
if context.individual and ...
trying to add my own consumable type, got this error
nevermind I guess
bump
also, is this incorrect? it seems to not be applying echips or emult
are you using talisman
yeah
echip_mod and emult_mod should not be a table.
do you really need to use emult_mod instead of emult?
btw how do i set an enhancement/edition to the created card? does it work the same way as adding the seal?
that's just how i've seen it done in the past
Also the message wouldn't work.
huh why not
Because you're defining it twice.
Just do return {emult = card.ability.extra.emult, echips = card.ability.extra.echips}
im surprised your vsc didnt underline that actually
They don't have the lua extension.
sob
i do have it i just keep it off most of the time, bad habit i know
whats with people coding without Lua extension
Axy codes in Notepad++, with only a low contrast color theme. 
but then again you're already running vsc
nah i have plenty i just have a habit of turning it off
in notepad++ you can style the color of the code?
Axy just doesn't like the telemetry from VS Code, and VS Codium starts up a bit slower than Notepad++, soooo.
I'm pretty sure they said they turn it off because they don't like that the colour changes.
i actually fixed that one
but yeah by default the lua extension makes like almost all the text green
bump 🙏
makes it kinda hard to read
Not sure, but there's syntax highlighting and line numbers and code folding.
n++ does not have code completion though its fine if you don't need that
Axy never got used to code completion, so that works out
lsps like the sumneko lua extension provides provide that
yea, its just sometimes dont color none of the code
even it is in formatt
You might want to specify the language then
awesome, works great now, ty for the help yall
yess
Imagine if you replaced all letters with that
was an absolute pain to implement
did you change the max size of blinds?
actually, it's just this
how do I check if a played card is a certain rank
the font system is a recent smods addition
wdym?
if card:get_id() == id
They merged Aiko's font PR already?
yep!
yeye
I guess i more mean in what context do I do that
hypeeee
context.individual?
I don't want it to trigger multiple times if the card is scored multiple times
okii
thanks 
blinds cap out at like 1e308, going over it is what gives you naneinf in game. If you raise the cap, you could play with a Joker like that for alot longer yknow
oh yeah, talisman makes (most) numbers in the game able to go way above 1e308
theoretically infinite, if your pc can handle it
epic 👍
you can get scores like this lmao
...Wondering how difficult it would be to run it well on an FPGA
Use the massively parallel power of VHDL/Verilog
lmao yeah
To run... high frequency financials Balatro
im not using talisman for my mod bc i could never get used to having to wrap everything in to_bigs
for some reason i can't fast reload the game with alt + f5, only the holding m fast reload works. y'all got any ideas as to why? i'm on the latest version of smods
what joker are you using?
asgard, from my mod
what he does?
bump
the first time i reach that score (actually was ## ) i have cosmos and his puppet
oh sorry i dont see you name, i play your mod a few days ago
How do you tell if a Wheel of Fortune has failed
I made checks for that and you need to patch/take ownership to make that work

i feel bad patching these things because it makes my compatibility with other mods worse
but I guess I have 4 different Jokers based around modifying/using Wheel of Fortune so I guess it balances out
Taking ownership is a lot less destuctive if compatibility is a concern
Also it is very possible to make non-destructive patches
o
how do i change a cards rank to a selected number? is it with this? lua card:set_base(G.P_CARDS[suit_prefix..rank_suffix])
I might as well just patch the entire thing since I'm changing it anyway
How do I patch the use function of it
SMODS.change_base(card, suit, rank)
@vale glen
Ooh, am curious about how one would do that
thats easier lol, is it necessary to specify suit if the card already has one?
This is the patch I made for my purposes
No.
ok, thanks!
Basically using befores and afters are way more sustainable than using ats
Ohhh, patches, not taking ownership
Read that wrong 
all good lmaooo
Non destructive taking ownership would be nice though, then it could be like hooking a function
ownership taking in general is pretty non-destructive honestly
thank u again meoww
wat would the flag be here
It's just when multiple mods start to try taking ownership at the same time where it starts getting hairl
Firstly, it should be Mod/assets/sounds/1.ogg
Use the key in play_sound
Yeah thats what I originally had
But the game is telling me different
Not necessarily
It can just be the file name and it works just fine
What's your mod prefix?
MAES
No, I was referring to the file location.
Ah, so you are
oh is it play_sound('MAES_joker_spawn_ping')?
Thought you were talking about the path attribute
bump
Use play_sound('MAES_1',1,1) to get your original sound
Also do this, since the resources folder isn't the right spot
yeah putting that back to how I originally had it
I was confused as to why it keeps saying resources in Balatro itself
because nowhere in my code did I say resources
"Flag" is honestly an outdated term for this functionality. What I'm doing here is adding a custom context call to Wheel's fail code, allowing some of my jokers to detect when a Wheel fails
Technically I use this for more than just the Wheel, but that's moot for your purposes
Your mod prefix is whatever's in this line, in your JSON metadata file
fair
Not sure how I detect it with a Joker tho
Yeah.
MAES
I was asking if the corrected line was what I sent
For your purposes I would replace my payload with simply SMODS.calculate_context({failed_wheel = true}) and then check if context.failed_wheel in your Joker
Then prefix your sound files like written here
Finding out calculate_context exists was a game changer for me so I hope you find use out of it too
Oh, do you know how the return table works for that function? The second parameter to calculate_context
Ooo
this worked
Im probably gonna ask for help again because i also wanted to rewrite the functionality of the card itself 
I had a Joker that allowed Wheel of Fortune to make jokers negative
Admittedly I do not
Awh
Some contexts use it, but Axy's never, like, actually read those contexts to see how they're used, or what they contain
I honestly have never seen another mod use that arg so I never looked into it lmao
Mmh, just copying existing mods isn't great software engineering practice, bweh... Axy's never worked with code this large before though, so just reading all these fields is slow going

All of Balatro is a giant table, but it's also a giant table
i think the brackets are mismatched unless i messed up somewhere
Basically started around April 7 of last month, with some chatter among friends about making Jokers based on us
Made a few jokers and have 'em on a Github, if you wanted to have a look
I highly recommend you get the Even Better TOML extension for linting and formatting purposes
Ah so still pretty new, gotcha
After your juice_up line, add a closing curly bracket and two closing rounded brackets
No this is a patch, this is ok
My guess is you forgot a set of ''' at the beginning of the pattern argument
That seems to be the only place they're unpaired, so
in my mind I say "I'm probably fine as this is probably gonna be the last patch I do" and then immediately the next day I'm like "gah I gotta modify how Wheel of Fortune works in like three different ways"
Trust me, you will very likely do more patches lol
i dont know why i didnt include that part in the screenshot
Mmh, although the ideas the friends gave are ambitious and things
Ok yeah I think that's just a result of VSC not knowing how to format TOML without the extension lmao
o
Oh trust me I FULLY understand that pain LOL
last gamba of today to see if this is gonna get buried again or if someone is actually gonna help
vsc's ui is so confusing to me ;-;
Why can't it be more like vs
Like, this was a joker Axy coded in recently, and added dynamic descriptions so it's not a wall of text.
goodness me
I've come around to VSC after using VS for awhile ngl
It's honestly a lot more sleek
Better keyboard shortcuts too
Would it not be card.config.center.config.hand_type?
I mean you can use vsc shortcuts on vs
Sometimes
not by default but it's in settings
I've only really used vsc when I haven't had any other IDEs that support a certain language
lemme see if that works
which has been slowly decreasing
it's a planet btw if thats important
yup card returned nil again
Hm
Are you available for a screenshare to figure it out?
Axy has some time, if you don't mind that
Did you by any chance put hand_type in an extra table in your config?
it is not in an extra table, i was under the impression from other mods that it was not required
It is not
That's why I was asking lol
Could you send the full code of the card?
double checking
you mean the payload is like this right?
Tested it in game and doesn't seem to be working
yeah that should work
hm
Show the full patch if you could
Is that line in the right spot? Hrm
while we're at it the joker too
Ah that's why. Your check in the joker is wrong
full code, line inside colours trying to index a nil value
Literally the only context check you need is context.failed_wheel
How Axy does it is in [this message](#💻・modding-dev message), if that helps any.
oh
well then
this is like the second smallest Joker I've made so far 
actually it might be the smallest
the problem is colours not working, i haven't even been able to test the planet yet because of colours perpetually returning nil
I SEE THE PROBLEM!!!
The colours table needs to be in your vars table
Right, using center.config.hand_type doesn't reference itself. Try self.config.hand_type maybe?
Like this
Ah, that too!
Yeah, colours are a variable
That's 100% the crux of the problem. Don't try anything with self, that will BREAK!
Eh? They... don't break though?
They're the prototype of a card, shared between instances of a card
While stuff accessed with card refer to the copy of the card
this doesn't work either actually
changed that
still nil
I've had it break on me before so that's odd, but this is even more of a reason to use card instead
cuz the values could potentially be different
Ehhhh... Depends on what you're doing with it. Can't imagine hand_type changing unless other cards take ownership of that Joker, to change that specifically
Check your logs, see if the patch is failing
What does your code look like now?
where do i check those
change all of your card.config.whatevers to card.ability.hand_type
card is still nil, but even just center.config was returning overall nil for the line
mods/lovely/logs
will see if that works
card is still nil
wdym
ah ffs
I've gotten pretty good at sniffing out small things like that over the months I've bummed around here lol
Why was it changed at all xD
They changed it to center as a last ditch effort I assume
i do not remember why it's center (prob from the mod i copied to try and get the colours right)
WARN - [♥] Pattern [I'm not pasting the entire patch here] for pattern patch from JoJoMod\lovely.toml resulted in no matches
Do you by any chance have any other mod installed?
You might just have a tiny typo in your pattern somewhere then ngl
Try looking for a less broad pattern.
works now at least (it seems), will full test rn
yayyyy
They were copying mine so that's kinda on me lol
for anyone wondering why it doesnt say the hand name
the hand has no name
it's my worst nightmare
HELL YEAH IT FULLY WORKS
Gimme a sec, I'm gonna make a smaller pattern to check and give it to you to use
okiii
Does your approach work for vanilla Jokers too? Axy is trying to access hand_type or hand_types too, in their own Joker, and wandered around until they found this table that was shared between vanilla Planets and Cryptid Planets, among others.
pattern = '''
G.E_MANAGER:add_event(Event({trigger = 'after', delay = 0.06*G.SETTINGS.GAMESPEED, blockable = false, blocking = false, func = function()
play_sound('tarot2', 0.76, 0.4);return true end}))
play_sound('tarot2', 1, 0.4)
used_tarot:juice_up(0.3, 0.5)
'''
that seems a lot smaller
it is lol
Sometimes my adhd brain wants to make extra sure I don't patch something I don't wanna 😭
I have never ever seen SMODS.deepfind before 😭
it works :3
thank uuu
Woohoo!!

Happy to help
am i going to have to go through this for every single joker


Well, it worksssss 
Just wondering if using a different field would be better
this is going to be a very long weekend I'm guessing
What happens if you have an Act 2 and an Act 4 in the same hand, would they override each other based on the order of the joker
im getting this crash when looking at the joker outside of a run, how can i fix it? lua loc_vars = function(self,info_queue,center) return {vars = {center.ability.extra.chip_bonus * G.GAME.consumeable_usage_total.planet}} end, calculate = function(self,card,context) if context.joker_main then return { chips = card.ability.extra.chip_bonus * G.GAME.consumeable_usage_total.planet} end end,
You should be able to access hand_type from planet cards in your loop with v.ability.hand_type if that's what you're asking
4 would override 2
Though it would be quite hard to get into that position
You upgrade the Joker by getting a Stand Arrow consumable which is supposed to be almost like "The Soul" levels of rare
G.GAME and G.GAME.consumeable_usage_total.planet or 0
ok thanks!
Could possibly have a card that duplicates a given Joker then self destructs, then keep upgrading only one of the other Jokers. It'd be difficult, but not impossible.
true
invisible joker could allow for that
Yeah, although Cryptid has cards that look at hand_types instead, and Aikoyori has their own field name for it. So just checking v.ability might work, will try it soon. Thanks!
How does one allow for retriggers on a joker that doesn't return?
So, little bit of quick context, I am following along to the outdated YT video on how to make a joker and I'm at 4:52. So I finally got myself to the point to which I want to test to see if my Joker would be detected by smods and it seems to not show up.
I kinda wanna buff the joker because three stand arrows is insane but I think it's powerful enough
Cryptid compatibility is ambitious lol
But I wish you luck
Like I said, the video is outdated. Is there anything else I need to do for the Joker to appear in the game.
Well, it works for Cryptid planets with this method, outside of Ascended hands, soooo 
This doesn't do anything:
Take your wins lol
It does print "no effects" though.
got this crash with that lua loc_vars = function(self,info_queue,center) return {vars = {center.ability.extra.chip_bonus * G.GAME and G.GAME.consumeable_usage_total.planet or 0}} end, calculate = function(self,card,context) if context.joker_main then return { chips = card.ability.extra.chip_bonus * G.GAME.consumeable_usage_total.planet} end end, in_pool = function(self,wawa,wawa2) return true end
(G.GAME and G.GAME.consumeable_usage_total.planet or 0)
The biggest mistake I've typically seen is a missing metadata file. Do you have one?
the funny part abt having a really good enhancement that's all suits means it gets debuffed by boss blinds that target suits 4x as often
just have it unable to be debuffed, so shrimple
Yes. And it's a json.
What does your joker code look like then?
sunny.json.json
.jsom
jsom
erm what the scallops
main.lua.txt
me when the arrow hops between messages

crashed again lua loc_vars = function(self,info_queue,center) return {vars = {center.ability.extra.chip_bonus * (G.GAME and G.GAME.consumeable_usage_total.planet or 0)}} end,
main_fille
main_fille
badge_tect_color too
G.GAME and G.GAME.consumeable_usage_total and G.GAME.consumeable_usage_total.planet or 0
The code
Lotsa typos in your metadata. Might wanna look it over. Likely the cause of your missing joker
main.lua.txt is DIABOLICAL
how would one go about removing the main menu button
badge tect colour
Try using the JSON template.
I'm so tired 😭
Me too.
that worked, thanks
eternal... has no functionality of its own...?
Correct lol
lalala
Eternal’s “functionality” is just other methods checking if a card has it lol
how do i make a sticker thats like eternal but for playing cards (the tarot card meant to apply it to playing cards already exists)
I used the steammodded template to make the code from the first picture I took a few minutes ago.
How did it get messed up so bad????
You hook Card:start_dissolve and Card:shatter and you patch SMODS.calculate_destroy_cards
cool code terminology
how
When you said templates I was confused if you were talking about the metadata or the example mod? Or was it something else?
Million dollar question right there
-# ive learned that i barely if ever get somewhat useful answers from him tbh
The metadata
I am so new to making mods. This is my first ever mod project.
show how it looks in your folder
is there a version of G.playing_cards that works outside of game
My card keeps crashing because the preview keeps trying to access it
If it was from the metadata, then I pretty much used the templates anfd copuied it
Can you show the code you have have that’s accessing it?
set_ability = function(self, card, initial, delay_sprites)
local valid_cards = {}
for _, card in ipairs(G.playing_cards) do
if not SMODS.has_no_suit(card) and not SMODS.has_no_rank(card) then
valid_cards[#valid_cards + 1] = card
end
end
local lucky_card = pseudorandom_element(valid_cards, pseudoseed('dragonsDreamLucky' .. G.GAME.round_resets.ante))
if lucky_card then
card.ability.extra.luckyHand = lucky_card.base.value
end
valid_cards[lucky_card] = nil
local unlucky_card = pseudorandom_element(valid_cards, pseudoseed('dragonsDreamUnlucky' .. G.GAME.round_resets.ante))
if unlucky_card then
card.ability.extra.unluckyHand = unlucky_card.base.value
end
end
where is main.lua
You should check for if G.STATE == G.STATES.RUN then for that entire set_ability code
I think I know where I messed up. I put the main. lua inside of Sunny.lua
move it out
And make sure you have fallbacks set
Already done.
I was mainly just doing it so that I could have some random preview text if I go into collections and view the joker
i figured if there was some generic deck table I could pull from I would just use that instead
can you check if other jokers do not trigger like how you can check if cards dont score?
There is not unfortunately. You just need to set some static fallbacks
what is in the smods folder there
unfortunate
Yes.
how?
if not G.STATE == G.STATES.RUN then return nil end feels a bit cleaner 
Fair nuff
nested ifs just kinda get under my skin sometimes
Also fair lol
wait im dumb that would just be if G.STATE ~= G.STATES.RUN then return nil end
Oop yep
I was told to put the smods folder into the mod, it has helped. Before I was told that, smods would have a red line under it.
You do not put it in the mod folder, you put it in the workspace.
Also the line was yellow.
My bad. Also, when I took it out of the mod, the yellow underlined came back.
Does it matter if it stays like that?
No.
anyone knows how to make partners for the partner mod?
Try looking at the mod and other mods for reference.
all mods i can find with partner compat are either not updated or not even out. or i'm just blind
Try looking at partner itself then.
tried, it either didn't do anything or crashed
like i'll give it another shot but still
I rewrote the code for that Joker I mentioned yesterday and XMult scaling works now for some reason.
I don't know how to change the card (like Idol) at the end of the round. I looked in the example Castle 2 code and I do not understand when reset_game_globals is called
It is called when the round ends.
Thanks, got it
Does anyone know why the infoqueue is empty?
The description of the cards themselves is fine btw
Wait,
If it's called at the end of round, then why "print(Resetting card)" does not appear in console when I have this Joker?
you're missing commas
regardless, its a bit odd that it isnt crashing and instead leaving it blank
If you're talking about here, then no, that definitely isn't the problem
Since descriptions on cards themselves work just fine. Commas on last lines aren't needed or smth like that
are you allowed to define custom sets like that and not use the prefix
If they are cards why don't you link to their center?
Names are showing correctly so I think yes
and the names aren't defined anywhere else?
Nope
hmm
That works, still kinda curious why it only showed names when I tried doing it the other way tho
ok, now I know what reset game globals does but why doesn't it trigger at the end of round, there is no debug message in the console
I don't understand how the Castle 2 is coded. In VanillaRemade, there is a reset game globals function that triggers several other change suit/rank functions, but here it just triggers 1 block of code? But when I try to do the same thing Castle 2 did but with my Joker it doesn't work?
Are you having any problems? Feel free to leave a comment in the API thread.🥺
i fixed it and it was a load order issue
both of our mods had -10 priority
OK☺️
how do i check if the card pack being opened is a standard pack (the one that gives playing cards)?
What was the proper way to pass values from a calculate's return function back to the return from a SMODS.calculate_context call?
is it possible to use malverk to replace the whole sheet
self.ability.set == "Booster" and self.ability.name:find('Standard')
that from the game source
whenever base game used self it had to be changed to card right?
you wanna make a custom context right?
How would I have a Joker retrigger itself a certain amount of times?
you have the retrigger joker optional feature?
retrigger joker optional?
yeah, it's not enabled by default
that's how you enable it
just put it into your main file
specifically one that can change specific values. I have it in Kino already but I've not properly documented how I did it and don't remember which functions and hooks cascade into each other, there, haha
what does that do
enables two things: the ability for jokers to be retriggered and unscored cards being a separate cardarea (you dont need the latter)
it is enabled now
next i think you wanna check 'context.retrigger_joker_check and context.other_card == card'
ok
oh and dont forget 'not context.retrigger_joker'
or it's just gonna retrigger itself over and over
o
like return { repetitions = 1 } repeats it once?
yeah
np
You don’t need the latter either, it doesn’t do anything
No the unscored area
a
Unscored isn’t an optional feature
was Ace id 1 or 14?
14
ok thanks
like this unscored?
Yes
aight

context.cardarea.cards ends up as nil if I play these 4 cards... because of the unscoring cards?
(3) Lua global 'ReverseTable' at file 'togastuff.lua:513' (from mod with id TOGAPack)
Local variables:
t = nil
rt = table: 0x1e87daf8 {}
(*temporary) = number: 7.17034e-164
(*temporary) = table: 0x1e122f18 {click_offset:table: 0x1e1232e8, ignore_base_shader:table: 0x1de20530, children:table: 0x1e3cea38, ambient_tilt:0.2, parent:table: 0x1e6fb330 (more...)}
(*temporary) = table: 0x1dcb70a8 {poker_hands:table: 0x1e0fc6a0, cardarea:unscored, scoring_name:Pair, scoring_hand:table: 0x1e0f69d8, full_hand:table: 0x1e5ba9d8, main_scoring:true (more...)}
(*temporary) = table: 0x1e0c5f60 {1:1}
(*temporary) = number: 2
(*temporary) = number: 1
(*temporary) = string: "attempt to get length of local 't' (a nil value)"
(4) Lua field 'preprocess' at file 'togastuff.lua:526' (from mod with id TOGAPack)
Local variables:
cards = nil
context = table: 0x1dcb70a8 {poker_hands:table: 0x1e0fc6a0, cardarea:unscored, scoring_name:Pair, scoring_hand:table: 0x1e0f69d8, full_hand:table: 0x1e5ba9d8, main_scoring:true (more...)}
output = nil
(5) Lua upvalue 'calcmainscoreref' at Steamodded file 'src/utils.lua:1807'
Local variables:
context = table: 0x1dcb70a8 {poker_hands:table: 0x1e0fc6a0, cardarea:unscored, scoring_name:Pair, scoring_hand:table: 0x1e0f69d8, full_hand:table: 0x1e5ba9d8, main_scoring:true (more...)}
scoring_hand = table: 0x1e0f69d8 {1:table: 0x1e7b3d90, 2:table: 0x1dd74188}
(6) Lua field 'calculate_main_scoring' at file 'togastuff.lua:539' (from mod with id TOGAPack)
Local variables:
context = table: 0x1dcb70a8 {poker_hands:table: 0x1e0fc6a0, cardarea:unscored, scoring_name:Pair, scoring_hand:table: 0x1e0f69d8, full_hand:table: 0x1e5ba9d8, main_scoring:true (more...)}
scoring_hand = table: 0x1e0f69d8 {1:table: 0x1e7b3d90, 2:table: 0x1dd74188}
The context you use doesn't have cards in it
Well, the original function doesn't seem to be checking explicitly for it, no?
you can't blanket use context.cardarea.cards in any context
Well, as I am patching such anyway...
function SMODS.calculate_main_scoring(context, scoring_hand)
local curcards = togabalatro.preprocess(context.cardarea.cards, context)
for _, card in ipairs(curcards) do
...do I toss a check in here then?
i think i have a problem with my consumable key, anyone can help me ?
I mean I have no idea what your functions do, but I'd just pass the context to your preprocess function and do any checks necessary in there
it'd keep this hook cleaner
yeah so do all your checks in there
what does collection_rows mean here?
Which exact ones? For specific context.cardareas?
Card display in collection, 4 cards at the top, 5 at the bottom
o
is there a way to determine the winning hand? i was going to make a joker that applied a purple seal to each card in the winning hand
So I want a consumable that's usable on a select few different Jokers
How would I go about making sure it can't be used unless the selected joker is one of those jokers
In can_use, iirc, return true if cards in G.jokers.highlighted ('tis a table) match the keys.
so I'd just pass the context, and then the first line would be something like local cards = context.cardarea and context.cardarea.cards or nil
thank uu
...so this-
togabalatro.preprocess = function(context)
local output = context.cardarea and context.cardarea.cards or nil
if not output then return end
...
end
-would lead into me doing-
function SMODS.calculate_main_scoring(context, scoring_hand)
local curcards = togabalatro.preprocess(context)
if not curcards then return end
for _, card in ipairs(curcards) do
Which doesn't really let the "backwards" scoring occur after the initial "forwards" one.
If I do this, however, it works.
togabalatro.preprocess = function(context)
local output = context.cardarea and context.cardarea.cards or nil
if not output then
if context.cardarea == G.play then output = context.full_hand
elseif context.cardarea == G.hand then output = G.hand.cards
elseif context.cardarea == 'unscored' then output = context.full_hand end
end
if not output then return end
there should never be a context.cardarea == 'unscored' anyway
...so that's saying that my checks are fine? 'cause this basically more or less (I hope--) fixed why I was on the goose chase yesterday for a good while through the entire day.
how to do i create a bunch of playing cards from a table?
well unless you're doing other stuff or are on a very old smods build, this cardarea should never be unscored in this function
cards variable is no longer existent, anyway.
how could i make a joker apply a boss blind effect on the start of the round?
how do i return something multiple times?
{ extra = { xmult = ..., extra = { xmult = ... } } }
card.ability.extra.shots can scale infinitely. would that still work here?
You'd probably want to do a recursive table prep, which you then return.
whats the difference between a recursive table and a loop with multiple SMODS.calculate_effect? 🤔
I'm so confused
what is your smods version
should i even bother adding joker display support?
key = 'Jokers', --joker key
atlas = 'Jokers', --atlas' key
rarity = 4, --rarity: 1 = Common, 2 = Uncommon, 3 = Rare, 4 = Legendary
soul_pos = { x = 1, y = 0 },
cost = 5, --cost
unlocked = true, --where it is unlocked or not: if true,
discovered = true, --whether or not it starts discovered
blueprint_compat = true, --can it be blueprinted/brainstormed/other
eternal_compat = false, --can it be eternal
perishable_compat = false, --can it be perishable
pos = {x = 0, y = 0}, --position in atlas, starts at 0, scales by the atlas' card size (px and py): {x = 1, y = 0} would mean the sprite is 71 pixels to the right
config = { extra = { mult = 4 }, },
loc_vars = function(self, info_queue, card)
return { vars = { card.ability.extra.mult } }
end,
calculate = function(self, card, context)
if context.joker_main then
return {
mult = card.ability.extra.mult
}
end
end
}
SMODS.Joker{
key = 'Jokers', --joker key
loc_txt = { -- local text
name = 'Sequel the Sequel',
text = {
'When Blind is selected,',
'create a {C:attention}Joker{}',
'{X:mult,C:white}X#1#{} Mult',
'Gain {C:money}123${} at end of round'
},
--[[unlock = {
'Be {C:legendary}cool{}',
}]]
},
atlas = 'Jokers', --atlas' key
rarity = 4, --rarity: 1 = Common, 2 = Uncommon, 3 = Rare, 4 = Legendary
cost = 5, --cost
unlocked = true, --where it is unlocked or not: if true,
discovered = true, --whether or not it starts discovered
blueprint_compat = true, --can it be blueprinted/brainstormed/other
eternal_compat = false, --can it be eternal
perishable_compat = false, --can it be perishable
pos = {x = 0, y = 1}, --position in atlas, starts at 0, scales by the atlas' card size (px and py): {x = 1, y = 0} would mean the sprite is 71 pixels to the right
config = {
extra = {
Xmult = 4 --configurable value
}
},
loc_vars = function(self,info_queue,center)
info_queue[#info_queue+1] = G.P_CENTERS.j_joker --adds "Joker"'s description next to this card's description
return {vars = {center.ability.extra.Xmult}} --#1# is replaced with card.ability.extra.Xmult
end,
check_for_unlock = function(self, args)
if args.type == 'derek_loves_you' then --not a real type, just a joke
unlock_card(self)
end
unlock_card(self) --unlocks the card if it isnt unlocked
end,
calculate = function(self,card,context)
if context.joker_main then
return {
card = card,
Xmult_mod = card.ability.extra.Xmult,
message = 'X' .. card.ability.extra.Xmult,
colour = G.C.MULT
}
end
if context.setting_blind then
local new_card = create_card('Joker', G.jokers, nil,nil,nil,nil,'j_joker')
new_card:add_to_deck()
G.jokers:emplace(new_card)
end
end,
in_pool = function(self,wawa,wawa2)
--whether or not this card is in the pool, return true if it is, return false if its not
return true
end,
calc_dollar_bonus = function(self,card)
return 123
end,
}
Hi guys ! got a problem, my second joker wont spawn...
update smods
oki
between the legendary and the m, it should be an exodia joker