#💻・modding-dev
1 messages · Page 89 of 1
startRef(self, args)
--reduce hand size by x after round
G.GAME.TGTMchangeHandSize = 0
--Get intrest amount
IntrestAmt = G.GAME.interest_cap
--Chance for a card to get cursed
G.GAME.TGTMCurseChance = G.GAME.TGTMCurseChance or 0
--Buff Face Card for a round
G.GAME.TGTMFaceBuff = G.GAME.TGTMFaceBuff or false
end``` set globals (TGTMFaceBuff)
even with a toggled global variable its like
sdjfhsdkfjh
I meant
the card still isnt acting like a joker in the end, it doesnt get triggered by all the contexts because it isnt a joker, it isnt in the right card area
do you have a keyboard smash button???
im actually very trained in it
joker_main also gets called for consumables
what happened!
and it works for the basic effects
but it just doesnt seem to trigger for more complicated effects
wdym by basic and mor complicated
sdkfjhsdfkjh
basic meaning +20 mult or +50 chips
complicated being anything that is triggered outside of just when scoring your hand and adding up all the numbers
like Xmult
reading through the code its like
yeah Xmult counts as basic
that was the one coded exception
but like Xmult for kings
yeah no too complex
almost all the calculation functions are designed to check for joker cards
if you didnt want to use patches you couldve gone with the spawn joker path
i do like it, very good mod
i liked the challenge and i wanted the coolness to be acknowledged :(
ksdfhjksdhjf
okay cool, thank you
sdjfkhgksdjhfk!!!
okay fair
im doing something similar with runes, with the temporary upgrades
oh hm,,
like they arent different runes, but the runes act differently
i mean
nobody's stopping you
G.GAME.round_resets.ante for reading, ease_ante(arg) for setting?
i think i was using G.GAME.round_resets.blind_ante instead of G.GAME.round_resets.ante
is it better for 2 different mods or just a button config
these runes will have NO downside, except gain curse chance for any rune
muahahaha
Cursed Planet: delevel the hand
Cursed Tarot: selected cards turn into dummy cards (0 chip no rank/suit)
Cursed Spectral: Remove edition, enhancement and seal from 2 cards that have them```
i already have curses in the game, its just that itd be more prominent
oh this would be so much work
its fine
can you have conditional descriptions?
like if a, description is "hi" else description is "hello"
it could probably be loc_vars shenanigans
you could,, probably look at the code for like, say, misprint?
yeahhh a lot of loc_vars shenanigans
indeed you are now a modder
should you be able to change if the runes are cursed in a game or only before the match?
NO WAY M i mean ehwaz
the M rune...
idea, if cryptid is installed also create a negative jolly joker
for m rune
This is cool, and using patches is definitely easier than trying to hook all the relevant functions in an elegant way
thank you!! ksdfjhskdfjh
yeahhh
though, looking through some of my issues now, it,, seems like its partly because of how steamodded implements the retrigger system?
i cant exactly tell where it is, but its like something something the code that evaluates the return is stuck inside callback and doesnt get called?
Uhhhh possibly, it depends how you’ve patched
i, essentially went through everything and created a copy of each main/relevant joker calculation for consumeables
In state events?
can i add a global from G? like G.TGTMVARIABLE
forgot what its called
for the contexts to go through
but im not sure if im missing something
Yeah that sounds like it should work properly then, it shouldn’t interact with retrigger api either depending on how you’ve done it
hm,,, weird
my main issue is that like
return values essentially do nothing
and i cant tell if its a problem with my patching or if there's something that i've missed
Probably a problem with your patching
Can you send an example of one of your patches?
sure thing!
this is the one im focusing on rn
and heres how it ends up in the code
cleaned up a little*
Yeah okay, so you’ve got the retrigger stuff included in that, I believe there are some more retrigger patches that’ll need patching to work
ahhh
okay gotcha
it kinda breaks whenever i dont include retriggers in this so i was a little forced to
but thanks!!
now i got a good direction to go in
I think if you put it back how the original statements were in the main game lua it should be fine
does having gemstones in glass make sense for the art
ive,, tried
but it brings up a lot more errors because of how the patches worked?
it added half of that callback function but not the other
yeah like they're on display?
oooh maybe
I should be able to take a proper look later this evening
yeah to make sure they don't get damanged
kinda like if they're in a museum

should i try to render the gems kinda like how the legendary jokers are done?
should i send my patches and stuff to you as well for debugging?
ooh yeah that would be fun
oh or maybe the opposite if you're aiming for a gem in a glass case look
i'll see what i can do
Sure, that’d be a good start, or you can send me your whole project in a zip and I’ll test it out
name = "NAME",
text = {"#1#"}
},
loc_vars = function(self, info_queue, card)
return {vars = {(G.TGTMCURSEDRUNES and "CURSED DESC") or "NON CURSED DESC"}}
end,```this would put cursed desc if G.TGTMCURSEDRUNES and NON CURSED DESC otherwise, correct?
that was easy, might need to remove some of the glare
how do i make a button
in settings
llike talisman
why dont i look at talisman
thanks guys
Don’t add a button to settings
what should i do?
add a config tab... like talisman
im looking at talisman and its complicted
man if only there was a html like sub inspector.....
if someone made that for Balatro UI it'd be a life saver
cuz it is 🙃
i would make one given infinite time and resources
curse you mathisfun and your very wierd code!!!!!
infinite monkey type theorem
localthunk code is weirder
i'll cast the Card:calculate_joker spell on you
i can understand it though

im going to copy some code and i am going to figure things out
each table is kind of like an HTML block
Here's a cleaned up version of the Talisman UI code if it helps you:
Talisman.config_tab = function()
return {
n = G.UIT.ROOT,
config = {emboss = 0.05, minh = 6, r = 0.1, minw = 10, align = "cm", padding = 0.2, colour = G.C.BLACK},
nodes = {
{
n=G.UIT.R,
config= {align = "cm"},
nodes={
{
n=G.UIT.O,
config={object = DynaText({string = "Select features to enable:", colours = {G.C.WHITE}, shadow = true, scale = 0.4})}
},
}
},
create_toggle({
label = "Disable Scoring Animations",
ref_table = Talisman.config_file,
ref_value = "disable_anims",
callback = function(_set_toggle)
nativefs.write(lovely.mod_dir .. "/Talisman/config.lua", STR_PACK(Talisman.config_file))
end
}),
create_option_cycle({
label = "Score Limit (requires game restart)",
scale = 0.8,
w = 6,
options = {"Vanilla (e308)", "BigNum (ee308)", "OmegaNum (e10##1000)"},
opt_callback = 'talisman_upd_score_opt',
current_option = Talisman.config_file.score_opt_id,
})
}
}
end
You can also look at any of my mods for ui code
i am going to go through each line!! and i will learn!!
Paired with my overview, I imagine you can get a reasonable grasp of it if you’re invested enough
i think im learning
https://github.com/Steamopollys/Steamodded/wiki/UI-Guide this is so useful
A Balatro ModLoader. Contribute to Steamopollys/Steamodded development by creating an account on GitHub.
what is a refrence table/value?
is this supposed to be a code block? 🤔
hard to explain exactly why but it looks for ref_table[ref_value] for some type of input (such that you can simply change the value to adjust what the UI shows)
like #1# in loc_vars?
No it’s not, gits markdown is different to discords and I haven’t combed through that one yet to fix stuff
I battled with it for a while on the calculation context page till i found a layout that I was sort of happy with
similar but not quite. #1# signifies that it should look for the first value in the table returned from loc_vars, a ref table/value indicates that it should look for a value in some table. in loc_vars the value is fetched from a function only when necessary and with a ref table the value is a constant kept in a table that is always existent
It’s mostly useful for toggles and option cycles
Though you can also use it on text nodes
mfw dynatext
No, just regular text nodes
you can with both
ik you were talking about regular text nodes
Yeah, dynatext is a bit different in how it works, with it being an object
I haven’t used it a whole lot tbh
ya not always very useful
is there like a template for boss blinds that i can use for the animation?
i absolutely LOVE settings, or well configs but omfg do i hate trying to make it, its hella comfusing
love2d reference ?
Question: what number would you think makes the following Enhancement balanced:
When you defeat a Boss Blind, gain [value] xMult
It could be +Mult instead but this feels like a good place to add xMult
What does it start as?
How do you pass vars to a tooltip?
1
some feedback on https://github.com/Steamopollys/Steamodded/wiki/UI-Guide as a new ui learner:
instanceType has a bunch of values that arent explain
you mention like 7 useful functions, but dont explain what they do```
if you wanted feedback
Somewhere between 0.5 and 1 I’d say
I was gonna say around 0.5 as well
It’s not really a hand holding guide, rather just a brief introduction and then a list of what values you can set
but a small description would be appreciated
atleast for the useful functions
or maybe im just dumb and its fine...
dont take my word highly
I think it's a bit out of scope to explain what the Sprite, CardArea etc objects are and do, but I think it might be good to explain where to look for them in the code
yea
@tepid crow that’s what I was thinking but it felt like 0.5 would be too slow
hmm, maybe 0.75 or something would be better yeah
1x feels like a lot, but maybe you'd want to playtest it
yeah it's a funny one, you can definitely get more than 1x scaling on other stuff per ante
but just 1x for free sounds really good
You also need to draw from benefit from it later
And find the Enhancement in the first place too
documenting thunks cursed functions 😱
just their locations 🙃
I mean, the files they are defined in are exactly the same name as the class
I don’t see why we would need to document class definition locations when you can just search <class name>.lua in the game directory
LocalThunk has good enough organization skills that this really isn’t an issue.
DynaText is actually a part of engine/text.lua, and you don't know in advance that the classes have separate files
I see all of this as more of a way to explain to a new developer how to start to understand how balatro is written
im using this... atp im just copying the entire nativefs class.....
what eve n is native fs
loves filesystem management but with fewer limitations
ah..
key = "RestBalatro",
key_pressed = "m",
held_keys = {'lctrl'},
action = function(controller)
if G.STAGE == G.STAGES.RUN then
if not (G.STATE == G.STATES.TAROT_PACK or G.STATE == G.STATES.PLANET_PACK or G.STATE ==
G.STATES.SPECTRAL_PACK or G.STATE == G.STATES.STANDARD_PACK or G.STATE == G.STATES.BUFFOON_PACK or
G.STATE == G.STATES.SMODS_BOOSTER_OPENED) then
save_run()
end
compress_and_save(G.SETTINGS.profile .. '/' .. 'debugsave' .. "0" .. '.jkr', G.ARGS.save_run)
log("Saved to slot 0")
end
SMODS.restart_game()
end
}``` This is not restarting balatro, it closes but doesnt reopen
this is probably a debug+ thing
Just use NFS, Steamodded already includes it as that
I bundle nativefs so it can run without steamodded
why would you run it without steamodded
lovely.mod_dir.."/config.lua" would this be in the mods folder?
itd be in balatro/mods, mot balatro/mods/folder?
Oops
how do you defeat bonus cards
Put them on and find out 🥊 🥊
Hanged Man
how do i get the setting to show up??
local tabs = create_tabs({
snap_to_nav = true,
tabs = {
{
label = "TGTMConsumables",
chosen = true,
tab_definition_function = TGTMButton.config_tab
},
}})
G.FUNCS.overlay_menu{
definition = create_UIBox_generic_options({
back_func = "options",
contents = {tabs}
}),
config = {offset = {x=0,y=10}}
}
end
``` is it this?? its not showing up in game
another day another patch
had 4 hours of sleep and immediately am going back to modding: i may have a problem
ui is hard
yeahh
Are you trying to make mod config for your mod?
If so, you want a line that goes SMODS.current_mod.config_tab = function(), it's an SMODS function, unsure where it's been documented yet, and then you return a {n = G.UIT.ROOT, config = {whatever}, {nodes = {UI nodes in here}} and then end the function, and steamodded will pick up that UI code and put it in your mod page automatically.
Or, wait, are you trying to put it in the escape menu?
You can do it in the escape menu if you insist, I'd have to look into it to remember how, but, it's not advised, as if every mod put their config in that menu, that menu would be completely unusable. If you still want to do it, let me know, and I can try pointing you to some examples of it.
Yea don't put it in the escape menu or you'll be hated for it
Yeah, like that. I do recommend checking out Eremel's link.
i looked at it, why isnt it the wiki?
nvm
im an idiot
i thought mod config was config for mods like colors or something
Does anyone know how to get rid of the white title?
If you're talking about badge colors and prefix stuff, that's in the getting started section.
Maybe getting started should be separated into "Installing Steamodded" and "Creating Your First Mod".
nod config should be named mod config tab
What's your code for it?
is there any documentation on making your own stakes? cant seem to find any rn
object_type = "Enhancement",
key = "squirrel",
atlas = "mtg_atlas",
pos = { x = 0, y = 6 },
config = { extra = {max = 6 }},
no_rank = true,
overrides_base_rank = true,
always_scores = true,
weight = 0,
loc_vars = function(self, info_queue)
return { vars = { self.config.extra.max } }
end,
calculate = function(self, card, context, effect)
if context.cardarea == G.play and not context.repetition then
effect.mult = pseudorandom_i_range(pseudoseed("mtg-squirrel"), 1, card.ability.extra.max)
end
end
}```
probably look at cryptid
return {
n = G.UIT.ROOT,
config = {emboss = 0.05, minh = 6, r = 0.1, minw = 10, align = "cm", padding = 0.2, colour = G.C.PURPLE},
nodes = {
{
n=G.UIT.C,
config= {align = "cm"},
nodes={
{
n=G.UIT.O,
config={object = DynaText({string = "Beware traveller...", colours = {G.C.WHITE}, shadow = true, scale = 0.4})}
},
{
n=G.UIT.O,
config={object = DynaText({string = "Lest you want to be cursed..", colours = {G.C.WHITE}, shadow = true, scale = 0.4})}
},
}
},
create_toggle({
label = "Disable Runes Downsides..?",
ref_table = TGTMButton.config_file,
ref_value = "CursedRunes",
callback = function(_set_toggle)
end
}),
}
}
end``` is this code wrong? its not showing up
I'm planning on reworking the start of the wiki
as someone who is bad at ui, im sad
where are you trying to view it?
I'm honestly unsure, do see a bit of Cryptid code in there, pretty sure object_type is unnecessary and gotten from Cryptid with the way it loads mods. Enhancements aren't really documented anywhere, so it's kind of rough.
You might be able to throw in a {C:G.C.UI.TEXT_DARK} into title or whatever it is for enhancements as a temporary fix if you want it to be legible while you test other things, but, it'd be best to wait for someone who actually knows what they're doing with SMODS enhancements to give advice.
Do you know where the mod descriptions are?
Well, you can see it now and work with it.
First thing is to try putting all three of those nodes into R row nodes, so that they line up in rows, instead of trying to be side by side in C columns.
It's finicky, but you can get the hang of it after messing around long enough.
And, yeah, it puts them in a single row because it's trying to place them as side-by-side vertical columns, with the middles of those columns lined up with each other.
you just need to put the internal stuff in their own rows
Is there a way to get a card's suit in singular? What localization command would you use for that?
i think you may have to do that manually unfortunately
I have an enhancement that has no rank, but does have a suit, and replace_base_card is true. The player still needs to know what suit it is, so I'm going to pass the suit in text in loc_vars
nvm i figured out the text lol
Is there a way to change the text color using a vars from loc_vars?
Yeah.
{C:#3#}words{} this is what I have right now
You use {V:1} instead of {C:}, and have it as loc_vars = {vars = {x}, colours = {colour variable}}.
cards not retriggering?
awesome thanks!
Wait, capitalize the V as well.
not entirely sure this is how you setup retriggers but i got the return table from red seal
I assume stickers don't have a way to naturally apply repetitions, I don't know what it'd take without diving deep into the code myself, it might require a lovely patch somewhere.
yeah not entirely sure either
i have an eval_card function that i got from crypid that allows stickers to have a calculate function, although not sure if they can retrigger cards
Stickers already have calculate functions, it's just that they only trigger for jokers
And iirc Gemstones are for playing cards?
oh they do?
thats right, for rental and whatnot
gemstones can be for playing cards and jokers
some gemstones aren't compatable with jokers, although all gemstones can be used on playing cards
*function makes sticker's calculate function work for playing cards
oh just looked at the function and returning a table is useless lol nothing happens with it
return { vars = { self.config.extra.max, localize(suit_clovers, 'suits_singular')}, colours = { suit_clovers.hc_colour} } so this crashes the game when I try to pass these arguments (suit_clovers = SMODS.Suit {...})
ok i found a lead
retriggers are calculated in functions/state_events.lua (starting line 189) and only goes through eval.jokers.repetitions and eval.seals.repetitions
Here's how I did mine, colours = {G.C.SUITS[center.ability.extra.cur_suit]}, and cur_suit is a string of the suit - this method might not work for modded suits, though, unsure.
so i would need to patch in sticker support?
Yeah, best of luck. Don't have much advice outside of read carefully and test a lot.
going through how repetitions are calculated for red seal, eval_card in functions/common_events.lua is where i'll need to patch stuff in for stickers
also in functions/state_events.lua after eval_card returns a value
To clarify this a bit more, colours is expecting a HEX('colorcode')value, however you can get that into there.
Is there a way to tell if the enhancement is in the collection or not?
There should be a thing in the collection menu, right?
Oh, you're asking like a check.
The issue is when you hover over the card in the collection, it tries to get the localization of the card, but it has no suit, so it breaks
There's likely to be a better way, but any Jokers like that I just have it default as Ace/Spades in code, to match castle/idol/rebate, and just overwrite the config with with the information it needs whenever it's applied to a card.
is there a way to print debug info
print()
It throws an error even when I just give it a hex code
What happens if you put it like {HEX()} or (HEX())?
crashes either way
return { vars = { self.config.extra.max, suit_text}, colours = {HEX('3dad2f')} } what do you mean colours is a nil valueeeeee
Odd. Does it crash with G.C.MULT?
And, I was talking about something like colours = {(HEX('3dad2f'))}, just in case.
Is it? I swear it was separate, but I am still quite rusty to be completely fair.
100% my fault for misleading you if that's it.
Does anyone know what the different contexts that an enhancement's calculate function will be called in?
would this patch work?
i did something and now my button is missing
also my text is in the center? instead of the top
try printing them and you'll see
should be all the ones that playing cards are called in
Don't see any obvious issues with it. Why are you multi-line matching though?
trying to replace one block of code with another
not sure, but pressing G+A when debug mode is enabled might help you understand
oh my god!!! the sub ispector!!!
the button is outside of your root element
is there any reason why you're not replace the if-statement itself?
or rather, outside of the nodes of the root element
didn't think of that ngl
it also shouldnt be in an object node
fixed it
a toggle is not an object
but why is the button at the top?
because its in a container thats aligned to the top
the align property tells it how to align the things inside
ok i was trying to do something else but this is better
also do you like the spooky screen
been getting this error for an hour 😭
did you go to functions/state_events.lua
and line 713
how do i make the button do things?
can you show me what your patch looks like now?
label = "Disable Rune Downsides..?",
ref_table = TGTMButton.config_file,
ref_value = "CursedRunes",
callback = function(_set_toggle)
config.TGTMCURSEDRUNES = not config.TGTMCURSEDRUNES
end
}),```is it like this
here are the patches
you don't need the callback
think about the order of the if-statement in your last patch, there's an issue there
it just works with the ref_values?
and your ref_table is wrong
is it just config?
it's wherever you've saved oyur config
pretty sure config isn't a variable that's normally defined, so... maybe?
this one
that's the one
though calling it config seems unwise
I tend to use ModName.config
tell this to yourself!!!!
is it something to do with the and after if eval.seals?
past self is big noob
past?
yes I wrote this months ago
ish. Do you understand what if next(eval) does?
returns the first index, along with its value, of eval?
if eval is empty than next(eval) returns nil
i dont need this right?
no
Correct. So why are we not checking the output of next(eval) against anything?
curse you mathisfun and your wierd and efficient code!!!!!!
thats a good question LMAO
is any of this nessesary?
if next(eval) == eval.seals?
no
curse you mathisfun!!!!!!!!
my general advice is to not look at Math's mods if you don't know what you're doing
Math's mods are very confusing and definitely not standard nor easily readable
No no, I'm not asking you to change anything, I'm asking you why the original (unpatched) code doesn't compare the output of next(eval) with anything
oh i'm not sure, that's what localthunk wrote
Could make a whole story mode with selection boxes like that
Well, good thing I didn't either. So I googled it! This is what I found
Lua's
next()function returns the next index of the said table and its value associated with the table.
- When the next() function is called with nil value as the second argument, next returns an initial index and the associated value.
- When the next() function is called with the last index of the table or with nil in the empty table, Lua next will return nil.
- If the second argument ‘index’ is not present, then next() functions interpret it to be nil.
- User can use next(t) to check if the table is empty.
- The order in which the indices are enumerated is not that specific, also for numeric indices.
- For traversing table in numeric order, user can use numeric for or ipairs function.
- If next() function gives undefined, during traversing, the user can assign any value to any nonexistent fields of the table.
- User can clear out or modify the existing fields in the table.
thanks discord formatting
really appreciate it
now this one stood out to me
User can use next(t) to check if the table is empty.
so basically
i patched in a non-joker/seal source for repetitions
and the next(eval) check brokey
almost
right now the if statement does this:
if (eval.seal) and (eval is not empty) and ...
which doesn't make a lot of sense
try checking if eval is not empty before you check for eval.seal
so if next(eval) and eval.seals and ...
it at least makes more sense to me that way yeah
Lets go. i did UI, i did consumables!! im on fire
whats next? shaders!!!
(im not doing shaders)
seems to be the same error
indexing nil with seals
Ugh, okay. Was hoping the order change would magically fix it even though the error didn't seem to indicate it would.
Do you know how to access the lovely dump?
not that i know of
it's just at mods/lovely/dump
find the functions/statevents.lua line that it errors on
it errors on a line that counts repetitions in the scoring hand
just show the line
hmm......
is that even around a line you patch? 🤔
how do i fix this
had the wrong line but
well your patch is actually in 2 locations because you only match the if-statement but you probably want that anyway
sounds like the problem is on the lua side somewhere?
Depends. WTF is the context here
return {vars = {(G.TGTMCURSEDRUNES and ("Gain {C:red}".. card.ability.extra.discards .. "{} discards")) or ("Gain {C:red}".. (card.ability.extra.discards * 2) .. "{} discards")}}
end,```
text = {"#1#"}
doesn't work like that
i think i need to patch in every instance of when repetition is calculated
should i split my lovely patches up into different files lol
you can use main_start, main_end or key instead, see https://github.com/Steamopollys/Steamodded/wiki/05.-SMODS.Center#all-centers
hmmm, what are you actually trying to do? 🤔
They're trying to make a sticker apply repetitions like seals and jokers.
add a gemstone (technically a sticker) that replays the card its attached to 1 time
oh were you the skyblock guy
Actually, question, why not make it a seal?
Nevermind, because it's also supposed to apply to jokers, right?
because i want the gemstones to not interfer with any current modification
and seals can't be applied to jokers
do i have to make a english.txt to use key?
i made the runes, now i have to MAKE the runes.
you'd have to make a localization file for key yes
forcing me to make my mod better 😔
Ah. Sounds like a lot of lovely patching 😅
I'm assuming you (accidentally?) mess with the seal code somewhere, either with your other lovely patches or with lua code
where is the localization wiki
yeah that one might interfere with seals too haha
Nowhere! Look at what the base game and other mods do >:)
i cant put down the cryptid mod....
is there a mod that adds the star suit?
sorry had to leave for a sec, but here's what the dump shows
return {
descriptions = {
Runes = {
r_runes_laguz = {
"Gain {C:red}#1#{} discards"
},
r_runes_Claguz = {
"Gain {C:red}#1#{} discards"
},
r_runes_dagaz = {
"{C:red}Disable{} boss blind", "{C:attention}No reward money from blind{} "
},
r_runes_Cdagaz = {
"{C:red}Disable{} boss blind", "{C:attention}No reward money from blind{} "
}
}
}
}```This is a good en-us.lua?
example, not done
https://discord.com/channels/1116389027176787968/1210728178201526373 has a star suit?
if you send a variable w/ loc_vars, and there isnt a #1#, is that fine?
yeah that's fine
Hmm, weird. Seems fine to me
Replace the loc_txt entry. You should be able to check out my cardsleeves mod for localization on custom objects
i think whats happening is that every time next(eval) is ran (and stickers is apart of it) and a non-nil value is returned, the game assumes seals/jokers is a property of eval
so i gotta patch where i need to and put either next(eval) and eval.seals and .. or eval.jokers
?
honestly I'm not even sure that part does anything
It doesn't
cheers, I'll remove it then
how do i use different localization for name vs desc?
oh right, I missed that you didn't have that
look at the cardsleeves/localization/en-us.lua file
yeah uhhhhhh thats gonna be a challenge
if next(eval) then appears in both the seal checks and joker checks
so idek how i am supposed to replace them all
oh yeah that might be it
"r_rune_!!NAME!!" .. TGTMConsumables.config.CursedRunes and "C" this appends a C only when TGTMConsumables.config.CursedRunes right
will it append false??
TGTMConsumables.config.CursedRunes and "C" or "" to be safe
try it out and see
nope
so what's the issue?
attempt to concatinate boolean
which means the error is talking about what part of the code?
"r_rune_laguz" .. TGTMConsumables.config.CursedRunes and "C" or "" this also doesnt work
because it evaluates to ("r_rune_laguz" .. TGTMConsumables.config.CursedRunes) and "C" or ""
same reason
oh
wow
parenthisis time
uhm
this is what key = is
did i do something wrong
How do you get the r at the start?
I know base game, if it it's a consumable, it has c_whatever, doesn't matter what set, may possibly be applying that and missing it.
depends on your class_prefix
thats a thing?
depends on what class you're subclassing
consumabletype?
@tepid crow good news, patched out all of the next(eval); no more crashes
now i gotta add the repetition for stickers in all of the places
how do i do it?
Ugh. Try printing your class_prefix anyway to see what it is
?
no your consumable type's class_prefix
how do i get that?
is there documentation anywhere for all the config options for SMODS.Back and like how to apply them properly and such? im wanting to know all the options im working with with deck creation, especially with like maybe starting with jokers with various effects like eternal or negative n such on them
idk, I've never used custom consumables before
not sure, i would recommend looking at mods that add decks (ex. cryptid) and see what they have
@tepid crow its done
in total it took 10 patches
hey that's pretty good
Nice job.
now time to make sure everything is functional so i can finally relase the next version
Does anyone know the best way to force a suit of a card with an enhancement? For example, when the playing card is generated, if its enhancement forces a suit, its suit gets changed.
what is a good consumable mod?
# Force Suit
[[patches]]
[patches.pattern]
target = "functions/common_events.lua"
pattern = "local card = Card(_area.T.x, _area.T.y, G.CARD_W, G.CARD_H, card_init.front, card_init.center, {playing_card = G.playing_card})"
position = "after"
payload = '''
if card_init.center.force_suit then
SMODS.change_base(card, card_init.center.force_suit)
end
'''
match_indent = true```This is my currrent attempt
sadly i cant use cryptid because it uses 0.9.8 of steamodded, but i bet i can find some other decks or something from another mod, just gotta keep looking
cryptid doesnt use 0.9.8?
what???
look at top left
what is that doing there
????
why is that there?????
someone help me
debug mod
why does that show there
so... name goes to the title screen??? and i dont know why
the only version i could find did
i guess i have to look harder
wouldnt this?
what do i do differently?
idr
you are my only hope!!!!
did you define a generate_ui
a what
okay then
how do i do that
Whenever I try to commit something in vs to my github page it doesnt work and just loads forever
its been like this for a few minutes
It’s a function you can override to take full control of your card’s UI pop up
Lol just found out that the game has a method for printing out tables as strings
Probably used for the save thing
but probably handy for someone nonetheless
actually it's not used anywhere
so it actually probably is used for debug printing
doesn't play nice with massive tables
theres also aprint which makes a box over the deck with info (but only works with debug mode enabled)
thought smods defined that
oh wait no smods defines inspect
tprint is nice to use
Just some of the tables are a pain in the arse for duplicated information
Executing functions in debug +!!!!
how'd you magically summon the last thing you typed into the console
ive wasted several minutes of my life forgetting to type "eval"
You tried arrow up key?
how do i make a generate ui?
Did it actually worked? It was just a guess lol
no im not even home rn
smods has documentation on this
Ah
is it just me or do i not get console logs
probably the dims modpack fork
all i have is steamodded, lovely, debug plus, and my mod
im not sure what this means
ye install debugplus dev version
if you don't mind, where's that at?
awesome, thanks
i said that incase you had one, which you didn't so that was not the issue to the floating text issue
oh ok
it's usually due to the text node not having a proper parent node
is my localization correct?
here, your entire description didn't show, so there's a problem with your localizaton i believe
no, consumables have the c_ prefix
im only looking at the first one rn
my mod prefix is TGTM
let me test something
c_TGTM_<consumable_key>
return {vars = {AmtDisc}, key = "laguz"} in my loc_vars
this is correct right?
am i supposed to have key in loc_vars?
for localization?
no
loc_vars = function(self, info_quque, desc_nodes)
return { vars = { self.key } }
end
self.key?
i send the key in the vars?
no
thats not what this says
what is this then?
an example of the loc_vars function
using self.key is an example of how to send variables
if you give me a second i can show my code
@weary jungle here's a sample
ok i did
is this what your localization file looks like right now?
the keys after laguz are wrong
in the localization its supposed to go <type prefix>_<mod prefix>_<consumable key>
yeah thats the one i found, its packaged with steamodded 0.9.8
the manifest file inside the steamodded folder packaged with it literally says its version 0.9.8
,, which apparently the 1.0 pre-release also says
if i wanted an enhancement to do something when discardded
i guess i am wrong then
Which key?
Are we talking playing cards, consumables, jokers, boosters, or vouchers?
the key at the botto,
Oh get its center
so card.center.key?
didnt work, is it card.center.config.key?
whats the best way to go about adding jokers to decks by default? as well as adding editions (specifically negative) and eternal to them?
You can use the function add_joker in apply
wondering how this tallies up to 7 when i only have 6 slots in total
okay, thank you!
ok it did work i was just dumb
debug not working as well
haven't been able to get sendDebugMessage to work ever
check your steamodded settings in game
make sure the logging is set to debug
figured out why i'm stupid lol
its because the card's tally counter had gemslot in it, so i changed it to gem_slot_tally
incredible
awesome
?
I have one I can send you later
You need to check the edition, not the center
one of my jokers tests for (v.edition and v.edition.negative)
like this?
let me try this
thank you, i appreciate it :>
that will not work
Any lua you want
Its just on the Dev branch
i didnt relicre
question, why is it that when you're modifying a global using eval, you have to do "_G.foo = bar" as opposed to a typical "foo = bar"
Cause the eval commands global object is actually a different object for me to be able to inject the dp variablw into it without making it a global
definitely understood that yeah 
There might be a better way to do this but I don't know what it would be
Also it's kinda nice you can add fine variables that aren't global without clobbering the globals
you can't just set it as a local?
Well I don't know how to control loclas in others code I can't easily inject it into the eval code cause it wouldn't be able to reference it and it also would screw up with ljne numbers (which isn't a big deal for eval but I still don't like doing it)
i was thinking debug.setupvalue before calling the function but I think that might only work after calling it?
Idk I could take a look
Hey I've been having this really weird issue where when I try to destroy a card in pre_discard (cause enhancements don't trigger at discard context) a weird ghost version of the card stays in the deck. Any ideas of how I could get around this? Thanks!
Here's the calculate function of the enhancement
if context.pre_discard then
if G.GAME.current_round.discards_used <= 0 and #context.full_hand == 1 then
G.E_MANAGER:add_event(Event({
func = function()
destroy_card(context.full_hand[1],true)
return true
end
}))
card_eval_status_text(card, 'extra', nil, nil, nil, {message = localize("mtg_sacrifice_ex"), colour = G.ARGS.LOC_COLOURS.club})
end
end
end```
And here's destroy_card
```function destroy_card(card, noise)
if card.ability.name == 'Glass Card' then
card:shatter()
else
card:start_dissolve(nil, noise)
end
end```
oh the old ghost card
i dont know how to fix it
did you remove the card from the hand?
maybe add a table.remove(G.hand, something)
i dont know what the something would be
I'm not too familiar with ghost cards but I suspect it's being destroyed then being moved to the discard area causing the ghost card. I would take a look at trading card to see how it works
So trading card returns if the card is being destroyed, which enhancements can't return
I've just modified the effect to get around the issue
trading card isn't magic, that return does something that destroys the card properly
Well it's that trading card is triggered during context.discard, not context.pre_discard
enhancements in hand aren't triggered during context.discard
The destruction of the card occurs after context.discard, and I'm assuming that by destroying it at context.pre_discard, there's some issues being caused where the card is put into the discard pile while it's being destroyed
why would enhancements not have that context 🤔
Might be only called for jokers
Pre discard would be used for like golden seal
Wait no thats on play isn't it
Purple seal
Managed to fix the ghost card
[[patches]]
[patches.pattern]
target = "functions/state_events.lua"
pattern = "local cards = {}"
position = "before"
payload = '''
highlighted_count = math.min(#G.hand.highlighted, G.discard.config.card_limit - #G.play.cards)
'''
match_indent = true```
The problem was when I was removing the card during pre_discard, the code doesn't account for the change, so we have to redo the highlighted_count calculation
look at this photograph
he's sitting weird
Believe this is the right channel for a question like this; I'm working with a friend on making just custom card icons for the PC version of the game, swapping out the face cards basically, and was wondering if anyone knew or could tell me where to look for getting the requirements for cards in game (i.e dimensions, etc.)
https://discord.com/channels/1116389027176787968/1250386587691388989
dimensions are somewhere in here (jokers and playing cards are the same size)
Hello guys, mod beginner here. Is it possible to patch the localization files using Lovely?
the 1x export link is gone NOOO
Do high contrast cards just need a separate sprite?
Yes
got it. Thanks!
should be, what are you trying to acomplish?
unless its changed in newest lovely, you can't
You can indirectly by patching the loading but not by just patching the localization file
I think SMODS has api's to modify localization
how would i go about making a joker added to a deck by default negative?
nevermind, figured it out myself
is it possible to have two separate next properties on a Rank? For instance, if I wanted an Ace to have a next for 2, and then if this other rank called "Apostle" was in the deck, another next for that? So that a Straight with an Ace and an Apostle in the deck can be made either like 'J, Q, K, A, T' or 'T, A, 2, 3, 4'?
Or is there an easier way to do that
I'm not necessarily looking for multi ranks, if that's what I understand them to be. I just need some way for Aces to point to a 2 in general, but if a high straight is played, somehow treat the Apostle as the Aces 'next' rank
Would overriding something in the Straight and Straight Flush calculations be able to accomplish this?
So for example, when a hand is being checked for the hand type when cards are highlighted in hand, I want some code to run that checks if an Apostle is in those highlighted cards. If one is, do a manual check for if the specific ranks 'J, Q, K, A, T' are in those highlighted cards. If so, I want to return the fact that it is a Straight
If that makes sense
I'm working on porting old decks from the old "deck creator" mod that I made myself, and so I'm gonna be asking a lot of questions here, probably in batches
however this question will not be in a batch
- How would I go about adding a voucher to a deck?
Next is a table so I think you can just insert the other rnam into it
Not sure how it beaves in that case
I remember there was some talk about how to calculate Straights with an arbitrary graph
I think I remember DFS being suggested
Or a DFS-based algorithm since you can stop when you first find a Straight
check what base game does imo
when it comes to decks, base game does things a little differentlyyy
at least from what i can tell
how would i go about increasing the size of arcana packs?
Lovely injections probably
i should probably specify that i mean for a specific deck lmao
Yeah you most likely need to add an injection into card to modify booster pack behavior
Here's how I did my booster pack size increasing deck, you'll probably want to add a check for specifically arcana, but just for reference, here's the code:
SMODS.Back{
key = 'binah',
loc_txt = {
name = 'Book of Binah',
text = {'{C:attention}+1{} Booster Pack {C:attention}Size','{C:attention}+1{} Booster Pack {C:attention}Choice'}
},
atlas = 'Decks',
pos = {x = 1, y = 0},
unlocked = true,
discovered = true,
trigger_effect = function(self, args)
if args.context == 'booster' then
G.GAME.pack_size = G.GAME.pack_size + 1
G.GAME.pack_choices = G.GAME.pack_choices + 1
end
if args.context == 'booster2' then
local size = args.size + 1
return(size)
end
end
}
And here's the lovely patches I needed:
[manifest]
version = "1.0.0"
dump_lua = true
priority = 0
[[patches]]
[patches.pattern]
target = "card.lua"
pattern = "G.GAME.pack_choices = self.config.center.config.choose or 1"
position = "after"
payload = "G.GAME.selected_back:trigger_effect({context = 'booster'})"
match_indent = true
[[patches]]
[patches.pattern]
target = "card.lua"
pattern = "local _size = self.ability.extra"
position = "after"
payload = "_size = (G.GAME.selected_back:trigger_effect({context = 'booster2', size = _size}) or _size)"
match_indent = true
Cardsleeves' ghost and zodiac stacked sleeve effect do this, but I'm not sure if it's "best practice". Let me know if you find a better way
thank you all for the help!
you'll also want to avoid this: #💻・modding-dev message
here's the fix I used: fix, hook
is this code usable in SMODS, or do i need to change something about it for it to work?
(apart from the obvious self into card)
is this code usable in SMODS
I don't even understand this question
anything that thunk does can be done in smods
you can look at https://github.com/Steamopollys/Steamodded/blob/main/example_mods/Mods/ExampleJokersMod/ModdedVanilla.lua to see how smods does joker stuff if that's what you mean
should i remove the streak in the middle?
yeah no i have no clue what i'm doing wrong, im just trying to make aces of spades give x2 mult this shouldn't make me rage like it is doing rn
or have it go behind the gem, if that's possible
is there a context for just the end of hand? i couldnt find one specifically, but i might just be stupid
I kinda meant the line/streak, but I guess this works too
I did this exactly for testing purposes, but instead of like actually increasing the amount of cards in the pack by 2 (what i set it to) it just made the cards more spaced out weirdly
what context should i put to make sure it happens once before the hand starts scoring?
without any context it triggers 4 times, but with context.individual or context.before it never triggers
well, for starters, card.area == G.play should be context.cardarea == G.play
it works!!!
nice
heres a video of it, i dont know whats happening here. theoretically the size should be being increased??? i dont know
figured it out, just had 2 calculates and balatro didnt like it so it nuked the first one
Change text. Here's what I tried:
[[patches]]
[patches.pattern]
target = 'localization/en-us.lua'
pattern = '"-1 Hand Size"'
position = 'at'
payload = '"-2 Hand Size"'
match_indent = true
Initialization was complete, but patch isn't applied.
you have to match the exact line
so it would be something like payload = '"-1 Hand Size",'
localization patches don't work
well I think they technically work if you put the full contents of the localization file as the target
calculate = function(self, card, context)
if context.cardarea == G.play and context.repetition and not context.repetition_only then
if card.ability.extra.repetitions > 0 then
return {
message = localize('k_again_ex'),
repetitions = card.ability.extra.repetitions,
card = card
}
end
end
if context.end_of_round and not context.blueprint then
if pseudorandom('Uranium-235') < G.GAME.probabilities.normal/card.ability.extra.odds then
card.ability.extra.repetitions = card.ability.extra.repetitions - card.ability.extra.loss
return{
message = "Half-lifed!",
colour = G.C.RED,
card = card
}
end
end
if context.end_of_round and not context.repetition and not context.game_over and not context.blueprint then
if card.ability.extra.repetitions <= 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
-- This part destroys the card.
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 = "Decayed!",
}
end
end
end
}
i've got this hefty chunk of code, and i just cannot get it to work - when playing/discarding, it immediantly deletes itself and playes the "Decayed!" thing, for every card and when you win the blind, it throws an error
i'll quickly grab it, but its something to do with for
the idea of the joker is that it has X amount of retriggers, and has a 1/2 chance to lose 1 retrigger every hand (i couldnt figure out how to make it every hand, so right now its just end of round)
im not sure exactly whats wrong with it, its my first time working with chance and deleting a card 😭
this is the error that occurs when winning a blind
hm,,,
you forgot all the not repetition check for the half lifed end_of_round check
and i can't check the crash but i'll just assume it's because it's trying to return a message after the card has been destroyed (via events)
is that just not context.repetition or not context.repetition and not context.reptition_only?
which should be fixed after you add the check ^^^^
just not context.repetition works
i haven't seen context.repetition_only
its to do with seals, apparently
idk though 😭
i do have a question, is there a context to make this work after a hand is played, or is it condemned to only being at the end of a round?
context.after?
the game does not have a context for start of hand surprisingly, but context.after works for end of hand
wait seriously?
what abt context.before?
it works! it lost 2, which is unintended, but it works! ~~it didnt show a message raisedcateyebrow~2 ~~
that's before scoring
also epic fakenitro fail (atleast on vendetta)
😭
Vitro (real)
would their be any reason for this to not show a message when it runs? raisedcateyebrow~2
it.. showed the half life message when it was destroyed? lmao
context.after might not support a message return
wait what lmao
try using card_eval_status_text instead of returning the message
sure, one mo
it lost 1 retrigger while playing a hand, and showed the message afterwards? whuhhhh
like i mean, close enough to what i wanted
(this isnt even using eval)
oh yea it goes joker_main > after > scoring animation
oh, wait, no im just stupid, i forgot balatro doesnt update in the way you think it would 😭
yuh yuh
it works!
just wrap your things in an after event
im sorry, i dont know what that is 😭 (also if its just to fix the number thing, tis' all good)
When you run code, it gets executed immediately in the order it is. In order to have a delayed effect, you can create an Event, where it’s put into an Event Queue and the Event Manager handles its execution. (In Balatro.)
This handles both game rules and animations in Balatro, including both simultaneously, when something in-game causes an update in some datum and an accompanying animation.
Since it’s used for game rules, sometimes you need to use an Event or otherwise the effect won’t work as intended
Because it’s applied immediately instead of in-sequence
It’s also necessary to account for it even if it’s applied immediately
For example, there’s a money and consumable buffer that keeps track of the “true” numbers before scoring Events start executing
This avoids your Consumeables overflowing, for example
Animation-wise, that’s how vibrating DNA works
thats actually very good to know, never knew
second one
yippee
i've got one more hiccup until this thing works perfectly - when it reaches 0, it doesnt delete itself and instead just.. keeps counting down 😭
it looks fine to me, but making events is still new to me
thats sick
to my knowledge, this is the first time this effect has been achieved at this level?
How does it work with more than one wild card?
it picks the highest possible hand
though i believe it favors left over right?
*it also doesnt form like, two pair when its three cards
we spent a while trying to debug that
Did you reuse the Shortcut code?
for straights?
I think some of it could’ve been reused
The main extension is that it would need to account for skips greater than 1
had to add a lot more checks to make sure that it isnt using the wild card when there's a regular card that could replace it
it does
So an ace, a ten, and three wild cards would give the straight?
can someone tell me why it doesnt say anything?
its SUPPOSED to make the blind say something (this should work normally), and it works for the default fallback when the blind doesn't have any localization, but when it does have localization it just doesnt work?
i can send the code if you'd like to see
how difficult would it be to add a new tab for a new set of cards? essentially making a new planet card tab on the collection
as in new planet cards or a new consumable type
new consumable type completelt
planet cards was an example, its the first thing i thought of 😭
ih wait really? sick
just need to learn how to make consumables then 😭
next question, is there a way to change something about an entire deck of cards? i specifically want to change every card with a specific rank, in the entire deck, no matter what
for _, v in ipairs(G.deck.cards) do
-- do stuff
end
Collecter's Cards did it first.
is it possible to make specific cards trigger music
Yes, see Jimball in Cryptid
ahh fair point
where's the mod if i may ask?
im kind of interested in seeing how it was implemented
is there a way to get all cards in a played hand? regardless if they score or not
Loop through G.play.cards
Some contexts send it as context.full_hand too
,,,hm
this is a weird edge case
okay, so weird question related to the decks im making:
how would i go about making planet cards (and any form of leveling) trigger twice?
Hook the level up function so it asks to level up twice instead of once
Holy Shit I Am So Fucking Stupid™️
i forgot that its supposed to be the fucking key 😭
i've spent like 2 hours trying to fix this
does anyone know where the level up function is at? having trouble finding it lol
unless i am misunderstanding something fundementally here
im very new to this .w.
i just took the code from burnt joker lol
yeah, i found how to make something level up twice, now i just need to make it deck specific
speaking of, i might as well ask, how would i check what the current deck is? (specifically for the purposes of an if-then checking what the deck is)
This is what I do https://github.com/larswijn/CardSleeves/blob/main/CardSleeves.lua#L358
But you probably only need the G.GAME.selected_back
(the other 2 are during deck selection)
[patches.pattern]
target = "card.lua"
pattern = "level_up_hand(used_tarot, self.ability.consumeable.hand_type)"
position = "after"
payload = """
if G.GAME.selected_back == "vacuum" then
level_up_hand(used_tarot, self.ability.consumeable.hand_type)
end
"""
match_indent = true```
this, *should* work to duplicate the level up right? im trying it and its not working and im not sure why (the key for my deck is "vacuum" by the way, im assuming the key goes after the equals?)
the full key is "b_modprefix_vacuum"
ohhh i see okay, thank you
I also believe you need everything after the G.GAME too, check the full return of the function I linked
yep, that did the trick! many thanks
ill inevitably be back with more questions relatively soon
hello, does anyone know how to get deck config variables in lovely's patches?
nvm i figured it out
did something change with the newest update for calling the amount of options for the deck customizations? am wondering cause I am getting an error in my code when trying to call the number of deck customizations there are
does anyone have any idea of how id go about getting space joker to level up twice? it doesnt use the same level up function that other level ups use
how can i remove this bit of text from specific cards?
i want to make a special card that will have the properties of a wild card without actually being any suit
in this context the indication of the suit is useless and i want to remove it
oh btw haow can i put text under the +2 chips?
still needing help on this one, but another question has popped up:
how would i, for the player using a certain deck, give them a "Hanged Man" after every large and boss blind?
Having a very strange crash, all I'm trying to do is add Omen Globe to a deck, as shown here in the deck's code:
name = "Undead Deck",
key = "undead",
pos = {x = 6, y = 2},
config = { consumables = { 'c_ankh' }, vouchers = { "v_omen globe" } },
loc_txt = {
name = "Undead Deck",
text = {
"Start with {C:spectral}Ankh{}",
"Start with {C:tarot}Omen Globe{}"
}
},
loc_vars = function(self)
return { vars = { }}
end,
atlas = "NegEnhancers"
}```
I tried giving it crystal ball too to see if that fixed the problem, but nothing happened. Anyone know what's going on here?
You have a space instead of an underscore in your voucher key
basically
this
thank you!
it's like forgetting a semicolon, it happens to the best of us
why does this not work
Because you're trying to return from global MC, not a table called MC located in global G.
btw would this work or how can i put thsi into the table
yo if you're gonna do screenshots like that just copy paste
label text as "ERROR"
this is neat
its been like this for 30 minutes when im trying to publish it to my github
getting a strange error with this deck below, it only happens when i add the voucher config in. none of my other decks configured to have vouchers do this, so i have no clue whats happening here lmao
name = "Repetition Deck",
key = "Repetition",
pos = {x = 2, y = 4},
apply = function(self)
G.E_MANAGER:add_event(Event({
func = function()
add_joker("j_ring_master", "negative", true, true)
return true
end
}))
end,
config = {vouchers = { "v_reroll_surplus" } },
loc_txt = {
name = "Repetition Deck",
text = {
"Start with {C:dark_edition}Permanent{} Showman",
"Start with Reroll Surplus"
}
},
loc_vars = function(self)
return { vars = { }}
end,
atlas = "NegEnhancers"
}```