#💻・modding-dev
1 messages · Page 153 of 1
it does python interface stuff
I'll look into it
how do i do.. 2 dialog????
you'll probably have to modify it to be able to have it fetch the data you want
considering it was initially made for tasing and whatnot
wdym "2 dialog"?
so 2 different messages?
yes
im having the same issue myself
2 dialogs is too powerful
doesn't the tutorial do that? maybe check the code for that
what if i un dialog the dialog then dialog
...oh yeah, I was meant to ask about the other "effects" for text besides C:, s: and such.
key = "Jinzo",
loc_txt = {
name = 'Jinzo',
text = {
'Binds, and their effects',
'during the round, cannot be activated.',
'Negate all binds on the board.'
},
},
config = { xchips = 2.5 },
rarity = 1,
pos = { x = 6, y = 0 },
atlas = "TCGyugioh",
cost = 5,
unlocked = true,
discovered = true,
pools = { TCG_Yugioh = true },
blueprint_compat = true,
calculate = function(self, card, from_debuff)
if G.GAME.blind and ((not G.GAME.blind.disabled) and (G.GAME.blind:get_type() == 'Boss')) then
G.GAME.blind:disable()
end
end,
})
so I should use calculate for the disable blind function?
I tried adding this card_eval_status_text(context.blueprint_card or self, 'extra', nil, nil, nil, {message = localize('ph_boss_disabled')})
because i wanted the message boss blind disabled to appear
but it's considered a nil value when I addd it
you should be able to just do return { message = ... } instead of all of that
(if you're unlucky you might need a card = card too but my assumption is you don't)
attempted to compare a number with nil?
that's the error
trying to make lucky cards guaranteed
obviously doing something wrong, I think variable access?
not really sure why it's upset tbh
calculate doesn't magically know what context you're looking for
where is the tutorial anyways?
the error
make sure you're checking the right context (use https://github.com/Steamodded/smods/wiki/calculate_functions if you have no idea wtf I'm talking about)
seems to be spread out over button_callbacks.lua, common_events.lua and state_events.lua
use the return instead
return after the messages?
looks like this?
instead of the card_eval_status_text
Theoretically, yes. Though that context filter still seems a bit broad on first glance and might still crash with the same error
did crash with the same error
i want it to check when a card is played
and see if the card is lucky
then guarantee probabilities (set to 1)
pretty sure that exact context is documented in the link from earlier
like I said, too broad
oh okay
so how am I supposed to write it?
legitimately brand new sorry lol, me and a buddy "learned" lua last night by brute forcing custom jokers until 8am last night lol
return ({message = localize('jinzo_boss_disabled')})
G.GAME.blind:disable()```
like this because it returns an error that need } to close
great question actually
this joker might be a bit too advanced tbh
really? 😭
yeah, because instead of applying a new effect
i assumed the precedent already existed and I'm just doing it wrong no?
well kind of
i took code precedent from Oops all 6's
to modify probability
but the effect should apply the same way right?
and jokers like golden ticket check if a card is gold
so then you need to be real careful when you set-unset it
ngl I know it's a bad idea to use the global variable and I was just too lazy to find specifically the lucky modifier in the code
instead I'd take a look at how the lucky card is implemented and throw a check for your joker in there
lot less messy
basically all i want my code to do is:
Step 1 (golden ticket precedent): check if card is lucky
Step 2 (oops all 6's precedent): manipulate probability
just put it in the base code?
If I want the mod to be a separate file don't I have to do it locally?
yeah that's gonna error because you return and then still have statements
do you know what return does?
You'd either lovely patch your way in there or use a hook. Which is why I said this joker is probably a bit advanced right now
you're not adding +$4 (which can be done at basically any point, at any time) when gold cards are scored, you'd be modifying how lucky cards work internally
a really easy way would be to just give the lucky card bonus and let the lucky card roll anyway
I did a kind of similar joker with wheel of fortune where we just made the wheel basically impossible to hit and then separately applied the effects the wheel would be doing
is that the best way?
"too fast"?
interesting, how'd you do that? set the wheel's probability to 0?
well the probability in this game is a little hard to mess with
because everything is expressed as 1 / (value)
and then each odd in the game has (value)
yea
so wheel is expressed as 1 / (value) and (value) is 4
.extra yes
so while the joker is active we set value to like 2 billion
then when sold reset it
but i cant find the extra value for luckies lol
m_lucky = {max = 500, order = 9, name = "Lucky Card", set = "Enhanced", pos = {x=4,y=1}, effect = "Lucky Card", label = "Lucky Card", config = {mult=20, p_dollars = 20}},
they say this
yeah theoretically would work for luckies too (though it seems like a tad hacky approach)
super hacky
luckies don't have that (value) stored internally though
if G.GAME.blind and ((not G.GAME.blind.disabled) and (G.GAME.blind:get_type() == 'Boss')) then
return ({message = localize('jinzo_boss_disabled')})
end
G.GAME.blind:disable()
end,```
so this works but the disable blind doesn't work
but this crashes the game?
```calculate = function(self, card, from_debuff)
if G.GAME.blind and ((not G.GAME.blind.disabled) and (G.GAME.blind:get_type() == 'Boss')) then
return ({message = localize('jinzo_boss_disabled')})
G.GAME.blind:disable()
end
end,```
Swap the return and disable lines around (regarding your 2nd codeblock). You can't return then do stuff
If you really want to do this, you'll need to find where those values are actually stored (just search all files for "lucky") and either hook or lovely patch into those functions
for wheel I set the value to 2 billion because it's close to a 0% chance of triggering, and I needed to natively apply the effects of wheel rather than letting the wheel apply them itself at 100% chance to hit, because wheel effects don't stack and the point of the joker is that it can stack the editions. For this joker, the lucky triggers can stack as much as they want, so I figured it would be a lot easier to just set the probability to 1 so it always triggers natively instead of doing +20 mult and +20 dollars myself
this is how I handled the wheel
oh it stores it on the shiny joker? interesting
yeah
I found where luckies are handled
and there is no varibale to modify I think
just math built in to the function
so I'm not sure how I do it lol
like I said, hook or lovely patch the function
idk how to do those so I'm trying to see if there's som eroundabout way I can do it natively
but I'll learn if necessary lol
yeah the text just sorta comes in before u can even read it
wrong video
the correct one
[hooking](#⚙・modding-general message), lovely patching
ew discord lets you do that with links? cursed
lovely patching is maybe the most "native" way to do it?
🪄
shiny little guy
thank you
you can use delay = <number> to hold the message for longer - I suggest trying a delay of around ~1.5?
also do you just show up whenever I say the word "lovely patching"?
return ({delay = 1.5, message = localize('jinzo_boss_disabled')})
gonna assuming delay goes in with the message
yup
Do i need any imports or anything for lovely patching or if I have lovely I can just do that code in my mod file?
now the message doesn't appear and the disable blinds doesn't work?
but the game doesn't crash
You need a lovely.toml. Check out some other mods that use lovely to see some more examples
I'm so cooked
like I said, not really starter friendly
what's your current code looking like?
I had the channel open in the background
I mainly just show up when you're talking though
if G.GAME.blind and ((not G.GAME.blind.disabled) and (G.GAME.blind:get_type() == 'Boss')) then
G.GAME.blind:disable()
return ({delay = 1.5, message = localize('jinzo_boss_disabled')})
end
end,```
okay, so the easiest way I can interpret this is that I need two very simple injections, one that finds the lucky calculation in the mult function and replaces "probability/5" with "probability/1", and another that finds the lucky calculation in the money function and replaces "probability/15" with "probability/1"
and then it should work?
well I wouldn't replace it with probability/1 since then it'll always happen (even if you don't have the joker)
can't I just trigger those injections on "add_to_deck"
and revert them on "remove_from_deck"
then it's just a static guarantee while I have the joker
now the blind disable works but text doesn't appear?
no, those lovely injections either exist or don't
but i haven't change the code yet
oh you can't use them dynamically?
so then maybe I just make the luckies always fail and add the 20 mult and dollars myself?
hmm
but then theyre messed even when i dont have the joker
this code works for me 🤷♂️
I have a theory
sometimers the code works sometimes it doesn't
I do the above injections but instead of having them replace 5 and 15 with 1, I just implement my own random function, and my function checks whether or not you have this joker, and if you do it guarantees probability, and if you don't it uses 5 and 15 like normal
that's probably the best way to do it?
just used this to make a wee joker-sized joker and it fixed all my problems
it's a jank as hell solution but it's also really funny
whoops sorry for ping
okay so im editing a toml file
wonder if I could do the same thing with square/half joker
target is the file i need to change
pattern is the words i want to replace
position is where i want to inject
payload is the replacement text
that's all right?
I think so
here's a good example from smods itself:
[[patches]] [patches.pattern] target = "card.lua" pattern = ''' if center.name == "Wee Joker" and (center.discovered or self.bypass_discovery_center) then H = H*0.7 W = W*0.7 self.T.h = H self.T.w = W end ''' position = "after" payload = ''' if center.display_size and center.display_size.h and (center.discovered or self.bypass_discovery_center) then H = H*(center.display_size.h/95) self.T.h = H elseif center.pixel_size and center.pixel_size.h and (center.discovered or self.bypass_discovery_center) then H = H*(center.pixel_size.h/95) self.T.h = H end if center.display_size and center.display_size.w and (center.discovered or self.bypass_discovery_center) then W = W*(center.display_size.w/71) self.T.w = W elseif center.pixel_size and center.pixel_size.w and (center.discovered or self.bypass_discovery_center) then W = W*(center.pixel_size.w/71) self.T.w = W end ''' match_indent = true
yeah I took a file from the smods repo lol
just gonna edit it and use it as boilerplate
Yes target is card.lua
nice
It really isn't, it's just specifying where you want your code to be
i assume this refers to something specific in the repo
and has nothing to dowith my code?
i can just delete that right?
You need that
that's just what they were using in the smods file I downloaded
with a bit of luck, yeah
doesn't that just replace it at the position you evacuated?
what do these do sorry?
those [[]] tell lovely what type of patch it is
okay cool
and dump lua and priority
priority i assume doesnt matter for me if this is my only injection
so i can just make that 0?
I suggest setting it to 0
dump lua will put your code in the lovely dump under mods/lovely/dump
So you can see the result of your patches
oh sure
Priority does matter, your mod isn't the only one doing patches
Leaving it at 0 is fine tho
okay
And yeah, replacing code isn't a good idea, you might break other mods that try to target that part of the code
If you're not worried about that then go ahead
i am using vanilla balatro with smods and my custom jokers exclusively
is it fine for that?
If your mod is meant to be used without any others then you don't have to worry
also to look at the game's source I recommend looking at the lovely/dump instead of the extracted exe
Since the dump includes the patches steamodded does
Is it possible to take ownership of PokerHands?
do you see any problems with this or should this work?
emme_check will get +1 upon buyingthe joker
and -1 when it leaves
would anyone be willing to work on a little pet project of mine with me? I have a few ideas I'd like to implement into a QoL/Ideas mod but I'm unfamiliar with modding
lua has global?
It does not
that's what I thought lmao
that's a good start
do I just leave out local then?
yeah
defining the variable defaults to global?
Yeah the default is global
might be a good fit for #1210670452716994600?
Run your game and you'll find out, also look at the dump to see the results
I should start saying "run the code and find out" more often
Its just true
I haven't written the rest of the code for my joker yet lol
Also when comparing use ==, not =
And you might want to use multiline strings in your toml instead, aka """ instead of "
top level of your mod
either a lovely.toml file in your mod folder, or under your mod/lovely/whatever.toml
okay that one was actually just me being a dumbass ngl
^
this is also on the readme btw https://github.com/ethangreen-dev/lovely-injector?tab=readme-ov-file#patch-files
Bumpin' this. I really don't wanna patch into eval_functions in smods but if I have to I can
did you.. try to take ownership?
ngl I have troubles with reading comprehension sometimes (dumb and autistic), and I wasn't exactly sure where it meant whenI read it
still not exactly sure
sometimes my brain just needs to see a thing and be like, "you mean right here? okay cool."
Lovely will load all toml files under mod/lovely
I haven't because I'm lost on what the syntax is, though now I think my brain is starting to work it out
Or a single toml file at mod/lovely.toml, mod here being your mod name
Examples are always good haha. And the lovely readme definitely isn't the easiest to understand
Mods/your mod/lovely/blahblahblah.toml
top level of your mod
Or Mods/your mod/lovely.toml
Balatro/Mods/Akrones-mod/lovely.toml or Balatro/Mods/Akrones-mod/lovely/<whatever>.toml
oh I just have lovely in my game files but I also need to put it in my mod specifically you mean?
Just pick one of these
Not both, only one
and does it need to be named anything specific? it's currently nmed lovely.toml
What's your mod folder here
So I'm trying to change how Four of a Kind works, is this all the evaluate function that I would be taking over be?
im in my mod folder
those are just all my different jokers and crap
right here then?
That's not your mod folder
Yes this is correct
oh you mean like
yeah okay I see
thank you
my specific mod
thoguht you meant my folder for mods
Yeah each folder in Balatro/Mods is a different mod
yeah gotcha
any reason you're trying to change 4oak instead of adding a new hand? 👀
Yes, here's the functionality I'm after
Yeah kinda
I know how I want to do it, I just wanna make sure I'm changing the right things
you will definitely have to patch/hook into whatever function decides what hand is played
maybe get_poker_hand_info, I think it's called
But I'm not sure
okay well the game is no longer crashing when I play a card however it didn't give me any mult
my suspicion is that it's not crashing because I deleted my old function that was a problem, and the injection just didn't work
To see if your injection worked look at the dump
should double check if there aren't any other places where the poker hand gets calculated, but this will probably be one of them (and if you're lucky the only one haha)
Mods/lovely/dump/card.lua
Then your pattern is wrong
okay yeah it did not modify
Then your pattern is not correct
pattern = """
function.....
"""
okay
Sweeeeeeet
What'd you modify?
niiice
this lol
cool idea for a joker
still didnt work :(
sadge
oh wait
i should probably use multiline for the payload too huh
my dumb ass
dang still didnt work
Could you send your entire toml file
yep
okay wait I think I fixed the insertion
now I need to fix the code I'm inserting
nice, good luck
also what you're trying to do does not need a lovely patch
could be done with a hook
Let me write an example
idk how to do that either lolol
this is te current problem
i think im an idiot and im missing really obvious syntax
That's even better. Let's go
remove the "end" above "else"
also this is what I meant by a hook
local get_chip_mult_ref = Card.get_chip_mult
function Card.get_chip_mult(self)
if Emme_check == 0 then
return get_chip_mult_ref(self)
elseif Emme_check == 1 then
-- your code
else
-- your code
end
end
oh i was redundant with the return
does this just intercept a function before it happens?
this is modifying the original function
first it stores a reference to the old function, to not lose it
then you redefine it, adding whatever code you need, and at some point you call the reference you saved to ensure that the original code remains there
and you can add that hook anywhere in your code, wherever you need it
yeah, doesn't hurt to learn how lovely patches work tho
you just gotta know in what scenario to use a hook or a lovely patch
in this case your patch is just wrapping around the original code, not adding anything between the original, so you can just use a hook
what was the function you said I could use instead of emmecheck?
i think my current problem is that emmecheck is redefining itself as 0 before it runs the mult function'
just a function to see if i own a joker
so in this case it's "
if SMODS.find_card(Emme) == True then...."
or how do I implement that
check https://github.com/Steamodded/smods/wiki/Utility for the docs on how to use that function
and do I include the single quotes with the key?
I had a mod idea, not really coding anything yet but I really like it, yet it hinges on one little thing:
Is there a way to check, for a joker, what deck you’re using?
i.e. my key is 'emme_joker'
SMODS.find_card('emme_joker')
SMODS.find_card('j_[your modprefix]_emme_joker')
pretty sure that's balatro saying "you ran out of memory"
yeah, but the check == false doesn't seem right
oh i assumed it returned a bool
The docs! The magical docs!
I think you just have to check if the table is empty or not
oh cool
ngl I do not know how to write that
would you mind showing me how to check that?
if it's a numbered array you can do #array to check it's length
(with numbered array I mean {[1] = "a", [2] = "text", etc})
array was an example name
ohhhh
right I learned this syntax earlier for cards in hand
if #SMODS.find_card('j_FRND_Emme_Joker') >= 1 then
like that?
seems reasonable to me
I pray man damn
okay sick ! how do you do that lol
G.GAME.selected_back should do it
i'll need you to elaborate if you dont mind
is it like, "if G.GAME.selected_back == red_deck then;" ?
i dunno the exact in game terms for each deck
just print it out and you should be able to see what you want to check
(I don't actually know from the top of my head)
im still a little confused
like are you saying to
ahem
create a joker and make it so the joker prints whatever G.GAME.selected_back is?
and then that tells me
sendDebugMessage(tprint(G.GAME.selected_back), "skybox")
though yeah you might want to put that in a joker's calculate
presumably that means I messed something up here
pretty sure this lovely patch isn't the thing giving you a memory error 🤔
also is skybox supposed to be whatever the mod's key is? or literally just whatever lol
the name of the logger, otherwise you get a default "default" or smth
you might need to explain it to me like im 5 lol
the difference between
INFO - [G] 2025-01-19 18:57:26 :: DEBUG :: Skybox :: Message
INFO - [G] 2025-01-19 18:57:26 :: DEBUG :: DefaultLogger :: Message
you misunderstand my misunderstanding, i mean explain EVERYTHING like im 5 😭
im admittedly not the best coder
you want me to explain this entire message?
yes please
this is all of the code in my mod
very small joker code in main.lua
and then the lovely patch
really not sure why it's having a memory error lol
G.GAME.selected_backis a Lua table (almost everything in lua is either a table, a string or a number)tprint()turns a table into a string, so instead of printingtable: 0x55e44c737da0(how could this possibly be the default Lua wtf went wrong in development), you get a nice{ key = value, etc }sendDebugMessageallows you to send a string to the console- the first argument was the table, aka the current deck
- the second argument is by what name it'll appear in console; it's just good practice to set this to your mod's name or similar
see https://github.com/Steamodded/smods/wiki/Logging and https://github.com/Steamodded/smods/wiki/Utility for some actual docs
🤷♂️
did you try restarting your computer yet?
Dumb question can we use the pop up box that lovely uses
When u click the game during the crash log
I got a funny idea
@gaunt thistle would be the one to ask about that 🙃
you can use love2d's dialog box for that. it's how the crash card works in Cryptid
it's a native window so it'll look identical
was gonna add this card
and whe u lost a boss blind
the pop up box would come up say youn lost ur soul crash the game
anyone know where the source code for the event manager is? i want to know why the hell its working so badly with eachother
if I want to do two patches do they need to share a folder or both be loose in the mods folder
alternatively I could also do two patches in one file right?
damn im gonna have to learn how to mod balatro
you absolutely should
you can have as many patches as you want in a file. splitting patches up into separate files is generally good for organization, but it's not a requirement
i made these a while ago and someone said i should mod them in
off the top of my head the bulk of it is in engine/event.lua
wait i dont have balatro on steam can i even do this 😭
How would I make a joker trigger when only when a certain card of the played hand is scored (e.g. first scored card, second scored card, etc.)
game boylatro
thanks!
is it possible to look at something like hanging chad and determine
Hello, I want to get started making mods for Balatro. Where would be a good place to start? Are there any guides I could follow?
nope, cant get any info on why it breaks
heyo everybody, I am starting to mod and I wonder, what is the resolution of the joker card?
71x95
thankies!
How do i create a texture pack through steammodded? I have textures but i don't understand what i should put in lua file
yes i need to know this too
Do Vouchers really have a calculate function?
Im thinking of turning a Joker I have into a voucher and if thats the case it'll be quite easy
newly added
21 Jan, I gotta update my version 😢
you can also access the voucher cardarea, G.vouchers
You think a multi based on how many cards u have in your hand would work?
high card moment
7
depends on the exact effect of the joker
I'm basically just slapping yugioh card effects into balatro with a balatro equvelant
so some cards probably gonna have better effects than others
each card held in hand gives +1000 chips
I wonder if it's possible to make cards spawn only during an endless run
because this sounds funny as fuck
ok but what if i have 5 hand size and want to play flush fives
kinda underpowered imo
I could do a 3rd of 1000
high card supremacy
maybe 333 per card?
so if u want it to be super broken gotta pare it with a card that repeats the effect
h*gh c*rd brainrot
slifer as a legendary that gives +1000 chips per card in hand seems aight
Would 1000 per card pretty much guarantee you win all 8 antes?
no because you need mult smh
what if you run into a seed whre you only have chips

If u paired this with Jinzo you'd pretty much win
Jinzo disables boss blinds
Not sure how to balance it then lol
other than being a endless only card
or a card with such a low change of spawning
you'd never really see it unless u got more luck than a full odds shiny pokemon
me when legendary is sitting right there
What is a legendary spawn rate?
hmmm
ok idea
a card where u have to destroy 5 joker cards
🤔
So you'd have to have 5 cards already bought and get lucky to get the summoning card to get slifer
if you're gonna get a broken card might as well have to put some effort into it
I also have the other two cards
so I could just combine it into a 1/3 dice roll card of what u get is what u get
with winged dragon of raw I can easily used sphere mode
Have to wait until you beat boss blind to Turn it into Ra and requires u to destroy 3 random jokers to get this card into ur joker zone
how does one lock a joker? like how the pair/trio/family/tribe require you to win a run without playing their respective hands
i looked at game.lua and found
unlock_condition = { type = "win_no_hand", extra = "TWT_polycule" },```
but they do not work
where did you find start_locked? that doesn't exist
it's unlocked = false
it's in game.lua
right here
what version of balatro would that be
according to what
that's not a version that exists
i would assume it has to be some 1.0.0 version though, 1.0.1f also doesn't have it
CFBundleVersionString the info.plist
got it from apple arcade+ since its easier to browse
that... makes more sense
i can't tell if you if it does anything there, but it doesn't exist on the steam version
and even then unlocked = false is the important part
yea figured that out
how do you then display the unlock message?
and/or set the condition if its custom
ooooh
define a check_for_unlock function on the joker
El gato
you should know that modding balatro is based almost exclusively around the steam version, so the arcade version can and will have issues
im not modding the arcade version
i just have a copy and its easier to browse the src
ty!
just be aware that you'll keep running into code differences like this
so far there havent been any issues with doing so aside from start_locked which we just discovered
Is there a way to lock back a card without having to change the key?
I guess the save data
what's the right way to copy a joker's ability? rn all im doing is softlocking the game without even copying anything 😭
im talking blueprint type behavior
https://discord.com/channels/1116389027176787968/1327494105168875592
The OP of that thread did something like that just recently with Mimic Joker
Might be able to read their code
can i separate my code into multiple lua files? because i see i need to name one main in a json file
and i dont know how to execute the other files
yes
-# it's in the docs
assert(SMODS.load_file('path/to/file.lua'))()
I thought assert wasn't necessary anymore
sure it's not "necessary", it just makes crash logs completely useless when you don't use it
made the old transparency method
Oh ok
half of pixels are rendered as of alpha blending isn't fast enough
i should specify, crash logs from failing to load the file
im sorry i may sound dumb but i put this line into my main file which is reference in the json?
yes
thanks
can seals access the before/after contexts? - wondering if it's possible to have a sealed card's effect take place after the hand in which it is played
Yes
currently can only get it to activate when it's scored, through 'calculate' obviously
with new calc
as in an update to smods?
im pretty behind with updates tbf
I think any version of new-calc
ok cheers, i'm on old-calc
should probably update and get used to the new quirks and such
just a github jobby?
it has lots of improvements
ok cool, will it be labeled 'new-calc' or is it just the most recent commit on the main smods repo?
most recent one will work
ok great thanks
i seem to remember a reason I switched to old-calc because something was bugged (annoyingly can't remember exactly what) so I assume that's fixed now
im looking at a code from another mod and he uses self.config.type == 'something' but that something is never used again / i cant find it, any thoughts?
which mod?
looks like placeholder/debug script they never removed?
unless it's actually in something used?
@violet void imagine me spending all night trying to figure how to activate the damn seal after the hand and coming up short, only to not have updated the c***. smh
how do I check for modded jokers?
what do you mean by "check"
local negative_joker_count = 0
for _, v in ipairs(G.jokers.cards) do
if v.edition and v.edition.key == 'e_negative' then
negative_joker_count = negative_joker_count + 1
end
end
here i check for negative jokers
I assume you mean ones you've created yourself? In which case you can use #find_joker('your joker's key') > 0 to check for that specific joker in the cardarea
yeah, I thought of that... But is there a "mod key"? or something like that?
wasnt it SMODS.find_card()?
relatable
you want to know a certain card's full key?
yeah you should use SMODS.find_card
find_joker uses names
I want to check for how many modded jokers are there. Preferably my jokers
v.config.center.mod gives you the mod object the joker belongs to, if any
(v.config.center.mod or {}).id would give you the corresponding mod ID if the mod exists
-# I'll leave this to the professionals
lmao
-# time to be unprofessional
shucks, i guess I'll replace my find_joker calls with find_card then
you might be under the impression that it works with keys, but that's because smods defaults names to keys for some reason i don't remember
holy shit I forgot about .json
i think it was 0.9.8 compat
it may be removed when 0.9.8 compat is, and it's inconsistent with how it works for vanilla jokers vs. modded
is the logic the ssame as find_joker? Like just pass as an argument the key I'm looking for @frosty dock
I can just omit the second arg most of the time
yeah it's a drop-in replacement for find_joker
ok epic thanks
second arg isn't needed unless you have a reason for looking for debuffed versions of the card
sorry is it a '==' check against the respective key instead, because I'm using #find_joker() > 0 atm to check if the table regarding that joker is not empty essentially
so if SMODS.find_card() == _my key_ then?
its the same youve been using the other
no it works exactly the same way
oh ok literally just pick up and replace the words find_joker
if #SMODS.find_card('j_mod_yourkey') > 0 then is one way to check
ok great thanks
I prefer if next(SMODS.find_card('j_mod_yourkey')) then personally but either works
yeah the > 0 feels a bit hacky
Ill use this now
that's more succinct, just a straight boolean to return
mostly because it always accurately reports if the table is non-empty instead of just checking numeric keys
it's not a bool, really it's just the "next element" of some sort
which means it's nil/falsy iff there is no element
unless you're dealing with a table of bools i guess, in which case you'd have to check ~= nil
oh it's a lua intrinsic
kinda wish lua considered empty tables falsy
i think lua should consider "0" falsy 😃
wouldnt next(emptytable) return falsy? (nil to be specific) @violet void
yes
the string 0....?
I mean simply typing if SMODS.find_card() then doesnt work and I wish it did

oh right, just a concision thing
this isn't js
"Gains {C:white,X:mult}2X multiplier",
Idk why this happens, but it does. With multiple jokers.
shouldnt you close the brackets
or sorry after the 2x if you want the multiplier out of it
it strips spaces too fyi
it happens here too... I see them braces
oh...
generally you only want the numerical text to be altered by the colours
so just enclose the number with the second brace pair
fyi there isn't really "closing" these and they don't work in pairs
{} just resets the modifiers to null
yh Ik
is there a tutorial on how i could make a new area like the consumeable area for example
no but multiple mods do it
do you know which ones
betmma mods has it but its just so complicated for me and i cant seem to get it working haha
reverie also has a custom area
at some point you just run out of space to not overlap which is kind of a problem
Gotta make an area that takes the whole screen 
trying to make this without errors like these
all the basic context checks are literally written out
just out this first
most of those are implied no?
the check at the top
oh doy
it set out as "here's a check you can use to get this context" and "heres what the context contains"
sooo.
for _, v in ipairs(G.jokers.cards or {}) do
if (v.config.center.mod or {}).id == 'phasmo_cards' then
modded_jokercount = modded_jokercount + 1
end
end
?
whats the variable for card value?
get_id() is correct for value
evaluate = function(parts, hand)
if next(parts._flush, parts._high_card) then
local fibaflush = true
local _flushed = SMODS.merge_lists(parts._flush, parts._high_card)
for j = 1, #_flushed do
local rank = SMODS.Ranks[_flushed[j].base.value]
fibaflush = _flushed and (rank.key == 'A' or rank.key == '2' or rank.key == '3' or rank.key == '5' or rank.key == '8')
end
if fibaflush then return {_flushed} end
end
end,
trying to make a custom hand that checks for an ace, 2, 3, 5, 8 flush but obviously as you see here the code doesnt work because you only need two of the 5 cards to make the hand activate
how would i make it check if all the cards are present in the scored hand 
yeah looks good
the card is not triggering now
show code now
xmult = card.ability.extra.Xmult and remove the message parts
return {
xmult = card.ability.extra.Xmult
}```
does that pop up the X3 on screen?
yes
(Shoutout for allowing xmult btw ❤️ )
ah the silly quirks of old calc
how do i update?
unless you know anything about git, just delete the smods folder you have and redownload ^
do i replace the lua?
i already downloaded the most recent but the lua inside my git mod didn't change
because of course it didnt thats not how computers work
alright it completely works now
that's not steamodded
that's what you replace
where can you find the uhh
things for poker hands in the game files
-# like the things that define what cards they need
the functions used here (get_X_same, get_flush, get_straight, get_highest)
get_straight is overridden by smods
welp is not working lmao
SMODS.Joker {
key = 'revenant_jk',
atlas = 'Jokers',
loc_txt = {
name = "Revenant",
text = {
"Gains {X:mult,C:white}#2#X{} for",
"each {C:purple}modded joker{}",
"in your hand.",
"{C:inactive}(Currently: #1#{})"
}
},
loc_vars = function(self, info_queue, card)
return { vars = { card.ability.extra.Xmult, card.ability.extra.Xmult_mod } }
end,
config = { extra = { Xmult = 0, Xmult_mod = 3 } },
rarity = 2,
pos = { x = 7, y = 0 },
cost = 5,
calculate = function(self, card, context)
if context.joker_main then
local modded_jokercount = 0
for _, v in ipairs(G.jokers.cards or {}) do
if (v.config.center.mod or {}).id == 'phasmo_cards' then
modded_jokercount = modded_jokercount + 1
end
end
return {
Xmult = modded_jokercount * card.ability.extra.Xmult_mod
}
end
end
}
```if u want to take a look at the whole code
what smods version?
what does get_X_same do 😭
gets tuples of X cards of the same rank, at least that's the base game version
the smods patched version gets X or more
i dont know how to make this calculate function
saturday?????
uhh
so if thats too weak let me know
i did this with an update function
+1 X1 for each Joker held?
you got me hold on
that seems excessive
?
there's no need to count jokers every frame
lmao 😭
realistically you only need to do it in calculation and loc_vars
i dont know how to do it at all though tbh
you need:
a count of all the jokers
a value to times by that count
the amount you get itself
i think
well whats the easiest way to count jokers?
is there a way to just check how many jokers you have based on the joker slot counter?
#G.jokers.cards
for i = 1, #G.jokers.cards do
#G.jokers.cards
honestly i think this is a minor skill problem (/j)
-# says as im struggling to make a custom hand
well the main question that i have is mostly just
the location of the loop, and how to apply it to the Xmult variable
whatchu need
holy lobcorp
this thing
abomonation
😭
thats it
price of silence
smh
can i just see abstract jokers code actually
idk where it is in the base game
vro was right
is there any docuentation for SMODS.ConsumeableType
thunk moment
Is there no way to scale a node tree?
if context.joker_main then
return {
Xmult = #G.jokers.cards
}
end
This will give you 1 Xmult per joker
How do I properly manage the nodes created by localize()? This is what I'm currently doing, but this doesn't seem like a right thing to do
calculate = function (self, card, context)
if context.joker_main and G.GAME.current_round.hands_left == 0 then
return{
mult_mod = card.ability.extra.mult,
message = localize{type = 'variable', key = 'a_mult', vars = {card.ability.extra.mult} }
}
elseif context.end_of_round then
if context.individual then
if not context.blueprint_card then
if card.ability.extra.c_rounds >= card.ability.extra.rounds then
card.ability.extra.mult = card.ability.extra.mult + card.ability.extra.mult_gain
return {
message = 'Yum!',
colour = G.C.MULT,
card = card
},
card.ability.extra.c_rounds == 0
else
card.ability.extra.c_rounds = card.ability.extra.c_rounds + 1
end
end
end
end
end
what's wrong with my calculate function? it's supposed to trigger the joker gaining 2 mult every 3 rounds (starts from 8), but instead it does it each round and the mult gain is like 10?? (went from 8 to 18) is it set up incorrectly? did i miss a line?
loc_vars = function (self, info_queue, card)
return{vars = {card.ability.extra.mult, card.ability.extra.mult_gain, card.ability.extra.rounds, card.ability.extra.c_rounds}}
end,```
forgot the loc vars
how to check if a card is a stone card?
Change the individual check to main_eval
is it actually that easy
Assuming the rest of your code is correct, yeah it’s just an incorrect context check
It’s hard to read on mobile, can you screenshot?
?
something akin to this, just not self
i think
there's probably a better way to check it
are there any guides or any way to learn how to make mods for balatro (steammodded) sorry if im asking a stupid question
check out example mods
https://github.com/Steamodded/examples/tree/master/Mods
Steamodded example mods. Contribute to Steamodded/examples development by creating an account on GitHub.
its a joker check so i dont think self works
Oh what smods version are you on?
or just look through the game files/other mods and see if it works
ok ty!
oldcalc
SMODS.has_enhancement(card, ‘m_stone’)
this then
Then update 🙃
or what eremel said
oh ok
No reason not to update
i mean the only reason i WAS on oldcalc was i think cryptid?? iirc
one reason not to update
a small price to pay for a functional mod,,,
Doing a public test for #1318248620125851749 message
it works thank you 🙏
does anybody know whats going on ?? im not too sure
What’s calc_scale_fac?
you cant put an if statement in a table
ohh alr
Hello, I'm trying to have a joker retrigger playing cards that have already retriggered, afaik I can't check if there has already been retriggers in context.repititions. I may need to patch a new context to game.lua? Not sure where tho.
maybe you could set a a tag on the card to true in context.repetitions and read that value later?
sell = {n=G.UIT.R, config={align = "tr"}, nodes={ {n=G.UIT.R, config={ref_table = card, align = "tr",padding = 0.1, r=5, minw = 0.3, minh = 0.3, hover = true, shadow = true, colour = G.C.UI.BACKGROUND_INACTIVE, one_press = true, button = 'sell_card', func = 'can_sell_card'}, nodes={ -- {n=G.UIT.B, config = {w=0.1,h=0.6}}, {n=G.UIT.C, config={align = "tm"}, nodes={ {n=G.UIT.R, config={align = "cm", maxw = 1.25}, nodes={ {n=G.UIT.T, config={text = localize('b_sell'),colour = G.C.UI.TEXT_LIGHT, scale = 0.3, shadow = true}} }}, {n=G.UIT.R, config={align = "cm"}, nodes={ {n=G.UIT.T, config={text = localize('$'),colour = G.C.WHITE, scale = 0.3, shadow = true}}, {n=G.UIT.T, config={ref_table = card, ref_value = 'sell_cost_label',colour = G.C.WHITE, scale = 0.3, shadow = true}} }} }} }}, }}
this is the code for a sell button on a consumeable
can someone tell me how i can move it a bit to the left?
something like
if context.repetitions then card.ability.extra.retriggered = true end if context.cardarea == G.jokers and context.joker_main and card.ability.extra.retriggered then [retrigger card] end
like, move it behind the card?
ohh
looking at the shadow you would probably have to move the beer down rather than move the sell button up
is the hitbox of the card the entire square?
then you probably could just move the sprite down in your atlas so that the beer covers the sell button
you mean leave space at the top of the beer eg. make it smaller?
instead of leaving space at the bottom leave space at the top
yea smart but the problem is that the sell button is like directly above the use button
its a bad screenshot so you cant see
but its directly behind the beer
ohhh
the newest one
Just wanted to ask again if its possible to increase the chances of another joker being found in shop
Like gros michael and Cavendish but idk if gros Michael actually makes cavendish more common or just makes it avaliable
Cavendish will be available in the pool of possible Jokers to appear if Gros is eaten.
BEER
I see
then I'm afraid "does not work" isn't an accurate enough description of your problem
Surely I'm not the first person to attempt this right?
I hope I'm not 😭
You'd have to patch in to the get_current_pool function I think
line 1963 in common_events.lua
I fixed it thanks
jokers are not weighted within their respective rarity pools
What if i gave the joker a special rarity and manipulated that instead?
that is possible
Is this effect enough for a Legendary-like?
Also, is this wording OK?
Like accelerate instead of velocity
yeah i get it, you want quadratic scaling
And I'm asking if there's better wording because I was like 84% sure it is confusing before posting the ask.
thank god u wasn't 85%
Probably add a "per"
Gain mult per mult gained
Slightly less confusing
Or of
Gain mult% of mult gained
nah ur making it more confusing
Well im stumped
im rooted
im trunked
hey Mr. Johohon smods
the real john from smods
Maybe "Mult gained next hand increased by X0.25"?
jhon
is there a git page talking about message?
message = localize { type = 'variable', key = 'a_chips_minus', vars = { card.ability.extra.chip_loss } },
like this?
isn't that auto supported
I want to know the keys
like iirc you can just return { chips = -10 }
gain 0.25x mult when a hand with no face cards is played
increase scales with consecutive increases (resets)
will give 0.75x mult next hand
maybe?
i guess there's stuff like ice cream
where you really just want the message
in which case that does look correct
The joker I was working on triggers 3x mult on every modded joker, but It just returns the total, I wanted to "count" on screen before that
cuz is prettier 
sounds like a use for context.other_joker
I'd advise you also score the xmult at that time though, additive xmult per thing is confusing when done like this
change to context.other_joker instead joker main?
How about this?
(This is, in some way, inspired by Ride the Bus)
then context.other_joker is the other joker you use to check if it's modded rather than checking for all jokers
i think this is understandable yeah
so this is a scaling scaling joker but it doesn't reset the scaling on failure, it resets the scaling scaling on failure?
scaling is a weird word
Wait, hold on
here's something wacky
Each hand, this joker gains X0.25 Mult per consecutive hand played with at least one scoring face card
-# maybe that's too dense to not be confusing
maybe
well it resets the scaling instead of the value
the scaling scaling is constant
OK, playing a hand with no scoring face card resets the mult you gain each hand (to zero).
I'd say the scaling scaling scaling is constant (0.25)
it's just derivatives all the way down
0.25 is the second derivative.
exactly
I consider the:
- value to be the mult given
- scaling to be the amount the value gains (constant for something like bus unless resets), i.e. first derivative
- scaling scaling to be the amount scaling gains, i.e. the sceond derivative
but you said scaling thrice
i guess if you consider scaling to be the mult given, what you said makes sense
For reference, here's my code
me when I Xmult_mod_mod_mod
Because return {message=} method is too tailored to normal circumstances.
i don't see how that doesn't work here
For example, returning Xmult value overwrites my desired message colour to G.C.MULT.
you can put a colour in your return...
An upgrade function I can call inside the calculate function.
yeah okay so then a return should work fine?
...And still get overwrote to red? No thanks, I've tried that.
I had spent a whole afternoon trying to solve that problem, and card_eval_status_text is the first reliable solution I found.
hold on lemme test that then
I'd be very glad if it was just caused by me having not updated my smods.
I don't think it's that 😬
wait you're doing an Xmult return?
if you do a message return, colour works normally
for Xmult, it needs to be in xmult_message
The problem only happened when message, Xmult, and colour are returned in one braket.
I mean smods shouldn't get a final say on the colour?
it doesn't
this is just card_eval_status_text being passed x_mult type, this is easily overridden with xmult_message
it's just that normal colour only works for a normal message
so what, balatro itself isn't allowing it?
if you had both an Xmult and a different message, would you want to only be able to set the colour for both at the same time??
Oh, by the way, card_eval_status_text also allow me to display message when no return is required.
When I need to do calculation after message is shown.
Wait, lemme find the code that had bugged me into start using card_eval_status_text
why is the last card allegedly being calculated twice? i must've goofed up big time somehow
I feel like I'm being stupid, this is supposed to work right?
return {
xmult = 2,
xmult_message = "test"
}
ah
the docs need to be more precise on this
the docs still say
Use
chip_message = 'text'to change the text (this maintains default timings)
but yeah the table works
@wintry solar huh
I'm assuming your context check is too broad? you should be able to just print the context out to see what's happening
was that ever accurate?
everything looks good so far