#💻・modding-dev
1 messages · Page 143 of 1
everything works currently except for the money decrease variable
It shows up as nil in the card description and afaik doesn't reduce the money gained
smods version?
should be newest
lemme check
i for sure got it after old calc was replaced
unless there was an important update within the last 1.5 weeks i dont think its a problem
okay, I know about table.insert(info_queue, but how do I, like, make the thing that's in the queue just a block of text rather than something else's definition?
you can put a description in the Other set and just put something like { set = 'Other', key = 'whatever' } into info_queue
yeah i downloaded it on the 10th and that was from the latest release thing in the download guide
so should be pretty new
is there a smods example joker for ice cream or popcorn or something like thay
yeah no that's not new enough
damn
I added what I'm using here like 2 or 3 days ago
you gotta download using the code button on github
I used this
and semi good news
its working
but only 1 card is getting destroyed
from 3 copies of the guy
well yeah
does anyone have any input?
they'll destroy the same thing because the destruction is done after calculation
add a will_destroy flag to the card and check that before setting highest
if context.cardarea == G.hand and context.destroy_card then
local highest = nil
for _,v in ipairs(G.hand.cards) do
if (not highest or v:get_id() > highest:get_id()) and not v.will_destroy then highest = v end
end
if context.destroy_card == highest then highest.will_destroy = true return { remove = true } end
end
like so
new problem
huuh
copied your code exactly
i just need one that works
if context.cardarea == G.hand and context.destroy_card and not card.ability.extra.has_destroyed_this_hand then
local highest = nil
for _,v in ipairs(G.hand.cards) do
if (not highest or v:get_id() > highest:get_id()) and not v.will_destroy then highest = v end
end
if context.destroy_card == highest then highest.will_destroy = true card.ability.extra.has_destroyed_this_hand = true return { remove = true } end
elseif context.joker_main then card.ability.extra.has_destroyed_this_hand = false
end
try that
oh yeah
extra is not automatically created uh
if context.cardarea == G.hand and context.destroy_card and not card.ability.has_destroyed_this_hand then
local highest = nil
for _,v in ipairs(G.hand.cards) do
if (not highest or v:get_id() > highest:get_id()) and not v.will_destroy then highest = v end
end
if context.destroy_card == highest then highest.will_destroy = true card.ability.has_destroyed_this_hand = true return { remove = true } end
elseif context.joker_main then card.ability.has_destroyed_this_hand = false
end
just remove the 'extra's?
yea
Decided to use an exe patcher instead.🙄 At least it works.🔥 👌
no you have to edit the love2d assembly wdym
us balatro modders always have ida open on our second monitor!
lovely 0.7.0 is lovely enough to be able to patch into love files though?
Video's broken, hang on a sec. (Worked on a test server.)
lovely enough indeed
no separate tool needed amirite
it's the moral choice
can you support patching the c++ code and recompiling love2d at runtime?
no
it'd be very easy of course..
so true
c++ uses postfix increment so it evaluates to the same thing as c
c++ is a total lie
all it does is increment c by 1 and doesn't tell you
when discord is shut down this is how we'll communicate
no we'll use debugplus
TRUE
communicating by mail
what does juice_up do?
hop on tk debug console
when discord and debugplus are shut down this is how we'll communicate
or worse steamodded discussions
imagine not using imgui for a modding tool
It should play now (it's a sound mod, btw.).
smh my head
I imagine this wouldn't be too hard to make using lovely
?
is this real...
Tried Smods.sound, but "ambientFire" works differently.
nevermind, i'm dumb lmfao
no you're not
well thank you
https://love2d.org/wiki/cimgui-love okay this one is probably better but still
Posted to script a few times if you want to try it.
ignoring the brainstorm trigger, how do i potentially get these messages to play the same time as the card destruction
mmm this is better https://forum.cockos.com/showthread.php?t=250419
ReaImGui: ReaScript binding for Dear ImGui ReaScript, JSFX, REAPER Plug-in Extensions, Developer Forum
code for reference
actually this is better https://love2d.org/wiki/love.graphics
i feel it
pushes poker deck off table
hang on hang on hang on here buddy
balatro doesn't have p*ker c*rds, it has playing cards
why is cards censored
because they were p*ker c*ards
why is it not recommended to use mp3 files for sounds?
i think audio quality
how do i make a lovely file with no patches as a placeholder
is there a way to loop the music while you are in the pack and then turn the music back off once you make your selection?
SMODS.Booster({
key = 'LTMBooster1',
atlas = 'Jokers',
pos = { x = 3, y = 8 },
loc_txt = {
name = 'LTM Pack',
text = {
'Choose {C:attention}#1#{} of up to',
'{C:attention}#2#{} {C:purple}LTM{} cards to',
'be used immediately'
}
},
config = { extra = 3, choose = 1 },
weight = 1,
cost = 4,
group_key = 'LTMConsumableType',
draw_hand = true,
unlocked = true,
discovered = true,
create_card = function(self, card)
return create_card("LTMConsumableType", G.pack_cards, nil, nil, true, true, nil, "fn_LTMConsumableType")
end,
ease_background_colour = function(self)
ease_colour(G.C.DYN_UI.MAIN, G.C.SET.LTMConsumableType)
ease_background_colour({ new_colour = G.C.SET.LTMConsumableType, special_colour = G.C.BLACK, contrast = 2 })
play_sound("fn_pack")
end,
loc_vars = function(self, info_queue, card)
return { vars = { card.config.center.config.choose, card.ability.extra } }
end,
})
what's the reason?
you can just define a patch that targets something that doesn't exist
because im gonna have patches, but not right not
yeah just create a patch with an empty payload that targets something silly like "butt.lua"
no end to close the if context.discard then
what
TWITTER: https://twitter.com/LukeCorreiaVA
PATREON: https://www.patreon.com/LukeCorreia
KO-FI: https://ko-fi.com/lukecorreiava
MUSIC:
an avengers midi that i found
i cannot load balatro
Anyone aware of how to add a new suit to the game without adding it to every deck?
The wiki gives a guide to adding suits, which works, but every deck also gets the new suit as well.
this doesn't futureproof the balatro intercourse update though
dont threaten me i have all the mechanics planned out already
(this isnt a joke i have a google doc named balatro sex update)
bumping this, atm in my mod you can discard & play cards while the transformation animation plays which is weird
is there any way to make an added card guaranteed to have an enhancement
yeah
poll_enhancement
where do i put that
around the spot where you add the seal
value:set_ability(G.P_CENTERS[SMODS.poll_enhancement({guaranteed = true, type_key = 'randomnumbergenerator'})], true, false)
replace value with whatever you use to reference the added card
the type_key field is used for the seed to randomly generate an enhancement
so like this?
yeah that should work
also you can do the same thing for the seal
to get a random seal
and edition?
yeah and edition
does edition include negative
it can if you want it to
you can specify what editions it chooses from
and toggle if negative is available
yeah i want it to
value:set_seal(SMODS.poll_seal({guaranteed = true, type_key = 'randomnumbergenerator'}), true, false)
for seal
card:set_edition(poll_edition("randomseed", nil, true, true, {"e_foil", "e_holo","e_polychrome"}))
this edition poll does foil/holo/polychrome and has no negative
i cant remember if its the first or second true that toggles no_neg, but the last argument is an optional argument containing a table with every edition you wanna choose from
it didnt add an enhancement to the card huh
well why not
is G.C.SECONDARY_SET.Enhanced the problem
lets see
oh hey it worked
it deposited a stone card
though if its supposed to give "3 Jacks" i probably should remove stone from the pool
because yeah its TECHNICALLY still a jack underneath but like
i don't know how to do that
when my poll enhancement makes a stone card I just
reroll it until it stops being a stone card
while value.config.center_key == "m_stone" do
value:set_ability(G.P_CENTERS[SMODS.poll_enhancement({guaranteed = true, type_key = 'randomseed'})], true, false)
end
if you wanna do my botched method here you go
the indents are off because discord but yk how it works
oki
oh yeah for this are the chances for each how you'd expect them to be
like would polychrome be still rare
yeah it uses the vanilla weights
ok cool
you can specify your own weights if you want to
ok its still not
working
it either adds only the edition and seal or only the enhancement
wait i have an idea
it seems poll_enhancement has an options list like poll_edition
i just need to figure out what the names of the enhancements are
banger
oh you know it's good when the error screen is this blue
i figured out how to make 3 of them as well damnnn we are on a roll
epic for i = 0, 2, 1 do moment
if you want to check for enhancements you should use SMODS.has_enhancement
although in your case you should probably use SMODS.has_no_rank so it will also catch modded enhancements that remove a card's rank (like ortalab's ore cards)
the issue here is that it starts as base
if you use a repeat…until loop it should work
i uh.. don't know how i'd go about that
i only just figured out how to even add cards not that long ago ,,
does lovely have a problem playing too many sounds at once? sometimes my custom sounds arent playing, and sometimes while i have a custom sound playing cards i select dont make any noise
how would one destroy a joker? like how jokers such as popcorn are destroyed
copy the code lul
yknow what fair
👍
How do I make it so a joker does not appear in the shop
in_pool
yo fellas, quick question
this code creates two jokers, i only want it to make one
i stole this from riff raff and cant figure out how to make it be just one
change for loop bounds
oh?
jokers to create needs to be 1 but only if there is space
I TOLD YOU IT WAS THE LOOP
yeah, that's the plan anyway
tbh you could get rid of the foor loop and just make it check if theres space
yup
would that just be 'if G.GAME.Joker_buffer < 1 then'
how do you check if there's space?
like what are the peramaters on the if statement
(Yes I read the FAQ.)
Baby modder with a dumb question, what extension should I be using? Do I just use the LUA one?
(Thank you.)
#G.jokers.cards < #G.jokers.card_limit
no its G.jokers.config.card_limit
and you should still respect G.GAME.joker_buffer if you're using an event to spawn the cards, since that's the amount of "reserved" space in the jokers slots
that along with the joker buffer
show code
context needs to be more specific
context.discard might be happening twice
right
i thought the calculate function was in the loc_vars for a sec you gotta clean up that indenting
i think you want context.pre_discard
yeah hes stupid
OK LOOK
you should've seen the like
spreadsheet for the mod
no capitalization
no punctalization
THIS ENTIRE PROCESS IS JUST EDUCATED GUESSING OK
it was a mad house
youre uneducated guessing
context.discard is like context.individual for each discarded card, and it happens with context.repetition as well
right
will this work or do i need to add a .name or something to those contexts?
these are keys not names
context.card.config.center.key
danke
and those are the keys ive put in right?
yes
cool
um i tried to make it add a joker and instead its acting like riff-raff and adds 2 random commons
lol, that name
what context are you using
does anyone know what's with this crash?
oh and ideas man wants your thoughts on the joker itself one sec
I don't think card is in using_consumeable, it's consumeable
ah shit youre right
Decent econ — would be just fine in the base game (maybe a little weak) but has very strong synergy with Reverie from my pack
(the one that makes Heiro / Temp)
Maybe up it to $6, at least?
it only does one joker now!
..but it got stuck here when i discarded 5 cards...
you need to add return true to the event
- should be The Hermit
- add their info queues
i mean in the description
it works now
this is so annoying, there are so many things that i simply dont know of that balatro adds to itself
like all the G.whatevers
welcome aboard
ah
i see
also like, again
i've made two sigils, but i havent been coding
what im doing isnt coding
its stealing and educated guessing
then begging people here to help

welcome aboard
hello! im trying to make this joker work and it almost does, but i have a couple issues with it
the joker is supposed to have the effect
+15 Mult, -3 Mult per face card scored
however, the mult reduction doesnt work if the hand contains only one of each face card, and the description of the joker is also not static like i would like it to be
can anyone see the issue here? im stumped
like if this was reletively normal-er coding it would be fine, but its just
balatro
like- ill be getting mauled by a bear, and i try looking for sticks and stones and whatever to help with this bear, and after hours of trying to deal with this bear i go to a bear expert and she tells me that if i stand on my hands and whistle the bear runs away.
thats what this feels like
what the heck are you doing
this is wonderful
appears in meme packs
doot
hi lovelyman
welp, that's 2/95
ok so i managed to make it create 1 joker but it
creates a random common?
instead of the joker i set it to be?
also yeah code is based on the popsicle stick code from paperback lmao (at least this part)
cant you use card:is_face() instead of checking the id
you didn't set it to be a specific joker what the heck are you talking about?
i didnt?
no im the idiot
o
maybe the wrong amount of nils?
isnt the key on the right the random key
you should use SMODS.add_card tho
how do i convert it to smods.add_card
i would appreciate if you didnt react like this to my code!
and just told me what im doing wrong
for a challenge if I want all jokers restricted do I need to manualy type in restrictions = { banned_cards = {
and then all jokers ids?
if i leave that nil it crashes the game
yea it needs a seed key to randomize with, its not actually setting the joker
check the steammodded docs, specifically utility functions
no, just
from jokerless
oh, can i? i didnt know that
what exactly do you want your joker to do
actually true
give 15 mult, reduced by 3 for every face card played
and then add my joker's ID to jokers = { {id =
wdym?
you'll have to update the mult value manually
check the code for other scaling jokers
basically I want to make a challenge where you try to beat the game with 1 modded Joker and not have access to another ones
youre also looping through the scored hand, but using context.other_card instead of the loop variable, which im not sure is going to work
oh then yeah do that
awesome thanks
yeah you definitely should so that it interacts with pareidolia correctly
also if other mods add face card ranks
how do i do that?
card.ability.extra.mult = card.ability.extra.mult - card.ability.extra.mult_minus
i did that and now its crashing due to "attempt to index center a nil value"
hum?
sorry, a friend was trying to help me and we did a lot of back and forth with editing the code so some of it might have gotten lost between us
u forgor the j_
even with the j_ added it did that
u also have a name conflict
does the key need to be the same as my Joker?
where?
local card conflicts with calculate's parameter card
check out SMODS.Challenge docs
on the wiki?
ye
use SMODS.add_card, not SMODS.create_card
it handles all of the initialization and placement
also if specifying a key directly then set and cardarea are optional
oh my GOD still with the center nil value
j_modprefix_jokername
yeah remember to restart your game when changing stuff
no like
start a new run when changing your config
💀
that took WAY longer than it shouldve but at least this joker is now completed
jackpot gives 3 jacks, then the jacks are not there anymore so it becomes a normal pot
the funny
i have only one sprited joker left to implement and then the initial 10 will be done
what do you mean by this? sorry if it should be obvious!
if context.other_card:get_id() == 11 or context.other_card:get_id() == 12 or context.other_card:get_id() == 13 then
new_minus = 3 + card.ability.extra.minus_mult
end
end```
you make a variable called scored_card for tracking all the scored cards but when checking if the card is a face you use context.other_card
i also think you should do this loop in context.before otherwise it might run multiple times
Where are the descriptions for the jokers stored?
localization
Thank you. I don't know why I didn't think to check that one.
is there a way for a joker to fetch the sell value of another joker?
so what do i change to context.before?
i think the whole calculate function could just be this
if context.joker_main then
card.ability.extra.mult = 15
for k, v in ipairs(context.scoring_hand) do
if v:is_face() then
card.ability.extra.mult = card.ability.extra.mult - card.ability.extra.minus_mult
end
end
return {
mult_mod = card.ability.extra.mult,
message = localize { type = 'variable', key = 'a_mult', vars = { card.ability.extra.mult } }
}
end
set it to 15, loop through the scoring hand, remove minus_mult from the mult every time theres a face, then return the mult
how do I get a deck to be just hearts cards
the return should just be return { mult = card.ability.extra.mult }
in a challenge
you'd have to define each card manually
true, i copied from their return which i think is copied from popcorn
how does on do that/where can i find that on the wiki
also cryptid already has single-suit decks
look at the game's source code
extract balatro.exe as a zip
play_sound("modprefix_soundkey")
how would i get a joker to increase its sell value? im not sure how to do it from egg's code
if it sounds weird you may need to convert it from mp3 to wav or ogg
how do i stop the background music
this is such a dumb idea 😭
does anyone know?
based off this, change card.ability.extra_value then card:set_cost()
thank you for being straightforward with me! i really appreciate the help
is there a function to stop the bacground music?
if u wanna replace the background music check out jimball from cryptid
how do i know when a sound stops?
Can also open archive with 7zip.
you don't iirc
is pseudorandom the same when called in the same step? like, two times in the same if statement chain
i dont think so
it it needs to be the same, just store the random in a variable before hand
yep, that's what i assumed
why is this saying assertation failed
trying to get a joker gain half the sell value of every other joker at end of round (like a combo of egg and swashbuckler), but it crashes when thats supposed to calculate, any thoughts?
highlighted is line 781
...huh.
maybe replace the self's with card?
did you want to have an underscore in extra_value?
instead of a period?
yes
noted
copypasted from egg code
ah
new run
self refers to the prototype, you need card
yep, that worked!
also is it supposed to ignore all jokers of its type
im trying to do what cryptid does with jimball but its not working
also: testing environment bc funny
yes, so it doesnt scale quadratically if theres two of them
ok, just wanted to make sure that's intended
can still scale quadratically with egg
two of them would make it scale exponentially
oh wait
is there no context for each ante?
shit
hm?
i want to have an effect reset on each ante
but i ctrl f'ed basegame jokers to find any, nothing
and there's none on the joker calculation page
campfire
literally only affects crimson heart lol
oh yeah, what's the common way to make a sound only play as a thing is happening
e.g. an animation
it seems like events?
doot
okay it is events
now to learn how those work
presuming my mod's prefix is deal and comed is the key of the joker in question, this is the right way to check if its not that joker right?
i getcha, i was just looking up documentation
cus as of right now i think comedy gold is scaling off of itself
thankfully outside of like one bug this joker is (kinda?) working and isn't crashing at all
unlike before
so yay!
v.config.center.key
thanks
how do i wait for a specified amount of time?
okay so functions are just a structured way to tell the game to process these at the same time when it's able instead of immediately
ic
is it delay?
how do i make it not scaled
idk
yeah thanks for the help but also
i think im gonna play one run before i update the code
damn case sensitive values keep fucking me up...
problem, how do i stop the number in the description from changing alongside the effect mult?
it should always say "+15 Mult"
that's just what you're defining in loc_txt, no
it's pointing to a variable that's changing
redefine it to point to one that isn't
perfect!
(fwiw at that point you could just write the number in the description itself, but regardless)
true! but this works too
shit, thats it then! this is my first fully functional joker
feels good
but then oversat/glitched wouldn't work
hmm, having trouble understanding why this isn't working...
it's SUPPOSED to
- hit joker eval phase
- do the event (it is)
- change the value (it is)
- play the sound (it is)
- return the message (it isn't, i'm guessing i have to do it with a different function instead of trying to return it here)
- return Xmult AFTER all of that (it's not giving any xmult at all, no matter what)
OH!
okay
first issue gone
i think, anyway
no wiki entries
Man.....
yeah bettercalc still isn't well documented
also return xmult instead of Xmult_mod
just did yep
Alright here's a weird one I have no clue how to work around
and i got same issues
you need to lower bounds
nah it was a separate thing
an event happened every frame
it also played a sound!
it was very funny.
you need to context.after to do that
mr. lovely could i ask that in the release notes the expanded patch targets section mentions explicitly that --dump-all is useful for getting the target field for cross-mod patching? maybe save other people some condescending remarks and such
@gaunt thistle 
I figured that
Every encountered buffer can be dumped, not just the ones that have been patched. Alongside each is a text file which contains the internal name of the buffer - use this name in the target field of patches.
would be enough but it's a good request
let me write it up real quick
yeah its just
having the information in different sections
sorry im just bad at reading ig ;;
Oh shit 0.7 came out? Happy days 
Now to figure out how to patch into Steamodded. That sounds like a tomorrow problem tho lol
i think there's literally a delay function that does exactly that for you
I believe you can also do delay(time) in the function order lol
i think its just like a love2d engine thing
yeah lol
it's ok! improving docs is always really important
I've been trying to do a better job at it with this release
anyhow take a peek and lmk if it's a bit better
not to mention maintaining documentation is a very, like
"oh i know all of these things so i would never think to write down X"
the documentation i write is faaaairly different (unreal modding stuff) but it's mostly the same
it can be difficult to get yourself out of the "I made this so I know everything" and into mindset of a normal user
Making sure people understand how Unreal stuff works is a piece of work in it of itself lol
I find it's even harder to write good developer documentation though
installation guides are easy
ish
thankfully in my case it's a lot more step by step
so it's hard to miss specific things
just painful to write
any association with ue4ss?
oh wow, this is great
it takes talent to write good docs
so nice work
I've interacted with unreal engine modding a little bit for work
Ooooo Strive modding is sick. I respect that background
it's really impressive stuff
https://youtu.be/x48XlP9zYrg
i'd consider myself Pretty Good at it
it feels nice to get to the point where you become a pillar of information
(now to work on my balatro mod and not infodump)
Finally done!
MOD LINK: https://gamebanana.com/mods/526374
ah yeah balatro mods
True. Especially when it's like I made it this way do to x but then user doesn't know that and they make some mistakr and I'm like obviously you shouldn't do that
Neon White mentioned 
This is such a mood
yeah i just kept like flipping back and forth between what info i could find on 0.7 but somehow didnt find that it was just like two down on the release notes so
is there a way to know, within loc_vars, where the function is called? I have an idea to push something to info_queue that is a large block of text, and it might be better for the user experience if it only pops up within the collection page and not actual gameplay
well the smods docs have really been improving so nice work so far :-)
yeah that's totally fair
I added an additional explanation for that section. eventually this stuff should be moved over to a wiki, but I don't have the energy to do technical writing
That's mostly aures work.
great work mr. smods
valid
i really, really really recommend MDbook
using it has been completely pleasant
and i just host it on a github page
we use gitbook at work and I've really enjoyed it
but mdbook is also a really good option
Making a repo for the smods wiki was real nice
I pretty much just want something I can hook a repo up to and bada boom bada bing it works
yeah i saw; that should at least be enough to get people on track if that feature's what they're looking for
(i think i just skimmed the --dump-all section because it just said about debugging and im like "well thats not what im trying to do right now i dont even know where to start?")
yeah that was a smart idea. I didn't even know you could do that tbh
When I learnt that the wikus were just repos it kinda just clicked in my head
sorry to be a bother ;;"
never being a bother
I appreciate the feedback
lovely docs right now are basically non existent so anything helps
wiku? Miku's wario?
text block incoming
calculate = function(self, card, context)
if context.joker_main then
if pseudorandom('greenz') < G.GAME.probabilities.normal / card.ability.extra.odds then
G.E_MANAGER:add_event(Event({
func = function()
card.ability.extra.XMult = card.ability.extra.XMult * 2
play_sound('myo_greenzwin')
SMODS.calculate_effect {
message = 'Double!',
card = card
}
card = card
sendDebugMessage("greenzwin", "myodebug")
return true
end
}))
else
G.E_MANAGER:add_event(Event({
func = function()
card.ability.extra.XMult = card.ability.extra.XMult / 2
play_sound('myo_greenzlose')
SMODS.calculate_effect {
message = 'Nothing!',
card = card
}
card = card
sendDebugMessage("greenzlose", "myodebug")
return true
end
}))
end
delay(4)
return {
xmult = card.ability.extra.XMult
}
end
if context.end_of_round and context.individual and not context.blueprint then
if G.GAME.blind.boss then
card.ability.extra.XMult = 1
card = card
return {
message = localize('k_reset'),
colour = G.C.RED
}
end
end
end
}
okay so
i need help with timing
i want
- the calculation to happen BEFORE the joker gets its mult
- the message to pop up ASAP when the sound plays (if possible)
the 4s delay in there is for it to test
it seems that if i use calculate function at all it only happens when the delay is done
...which is bad, since i want it to be visible before the XMult appears
but i have no idea how to "reorder" these things in the event queue, or something
i've heard tell of the context.after
is that the solution?
You probably need to dispatc events for what you want to do manually instead of retuning
rephrase?
i'm basically banging my head against lua until i learn it here
you're saying i should add another event with a calculate effect to do xmult?
instead of leaving it up to the return value
okay word
that shouuuld fix both things
SMODS.eval_this might work https://github.com/Steamodded/smods/wiki/Utility#mod-facing-utilities
Can you type out the order of events how you want them to play out for me?
Pls no
okay i think i get it
event to do A and B
->
event with delay = 2 or whatever that has the xmult part in it
don't return anything
i'm guessing that separating it into two events will also fix the xmult order problem
hopefully!
That’s much more complicated than it needs to be
okay so
joker gets triggered
rng gets rolled, joker variable math happens, sound and message happen simultaneously
wait 2 seconds or whatever
do the XMult return WITH the value from step 2
right now the message happens later no matter what and the xmult is always taking the value from before the joker actually plays
Do you need the 2 second delay?
not literally two seconds, but if there's no delay the two messages happen at the same time (double/nothing & xmult) so it's a bit annoying
Gimme a minute to type it up, am on mobile 😭
valid!
i don't need actual code, just a lay of the land
Eremel you are a saint dude lol
the worst part is making these knowing i want to do so much worse
The horrors
ergo, "yeah let's manually redo the entire deck array to topdeck hearts only"
which honestly doesn't sound that bad from my limited understanding but i digress
That sounds broken asf
Real, writing code on mobile is insane
it'd be a Rare for sure
it just fits really well thematically
Pls, I need help, I'm trying to make a food joker that gives money. Currently the giving money works but I want it to reduce given money by 1 per round, how do I do that?
if context.joker_main then
if pseudorandom(‘keyhere’) < 'do you check here’ then
— change mult here
SMODS.calculate_effect({ message = ‘text’, sound = ‘sound key’}, card)
else
— change mult here
SMODS.calculate_effect({ message = ‘text’, sound = ‘sound key’}, card)
end
return {
Xmult = mult here pls
}
end```
unironically reorganizing the deck isn't actually that hard if you know what you're doing
okay i can pass sound into calculate effect
aough
documentation...
and the delay is handled by... calculate effect i assume?
It’s in the documentation…
balatro modders cant read
But yes calculate effect will handle all the timings for you
only mention of it i can find is some guy writing about it #1307744498360520805 message here
*that screenshot is me searching "calculate_effect" in smods
Ah
it's been indispensable
oh i just use npp locally to search the smods folder lul
valid
CTRL + F should activate that smh
Isn't that searching for the whole repo though
98%
slash does!
Add this into the joker's code
calculate = function(self, card, context)
if context.end_of_round and not context.blueprint and context.cardarea == G.jokers then
card.ability.extra.money = card.ability.extra.money - card.ability.extra.money_decrease
if card.ability.extra.money <= 0 then
G.E_MANAGER:add_event(Event({
func = function()
play_sound('tarot1')
card.T.r = -0.2
card:juice_up(0.3, 0.4)
card.states.drag.is = true
card.children.center.pinch.x = true
G.E_MANAGER:add_event(Event({trigger = 'after', delay = 0.3, blockable = false,
func = function()
G.jokers:remove_card(card)
card:remove()
card = nil
return true
end
}))
return true
end
}))
return {
message = localize('k_eaten_ex'),
colour = G.C.RED,
card = card
}
else
return {
message = '-$1',
colour = G.C.GOLD,
card = card
}
end
end
end```
Because the end of round happens before the money is given, you'll probably want to set `card.ability.extra.money` at one higher than you want the first payout to be.
thanks!
having a similar issue... anyone know how to make the card ui dissapear?
oh wait where is that
That’s an insane looking effect
Feels like the council is looking your every move
ANYWAY
calculate_effect was my savior
i think this finally works?
They watch…
my boy is finally alive
now for card art!
Someone forgot a {C:inactive}
I'm an artist I can make you art
Ah yes
X4Mult)
New lines should start with a capital letter probably
i am very proud of it if it werent for those pesky ace of diamonds, 9 of spades, and 8 of hearts......
i have three thoughts about this message
- why is the developer of lovely offering me art
- i'm doing my own already, don't worry lol
- i can't tell if this is serious or some MS Paint tomfoolery is about to be thrown at me
Nah I feel ya. Card UI ruining our fun by barging back in uninvited
This still doesn't work for some reason
I gochu homie
oh of course of course
Banger
i've always wanted to seriously Do pixel art so this is a good opportunity
I can do art here is my portfolio #⚙・modding-general message
message preview plugin coming in clutch
Woaw so talented
check again, I forgot to make sure that it properly eats itself when it reaches $0
actually i was curious why are these spaces not coming up
i assume X:mult doesn't support spaces?
yeah it doesn't have any code to do that
I updated the original message
On the calculate functions page
ive scowered most of the relevant source files but still just cant find where they actually hide the card ui, shit is black magic
geenz
Ikr?
i was too vulgar
Don’t look now muuyo, ethan lovely is stealing your oc
so Github is just being a [GREAT FELLOW] then
I have become god, destroyer of checkered deck (or any deck really)
Debuff <suit> blind
he's not even mine! he's John Jerma's!
Surely it’ll just get Jerma to play Balatro then 
idk why something about it just doesn't want to work
What a shame that would be for a build like this lol
every time I've tested it it doesn't trigger the reduction
two jokers !!DONE!!
now to sleep and then either hurt myself sorting arrays or do something simple in the morning
I’m excited to finally finish the implementation of one of my earliest Jokers in the morning since I can patch Steamodded thru Lovely now 
potential?
i just dont know what id pass through args
I'm sure this has been asked before but what source file has the actual functional joker effects? Trying to reference one.
Vanilla? card.lua.
Yeah I’ve seen a lot of wiki pages being missed from searching, maybe it’s because it’s on its own repo now?
Thank you. I've been looking but it's just walls and walls and even when I scroll through them I think I scrolled right past.
Which one?
what changes do you need to make to smods? just curious
you're probs one of the first people to use the expanded patch target system
nvm this is for resizing the screen, which moves the buttons around =\
I had a patch that needed to target smods but I don’t remember what it was now 🤣
#1330398500999135273 almost did
until i realized i didn't have to
didn't make any jokers today but I did convert the remaining three jokers to the new format, and gave them bestiary entries
i finally fixed mine by forcing the game state to playing a tarot & keeping track of the previous state so i could reinstate it after the animation. yours would probably be similar but with TAROT_PACK instead probably (this is probably not the correct way to do this but...)
I'm struggling to figure out how to make a retrigger effect that activates on more than one rank of card, in the style of Hack.
Would you guys say this is basically that hieroglyph voucher
-# Although I guess it "freezes" the ante and has no downsides
so the ante goes up by 1 after 2 boss blinds?
Only once, yes
its worded as if the ante increases an additional time after 2 boss blinds
+3 ante after 2 bosses
maybe Ante doesnt increase for the next boss blind would work
"Prevents Ante from going up after beating a Boss Blind once. self-destructs."
that sounds better
I like this one
Also is rare too much
its probably niche
rare feels like too much, uncommon feels like too little
but probably leaning more towards uncommon
since it is a joker slot being taken up
It takes a slot for a short time though
its kinda hard to take it late game since you probably have your jokers filled at that point
which i think balances it like heiroglyph
During late game it would prob be useless since its use would be to help scaling other jokers
Better
why doesn't the Xmult happen when i play an Ace of Spades?
if context.individual and context.cardarea == G.play and context.other_card:get_id() == 14 and context.other_card:is_suit("Spades") then
return {
message = localize { type = 'variable', key = 'a_xmult', vars = { card.ability.extra.xmult } },
Xmult_mod = card.ability.extra.xmult,
colour = G.C.RED,
card = card
}
end```
x_mult_mod perchance
no, this works with my other jokers
whats the full code
SMODS.Joker {
key = 'eyeofprovidence',
loc_txt = {
name = 'Eye of Providence',
text = {
"Each played",
"{C:attention}Ace of Spades{} gives",
"{C:white,X:mult}X#1#{} Mult when scored{}"
}
},
config = { extra = { xmult = 1.5 } },
rarity = 3,
atlas = 'Phanta',
pos = { x = 1, y = 5 },
cost = 8,
loc_vars = function(self, info_queue, card)
return { vars = { card.ability.extra.xmult } }
end,
blueprint_compat = true,
calculate = function(self, card, context)
if context.individual and context.cardarea == G.play and context.other_card:get_id() == 14 and context.other_card:is_suit("Spades") then
return {
message = localize { type = 'variable', key = 'a_xmult', vars = { card.ability.extra.xmult } },
Xmult_mod = card.ability.extra.xmult,
colour = G.C.RED,
card = card
}
end
end
}```
Mm I dont see anything wrong, try doing some prints
Altho this is for example Bloodstone and it uses x_mult
you dont need to return the message, and im pretty sure its 'x_mult'
weird
hmm
maybe Xmult_mod is for individual joker activations?
ah yeah, bingo
cheers!
Its probably for joker_main activation
Just use better calc and don’t worry about all this specific key crap
fewer dependencies is better imo
You’re just developing on an old smods version, it’s not a separate mod
ah
Is "Played cards that did not score will be destroyed." doable? Part of my memories keeps telling me that context.destroying_card only iters through scored cards but I'm not entirely sure about that.
i'm positive you can get unscored cards, and pass that info into an event that destroys them
that's a very op ability :D
even Trading card, which only allows 1 destruction per round, is great at deck fixing
Which means I have to either nerf it (limit to first played hand and/or destroys one card per hand) or tweak up the rarity.
How do I get my joker to trigger on specific cards without crashing Balatro immidiately? Everything else is going swimmingly.
context.other_card:get_id() == 9
Did not do the trick.
can i see the rest of your code?
🤫
Yes but it's defintely not good.
that's okay!
i don't mind it being "bad" by anyone's standards, i care about it working :>
i feel like the cash reward isn't a needed incentive?
destroying up to five cards per round is already really good
I was watching a tutorial on YouTube by "artmuncher" and it was helpful, but it's kind of limited.
Could I DM it to you?
It'd be best to just send it here, otherwise, the potential help may be limited.
I don't even know how to do the codeblock thing in Discord. Does it work if I just copy paste it?
```lua
code
key = 'Jokers',
path = 'Jokers.png',
px = 71,
py = 95,
}
SMODS.Joker{
key = 'joker2',
loc_txt = {
name = 'Placeholder',
text = {
'Retrigger',
'each played',
'{C:attention}6{} or {C:attention}9{}',
}
},
atlas = 'Jokers',
pos = {x = 0, y = 0},
config = {
extra = {
}
} ,
calculate = function(self,card,context)
if
context.other_card:get_id() == 6 or
context.other_card:get_id() == 9 then
return{
message = localize('k_again_ex'),
repetitions = 1,
card = self
}
end
end,
}
Okay, I finally got it.
if context.individual and context.cardarea == G.play and (context.other_card:get_id() == 6 or context.other_card:get_id() == 9) then ?
ya that :D
sorry, was getting food :>
for your text:
text = {
'Retrigger',
'each played',
'{C:attention}6{} or {C:attention}9{}',
}```
i'd change it to:
text = {
'Retrigger each played {C:attention}6{} and {C:attention}9{}'
}```
Yeah, that would look a lot better. That's an artifact of following Hack a little too closely.
all good :D
https://youtu.be/1KBAJg_PBdw a followup to yesterday's discussion
When I try to play a card it applies to I get a crash that says
attempt to index field 'other_card' [a nil value]
Also why does mine not have colors? I'm not trying to make it less readable.
you are checking for cards played in no specific context, so the game checks even if there are none, id recommend adding context.individual to the if statement
Is it OK to use wordings other than "destroyed" to mean a card will be destroyed?
Ah, that makes sense. Thank you.
mmm i think so yeah just make the text red
it seems understandable
maybe add a footnote saying (Archived cards are destroyed)
or something of the sort
my first fully functional joker!
"No no no, they're not destroyed! I just took them to somewhere else!"
LOL
JIMBUS COMPANY IM DYING THIS IS AMAZING
yeah! im gonna make a lot more limbus-related cards
so cool ill surely play the mod when you release it
yay! :>
Well, it's not crashing anymore, but it's not retriggering either.
It's just, inert.
what's the context for when a joker is sold?
like not the specific joker, thats context.selling_self
i mean like a joker in general
context.selling_card is for any type of card, i want to restrict it to only jokers
if context.selling_card and context.card.config.center.set == "Joker" then
perfect
key = 'Jokers',
path = 'Jokers.png',
px = 71,
py = 95,
}
SMODS.Joker{
key = 'joker2',
loc_txt = {
name = 'Nice',
text = {
'Retrigger each played {C:attention}6{} and {C:attention}9{}',
}
},
atlas = 'Jokers',
pos = {x = 0, y = 0},
rarity = 2,
cost = 6,
blueprint_compat = true,
loc_vars = {self.ability.extra+1},
calculate = function(self,card,context)
if context.individul and (
context.other_card:get_id() == 6 or
context.other_card:get_id() == 9) then
return{
message = localize('k_again_ex'),
repetitions = self.ability.extra,
card = self
}
end
end,
}
attempt to index global 'self' [a nil value]
and if i wanted it to also activate when a joker is destroyed how would i go about doing that?
card = card
card = self makes everything crash, use card = card like Ali said
self.ability.extra > card.ability.extra.repetitions
config = { extra = { repetitions = 1 } } too.
Do they just die when they reach 0
loc_vars is supposed to be a function, not a table
but you don't have vars in your description anyway
Thanks. I'll try that tomorrow.
how would i get these all to be able to trigger at the same time like the lucky card? right now it wont go past the first one
...define a blank table and "add" effects to the table that you return after all of that?
Yeah, relic from the tutorial tutorial which is for an x mult joker.
how?
local effect = {}
if condition1 then effect.x_mult = card.ability.extra.xmult end
...
...
return effect
bump
What's more appropriate for this, Uncommon or Rare? I'm a bit torn
Wut
hmmm id say uncommon
im torn too
on one hand it can be really strong
on the other it does occupy a joker slot, which a voucher does not
maybe rare is better?
It also costs 3 dollars less
Rare. maybe Legendary.
legendary is way too much
no but the ability to effectively halve the blind's requirements is insane
it's like a Heiroglyph, but with no downsides (other than the slot taken) and also a -1 rounds required to win
I dont think its a -1 rounds required to win, you still need to beat 8 antes
what? it just works like hieroglyph, i dont see where you've got the -1 round from
For some reason discarded face cards did not get removed by this joker.
Can anyone help?
crash occurs after the joker gets destroyed by dagger
the heck is jimbus company
How do I get black background in {X:}?
{X:black} i think
remember to also {C:white}
or your text will not be readable
so it would be like {X:black,C:white}
is this balanced as is?
it does make infinite money
but its also a malus because getting rid of it is extremely hard
it also gives utility to dagger to kill it
any infinite thing imo is unbalanced
should be like once per round or something
well you do make one dollar at a time
and you lose the ability to sell jokers for slots
that would go against the point of it being unkillable
maybe after 50 times sold the sell value goes to zero
well ok, is this mod supposed to be vanilla balanced?
mostly yea
losing the ability to sell jokers to free up space to make exactly one dollar at a time is strong but not really game breaking i think
at a certain point you deserve everything you get if you have the patience to sell a joker 100 times
You have to balance an effect like that between being too good or unusably bad
which is why these effects only appear in mods
originally it had 0 cost and sell value and x1.25 mult
would that be better?
actually this with campfire would go silly
Yeah, I forgot about campfire
In its current state this Joker feels like a cryptid joker
What’s a Consequence?
Hey, does anyone know of a way to place Enhancement text after bonus chips text? say I have an enhancement that doubles the total chips a card gives and that card has Hiker's 'extra chips'
+2 is base chips
+7 is my enhancement
+5 is hiker
how can i choose a random Tarot, and get both its name and ID?
(in case modded Tarots are in the game)
I can’t read 😭
There’s a vanilla function to create a random card
No its the wording that made it seem like something was gonna happen
I thought Consequences was a type of Joker
But I didn’t realize it was the Joker itself
anyone know what generally breaks older patches in lovely 0.7.0
patch ordering between patterns and regex has changed
in 0.6.0 they are executed in order of appearance in the file
in 0.7.0 they are executed in order of patch type
well
not just patterns and regex
how would i make a voucher do something at the end of the round
Gotta patch or hook... or wait until Voucher calculations are implemented. Waiting for that too.
😭
how do i wait for like 3 seconds
like wait for 5 seconds
Don’t really beg but maybe ask nicely in the Steamodded thread
But wait for what
actually you should beg
i want to space out some statements
then I have a reason to procrastinate for longer because I'm making you wait
so they happen one after another
either hog the thread for 3 seconds or make an event with a delay
which one is more acurate
note: delay only works if you use events for what you'll do after
i mean hogging the thread would be more "accurate" but freezing the game for 5 seconds probably isn't what you want
how do i keep this in sync with the music...
I don’t know if you can
custom music that plays for like 1 min
You can try with delays
so likeeeee
what is patching (or hooking)
But this isn’t New Super Mario Bros.
is there somewhere i can look for example planet/tarot cards? the documentation is extremely lacking on that :(
and my searches have so far brought nothing
@frosty dock three people begging
Maybe in the Example mods
Or Bunco
ooh right hold on
i was looking at the cryptid src but it doesnt do things exactly the same way
lemme see
unlocked = true,
discovered = true,
atlas = "ATLAS",
set = "SET",
name = "set-NAME",
key = "NAME",
pos = {x = 0, y = 0}, --Atlas position
cost = 4,
can_use = function(self, card)
--!!CONDITION FOR USING!!
end,
use = function(self, card, area, copier)
-- what the rune does
return true end }))
end,
}```
i assume set would then be "planet" "tarot" or "spectral"? or capitalized
or somethin else
im not sure about that
lemme experiment then
this is for if you have a consumableType
my goal is to create two new planet cards for the two new hands i've added, one new tarot card, and one new spectral
lemme poke hold on
thank yall
try set = 'Tarot', 'Planet' or 'Spectral'
will do
i want to make a card speak every like 5 seconds and end after 1 min so i need some sort of timing or delay
config = {
lasttime = 0
},
update = function(self, card, dt)
if (love.timer.getTime() - 5) > card.ability.lasttime then
card.ability.lasttime = love.timer.getTime()
--every 5 seconds
end
and then how do i define a description? loc_txt?
yes
perfect ty
what should i put in the loop to not have it lag
I don't think you can run that loop without lagging
You're hijacking the thread to wait
guess u gotta learn to multithread if balatro even supports that
i just want so pause until some time 😢
Hm... why do you want to pause?