#💻・modding-dev
1 messages · Page 96 of 1
all lovely does is it compares the path provided to it to the target path
if they match then it applies the patch
you mean my PR?
so yeah, I was talking about something else
larswijns question
have you confirmed that your target patch matches the path of the file within the game's executable?
does lovely not check that?
also happened to me so i can confirm
.
I don't think lovely does a sanity check on the path you provide in target
but can't recreate rn since im bed
if it fails it fails silently
mostly because it doesn't have a way of knowing what is and isn't a valid path
for the same reason that lovely can't know when it's done applying all of the patches
yeah, it exists

moMent
is src/ comprised of files that you dumped from the game executable?
no, src is a folder within the game executable
I dont think you should include that
hm
it's like
main.lua
other_file.lua
src/
menu/
...
what game is this?
oh
duh
🤣
if it's free then I would like a link so I can poke around at it
it's in playtest lol
where's the src/ or menu/ directory?
if you poke around a bit, the editor events are 3 folders deep
different game than theirs
that's... not the game im modding
i cant share source
I don't get the joke
the joke is that for some reason, reading comprehension has always sucked in any discord related to balatro
you missed the joke
I can take a look at beatblock
even THIS (imo the most basic lovely patch) technically gets recognized by lovely (it throws errors when necesairy) but i dont see the print!:
[manifest]
version = "0.0.1"
dump_lua = true
priority = 0
[[patches]]
[patches.pattern]
target = 'main.lua'
pattern = "function love.load()"
position = 'after'
payload = """
print("this is a test for lovely!")
"""
match_indent = true
that's odd. the print appears in the dump, right?
there IS no dump!
uhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
does io.write work at least
does lovely print even go through io.write or does it use the C lib for that
it won't create the dump directory if no patches were applied
oh there's no dump
WAIT...
that makes sense 😭
this might be a good clue
there's tprint for tables
thanke
would i be correct in saying that you're meant to use ''' not """ for multilines? do both work?
i imagine if not it'd panic
so probably?
i think it's """ for multilines in toml
both work-ish in my experience
ive always used '''
work-ish is truly the lovely experience
real ones use print(inspect())
what does that do?
WAIT A MINUTE, GOOD CLUE:
even if i change it to nonsense, the game starts up!
[manifest]
version = "0.0.1"
dump_lua = true
priority = 0
[[patches]]
[patches.pattern]
target = 'main.lua'
pattern = "function totally_real_100precent_love.load()"
position = 'after'
payload = """
print("test!")
"""
match_indent = true```
just an smods alternative to tprint that uses healthier values
there's also inspectDepth, and jenlib has an infinite depth recursion avoidance one
are my values deseased? (what does healthier values mean)
so true
inspect sucks, use inspectDepth
im gonna use tprint
inspectDepth also sucks use the jenlib one clearly
already made my own 
you can just joker.ability.debuff = true rigt
this is real
actually didn't you help me rewrite mine or was that someone else
oh nope that was Djynasty
i don't believe i did
but i wrote my own (aka modified inspectDepth) for #💻・modding-dev message
you did reply to my tprint though
this is super weird
no error or anything from lovely?
(when the game doesn't start)
make the patch file entirely nonsense and see if it panics
which means that either my patch is broken, lovely is broken or the game defines totally_real_100precent_love (which i know is not true)
i mean it would just say "patch not found, proceeding"
in console that is
...which it dosent!
INFO - [♥] Lovely 0.6.0
INFO - [♥] Game directory is at "C:\\Program Files (x86)\\Steam\\steamapps\\common\\Switchblade"
INFO - [♥] Writing logs to "C:\\Users\\ilayl\\AppData\\Roaming\\switchblade\\Mods\\lovely\\log"
INFO - [♥] Using mod directory at "C:\\Users\\ilayl\\AppData\\Roaming\\switchblade\\Mods"
INFO - [♥] Initialization complete in 42ms
okay, ima try and update
only if the patch target was valid
ah true
yeah I figured the same thing
did this before with balatro to see if anything interesting was being loaded
just the normal lovely output
INFO - [♥] Lovely 0.6.0
INFO - [♥] Game directory is at "C:\\Program Files (x86)\\Steam\\steamapps\\common\\Switchblade"
INFO - [♥] Writing logs to "C:\\Users\\ilayl\\AppData\\Roaming\\switchblade\\Mods\\lovely\\log"
INFO - [♥] Using mod directory at "C:\\Users\\ilayl\\AppData\\Roaming\\switchblade\\Mods"
INFO - [♥] Initialization complete in 7ms
aaaand try this one
anti-virus go brrrr
Discord whenever I dare to send a zip file
hey sorry to be a bother
i tried running that end of round context through an individual context
and now they proc less often but still more than once
and still, normal lovely output
INFO - [♥] Lovely 0.6.0
INFO - [♥] Game directory is at "C:\\Program Files (x86)\\Steam\\steamapps\\common\\Switchblade"
INFO - [♥] Writing logs to "C:\\Users\\ilayl\\AppData\\Roaming\\switchblade\\Mods\\lovely\\log"
INFO - [♥] Using mod directory at "C:\\Users\\ilayl\\AppData\\Roaming\\switchblade\\Mods"
INFO - [♥] Initialization complete in 6ms
what's the full if-statement?
elseif context.end_of_round then
if context.individual and not context.blueprint then
if self.ability.name == 'Perpetual Stew' then
is this the right order and way to check individual
Do I need to go and compile lovely?
try context.end_of_round and not context.repetition and not context.game_over and not context.blueprint and not context.individual?
thank you i will try that
if not context.individual
you are using if context.individual
good point lol
yeah i didnt know if it was supposed to be with or against
my bad gang
but that did it
I even wrote it into the context guide 😭
on the steamodded wiki
why is it on 2 pages
@vivid glade does this one work?
ima try
What’s your type definition?
oh is my lovely only work on my system
it was about half the size of methrul's
"it works on my machine" moment
please mount your machine to the rack
ok see if this works
I might have just made the most cursed change to my machine to get htis to work
oh god what did bro do
mine's release where meth's might be a debug build
perchance
so it starts up, but then dosent do anything special
send logs
apply_buffer_patches isn't being called
which seems to imply that the hooked function is never called
different lua version?
INFO - [♥] Lovely 0.6.0
INFO - [♥] Game directory is at "C:\\Program Files (x86)\\Steam\\steamapps\\common\\Switchblade"
INFO - [♥] Writing logs to "C:\\Users\\ilayl\\AppData\\Roaming\\switchblade\\Mods\\lovely\\log"
INFO - [♥] Using mod directory at "C:\\Users\\ilayl\\AppData\\Roaming\\switchblade\\Mods"
INFO - [♥] Initialization complete in 4ms
same old same old
yes
I've also been trying to lovely patch beatblock files and while most work and create a dump, some do not for some reason. I don't see any pattern in whether it'll dump or not either
is it patching but not dumping?
take the build I just send (or probably meth's) and see if the path you're looking for is there
it is not
wha? but this should be ok right?
this is the only thing it's showing, same old same old
INFO - [♥] Lovely 0.6.0
INFO - [♥] Game directory is at "C:\\Program Files (x86)\\Steam\\steamapps\\common\\Switchblade"
INFO - [♥] Writing logs to "C:\\Users\\ilayl\\AppData\\Roaming\\switchblade\\Mods\\lovely\\log"
INFO - [♥] Using mod directory at "C:\\Users\\ilayl\\AppData\\Roaming\\switchblade\\Mods"
INFO - [♥] Initialization complete in 4ms
apparently not
I was talking to laswijn
What rank and suit do the cards that marble joker produces have?
Oh wait, does lovely not patch files that are not loaded? 🤔
because that would probably explain it
you have a loc_vars reference and no loc_vars function?
SMODS.Voucher instead of SMODS.Vouchers
?
@rough furnace maybe try to make it always dump (even if nothing was patched)?
yes. It hooks the method for loading a buffer and then applies the patches on it
oh that too
No this is supposed to print the name of the buffer as soon as it starts handling it. If it's not priting the names, it's not hooking them
idk. wanted to experiment, but didn't even load the voucher apperently
i know, which is why looking at the dump is interesting
well there wouldn't be anything to dump cause it's not hooking properly
@vivid glade if you can manually modify a file to get it show some text somehow, can you get the result of string.format("Version %d.%d.%d - %s", love.getVersion())
11.5 - mysterious mysteries
Ah yeah that would actually explain every failing patch. Didn't know that's how lovely worked, neat.
you probably shouldn't be using 0.9.8 code btw
i'm just building off of someone's 8 month old texture pack template so i don't really know what that means
what should the code look like?
Ugh there's no docs for it yet. Uhhh some example mods would be
https://github.com/OppositeWolf770/ColoredTarots/blob/main/ColoredTarots.lua
https://github.com/Steamopollys/Steamodded/blob/main/example_mods/Mods/NegateTexturePack/NegateTexturePack.lua
what does prefix_config do?
Use Malverk instead #shilling
malverk is ungoogleable unfortunately
A Balatro mod that handles texture packs. Contribute to Eremel/Malverk development by creating an account on GitHub.
i just realized how much whitespace i have here? what was i doing??
so like this?
yurrrp
rip 🙏 I tried to give 3 voucher the same requirement 😭
is there a consistent cause for
card.lua:254 attempt to index local variable center with nil value
where i can be like "oh that means i did ___ wrong"
damn now i gotta launch the game
that doesn't seem like a real error
yeah i wrote it from memory its worded poorly
attempt to index a nil value and attempt to index value with nil are two very different things
also no you don't
INFO - [G] 2024-12-11 13:23:50 :: ERROR :: StackTrace :: Oops! The game crashed
card.lua:254: attempt to index local 'center' (a nil value)
Stack Traceback
===============
(1) Lua local 'handler' at file 'main.lua:590'
Local variables:
msg = string: "card.lua:254: attempt to index local 'center' (a nil value)"
(*temporary) = Lua function '?' (defined at line 39 of chunk [SMODS _ "debug/debug.lua"])
(*temporary) = string: "Oops! The game crashed\
you can just post the lovely dump
Some context as to what you’re trying to do would help too
elseif self.ability.name == 'Magi' then
if self.ability.extra.round >= self.ability.extra.req then
self.ability.extra.round = 0
self.ability.extra.req = self.ability.extra.req + 1
self.ability.mult = self.ability.mult + self.ability.extra.mod
else
self.ability.extra.round = self.ability.extra.round + 1
end
end
this is what i changed before it crashed
attempt to start challenge with the joker who uses this code
full error log and the card.lua dump (both in Mods/lovely) would be helpful
card.lua dump
full error log
i think i figured it out
challenge had outdated name so it was attempting to give a joker that did not exist
figures yeah im just wondering why that happened in set ability and not create card
The game uses set ability to determine what joker it is
that makes sense
pretty neat
a shame that theres no way make it display upgrading the correct hand type but thats a creative idea
there is i just forgot lmfao
#1248287850512781452 updated
i have one more foolish question, and forgive me for being a noob
i had a joker that is supposed to add mult (and im like 99% sure it was working before)
which displays that it should on the card, and h_mult is the correct number
but it simply does not
do you mean like
a joker that adds mult to a playing card
if so h_mult is mult that is given when the card is held
no like
it should just add mult
and it doesnt
like to your score
and im fairly certain it was before
in fact i have 2 jokers that do that in different ways and both stopped working recently
show the code.....
yessir
elseif context.individual then
if context.cardarea == G.play then
end
if context.cardarea == G.hand then
if self.ability.name == "Coup D'etat" then
local temp_Mult, temp_ID = 0, 0
local raised_card = nil
for i=1, #G.hand.cards do
if temp_ID <= G.hand.cards[i].base.id and G.hand.cards[i].ability.effect ~= 'Stone Card' then temp_Mult = G.hand.cards[i].base.nominal; temp_ID = G.hand.cards[i].base.id; raised_card = G.hand.cards[i] end
end
if raised_card == context.other_card then
if context.other_card.debuff then
return {
message = localize('k_debuffed'),
colour = G.C.RED,
card = self,
}
else
return {
h_mult = 2*temp_Mult,
card = self,
}
end
end
end
end
...
add_item(MOD_ID, "Joker", "j_coup", {
unlocked = true,
discovered = true,
rarity = 2,
cost = 5,
name = "Coup D'etat",
set = "Joker",
eternal_compat = true,
config = {
},
}, {
name = "Coup D'etat",
text = {
"Adds {C:attention}double{} the rank",
"of {C:attention}highest{} ranked card",
"held in hand to {C:red}Mult"
}
});
and no local vars
mult not h_mult
probably
this seems
not correct
is this old steamodded or something
wth is "add_item"
probably 0.9.8 yeah
i started writing this like 6+ months ago
add_item could be a custom function
in fact i think balatro didnt even use steammodded at the time
tbh this feels like it's even before SMODS 0.9.8
the era before SMODS had a joker api
and every joker mod broke every other joker mod
I rember when the first step in troublshooting crahses was asking if they had JellyMod installed
lmfao
i do remember this
tried it and immediately deleted it
so do i need to like
restart entirely
That is the sole reason I added mod list to the crash handler
is my code so outdated its not worth iterating on
yeah probably
but it should be easier to catch up now than it was to get here in the first place
to be fair it won't be that hard to transfer this format to SMODS 1.0.0 formart
if you did want to do it
the calcualte is probably just fine
now nothing works
oh it's because of the atlas table names
okay everything except the seals are working again
the default is ASSET_ATLAS, so you don't even need that part unless you specifically need an image atlas or animation
yeah having it like this works
i'm not creative enough to think of what the right key could be other than Seal
seal sprites are actually stored in a shared table
you can change the atlas, it just doesn't affect the sprites that already exist
the game creates a Sprite object once and then just keeps using it, so you need to reassign that object if you change the atlas, otherwise it won't take effect
it's kept in G.shared_seals
and that only applies to the seals?
that seems like a strange decision so i have to ask to make sure i'm not just doing things wrong
I know soul does something similar for it's soul
agony
he's such a joker
That’s why Malverk is bis 😉
the stickers actually do seem to be working right out of the bat
i'm thinking about it, i just don't want to make people download two things if it's avoidable
could just bundle it in your download like cryptid with SMODS and talisman
It also has the benefit of giving users customisation within your texture pack and the option of using additional ones, whilst your method doesn’t really allow that
Liking how this turned out
I ported my card fronts from my game over to Balatro for fun
so i had to work and im just now getting to reformatting my mod
but one of the first things i notice
is the function to generate the card ui box no longer necesary?
Are there any mods that have branching level two vouchers? Like you can choose 1 of 2 level 2 vouchers for different effects on each
My friend is tryna implement it and we have no idea how to do it 💔
https://discord.com/channels/1116389027176787968/1314802125141835908 this is what I’m talking abt btw
probably #1225831216939536394
no idea
i dont use their mods
I'm not too familiar with vouchers but see if they have an in_pool or whatever
smods does have this
All centers should have it atp.
atp? 😭
dw we still finding edgecases where centers don't respect in_pool (see hidden consumables PR)

In fact it should be everything after that PR.
I noticed the config file seems to have gone missing, won’t that break fresh installs?
it's not missing-?
Hi, is there any updated modding documentation for Steamodded?
trying to get some more of it done to move to a beta release
wym
like extra context types for jokers?
you know you can make your own right
yeah just calculate it whenever you want it to happen
good to know
G.GAME.blind.chips = G.GAME.blind.chips * (1 + (card.ability.extra.BlindInc / 100)) do i have to tobig() some stuff?
@teal estuary I recommend adding your mod’s prefix before custom contexts just to avoid issues
i shall, i usually use prefixes anyway (apart from joker keys, because no need too)
Joker keys get them automatically
I think usually Steamodded appends prefixes to keys automatically
Never mind my mobile browser didn’t show it to me 🙃
@tepid sky example joker: only appears if you have 0 joker slots
SMODS.Joker{
key = 'rarest',
loc_txt = {
name = "Rarest Joker",
text = {
"Only appears with", '0 Joker slots'
}
},
rarity = 4,
cost = 50000,
blueprint_compat = false,
eternal_compat = true,
perishable_compat = true,
in_pool = function(self)
if G and G.jokers and #G.jokers.cards == 0 then
return true
end
return false
end,
}```
this is how you use in_pool
thats what im SAYIN
random question, do you know if smods find card can also find a voucher?
i honestly just forgot what was used in in_pool
no idea
damn
just do if G.GAME.used_vouchers['v_modprefix_key'] then
ooh thanks!
thats really it? damn
<3, Reason i was asking cuz i wanted to make branching vouchers
:(
i forgot what other things went with in_pool
so i just
fair enough 😭
replaced it with wawa and wawa2
couldnt you just use requires = {'the voucher'}, on two different vouchers?
got a question, how could you effect the shop price of things with a joker? im not sure what the thing you'd call for it would be 😭
yea but one needs to dissapear if the other is bought
oh i see
thats why i asked
What do you want to affect prices of and how
otherwise i would've lol
lower the price of something by 0.1
well, everything in shop
most significant price change 🔥
real
Hmmm I’d try manipulating the price changing function to look if you have a Joker and modify the price there
Keep an eye out for the correct ordering inside the function whether you hook or inject into it
Also if you want it to apply immediately you might need to recalculate the prices of shop items although future items should automatically update
Balance-wise, I think the discount could be higher
patch Card:set_cost()
or hook...
naw don't think you can there
I think it’s one where you usually need to inject
pretty sure it doesn't return just does everything in the function
Because of how it works internally
i dont see why you couldnt just do self.cost = self.cost-number after hooking
because that wouldn't change the ui
not unless the text uses a ref value
which i doubt
self.sell_cost_label = self.facing == 'back' and '?' or self.sell_cost
I don’t think the issue is the ui
Mostly because the order of operations matters
And so you need to add some changes to the right place if you want them to work
also they dont exactly mention changing the sell cost
just the cost
regardless in this instance a patch is better for readability/visibility/debugging/etc
/performance 
those 8 cpu instructions are gonna save a lot of time trust
is there a function like "SMODS.upgrade_hand(hand)?" something that would just upgrade any hand input
and if not, how would one go about upgrading a specified hand
See how Planets and Astronaut do it
@tepid sky do vouchers have an in_pool function? If so just check there. Theres a few edge cases such as if both are spawned such as using a voucher tag, but that is probably ignorable
it's kinda unclear? i tried to look for it but i'm having trouble digging through there
🤷♂️ i'll let the player get those then lol
like this shouldn't be as unclear as it is
There’s a level_up_hand function
so when converting to smods format, should i move my calculate code into each joker? or does it not matter
yeah you should. I assume right now you're hooking card.calculate_joker and it's not very compatible rn
heard
i also have a hook on card:is_suit
function Card:is_suit(suit, bypass_debuff, flush_calc)
if flush_calc then
if next(find_joker('Plaid Joker')) and (self.base.suit == 'Hearts' or self.base.suit == 'Spades') == (suit == 'Hearts' or suit == 'Spades') then
return true
end
if next(find_joker('Plaid Joker')) and next(find_joker('Smeared Joker')) then
return true
end
return self.base.suit == suit
else
if self.debuff and not bypass_debuff then return end
if next(find_joker('Plaid Joker')) and (self.base.suit == 'Hearts' or self.base.suit == 'Spades') == (suit == 'Hearts' or suit == 'Spades') then
return true
end
if next(find_joker('Plaid Joker')) and next(find_joker('Smeared Joker')) then
return true
end
return self.base.suit == suit
end
end
should that go in that jokers section reformatted or stay outside like so
this is an override not a hook do not do this
i see
oh its going to increase by 0.1 every X
the only reason it starts at 0.1 is because of its reference
okay, i think that works, but how would i get it to do the animation that plays alongside it?
Look at how the game does it
intresting
i'm trying, but i'm sure how to get update_hand_text({sound = 'button', volume = 0.7, pitch = 0.8, delay = 0.3}, {handname=G.GAE.current_round.most_played_poker_hand,chips = G.GAME.hands[text].chips, mult = G.GAME.hands[text].mult, level=G.GAME.hands[text].level}) to target G.GAME.current_round.most_played_poker_hand.
full code:
enhancement.calculate = function(self, card, context, effect)
if context.cardarea == G.play and not context.repetition then
if pseudorandom(self.key) < G.GAME.probabilities.normal/self.config.rand_planet_odds then
update_hand_text({sound = 'button', volume = 0.7, pitch = 0.8, delay = 0.3}, {handname=G.GAE.current_round.most_played_poker_hand,chips = G.GAME.hands[text].chips, mult = G.GAME.hands[text].mult, level=G.GAME.hands[text].level})
level_up_hand(self, G.GAME.current_round.most_played_poker_hand, true)
sendInfoMessage("Cosmic roll succeeded", "Shellular's Deck of Cards")
else
sendInfoMessage("Cosmic roll failed", "Shellular's Deck of Cards")
end
end
end
change text to G.GAME.current_round.most_played_poker_hand
is
return {
message = 'Upgraded!',
colour = G.C.MULT,
card = card
}
more up to date than
G.E_MANAGER:add_event(Event({
func = function() card_eval_status_text(card, 'extra', nil, nil, nil, {message = localize('k_upgrade_ex')}); return true
end}))
return
very
i mean you can still do it
but like
would you rather do that
no true
thank you
what would be the check for cards with editions, as to #G.jokers.cards for jokers
if (the card).edition then
local m = 1
for i, v in pairs(G.jokers.cards) do
if v.edition then
m = m + 1
end
end
if you want cards then you can loop through every area
ok so im having issues figuring out how the HELL im supposed to make a custom deck...
I was able to just raw edit the exe code to put a deck in the game, but I want to make it into an actual mod
depending what you're doing you may need a lovely patch as well https://github.com/ethangreen-dev/lovely-injector?tab=readme-ov-file#patches
If I wanted to make it so if I sold the joker "x" it would give -1 ante for example how could I achieve this? I wasn't sure what the effect or variable for that would be.
ease_ante probably
thanks!
godsmarble in jens does exactly this if you run into any issues
thank you
Hello! Are the example mods intended to work out of the box? (Assuming they are copied out of the example_mods dir and into the root /Balatro/Mods/... dir)
I'm trying to diagnose why I'm unable to load mods.
I believe that the lovely injection is happening because if I've only ever gotten the console to launch when the injected version.dll is present alongside the the other Balatro binaries.
The lua files for the mods are located at the directory specified in the logs so I'm not sure what I'm missing
they were when they were made
some do not work anymore
which one are you specifically trying to use
I've tried the shipped
--- MOD_NAME: CustomKeybinds
--- MOD_ID: CKeybinds
--- MOD_AUTHOR: [stupxd]
--- MOD_DESCRIPTION: Custom keybinds example!
--- DEPENDENCIES: [Steamodded>=1.0.0~ALPHA-0812d]
--- STEAMODDED HEADER
--- MOD_NAME: Achievements Enabler
--- MOD_ID: AchievementsEnabler
--- MOD_AUTHOR: [Steamo]
--- MOD_DESCRIPTION: Mod to activate Achievements
--- DEPENDENCIES: [Steamodded>=1.0.0~ALPHA-0812d]
And I've also tried this third-third party (lol) keybind mod
https://github.com/DorkDad141/keyboard-shortcuts/blob/main/keyboard_dorkdad.lua
If the console launches is that a fair assumption that injection occurred? Is there a debug flag to get more information from the logs?
steamodded isn't loading
just realized lol
Figured it out. I had the repo cloned into the mods directory instead of a steammodded subdir within mods. Thanks for pointing me in the right direction
can loc_txt be changed per card?
as in, I want to change the description of a joker after it's added to the deck
you can dynamically update loc_txt yes
You probably could update it within add_to_deck. I wouldn't do that though
see loc_vars at https://github.com/Steamopollys/Steamodded/wiki/05.-SMODS.Center#all-centers for ways to properly change a joker's description
I mean I can just put a ternary to choose between nil and the text I want ¯_(ツ)_/¯
I'm guessing card_eval_status_text? not 100% sure
hmmm
loc_vars to change the keys is preferable to anything else
changing loc_txt doesn't do anything because it doesn't update localization
(you could try to update and reparse loc_txt if you're a masochist)
hmmmm
the problem is that I want it to have an entirely new text
DID YOU READ THE DOCS I LINKED
that doesn't mattter unless you literally generate it on the fly
loc_vars lets you change the loc_txt you use on the fly
you can return a completely different key to use
YES I DID
it's how I set it up with Cryptid's gameset system
what do you think
You can force the use of a different description entirely (
key).
means???
loc_vars = function(self, info_queue, center)
local gameset = Card.get_gameset(center)
if gameset == 'disabled' then gameset = 'mainline' end --still show description
return { vars = { center.ability.extra.chips }, key = "j_cry_test_"..gameset }
end,
then I have loc_txt for j_cry_test_mainline, j_cry_test_madness, etc.
you also need to use the localization file system for that
what is that arg naming
idk, that's how I have it set up :jimball:
oh ok thanks
naming a Card object center is hideous
is this additional tooltip done by appending to info_queue?
tbf I still get lost between the 2
wait so does SMODS work localization out or should I implement code for it?
it's covered by steamodded. for the text you can just put it inside a localization/en-us.lua in the correct format (or whatever locale you need) and it will load it by itself
I have this code for a basic joker but in game it looks like this. Is there something wrong with my assets?
you haven't discovered it yet?????
I tried to set it so it should be discovered by default
the other jokers work like that. Or if I load mods they are all available right away
if I discover it using the debug mod the art is replaced with the regular jimbo
Please don't tell me I screwed up yet another PR
Oh no I think I did
😭
ON THE DAY OF MY FINALS OF ALL TIMES TO NOTICE
wait im new to love2d, does it hotload? like if i change text, will it change while the game is open?
i don't believe so
You'd need to use a specific function in DebugPlus to do that (not built into Balatro nor Steamodded).
discovered = true in the joker?
oh it is mb
dang, it would be helpful if textures were steamed live, or at least an option to enable that, so texture packs would be a bit easier
can you lovely patch into another mod?
nope?
I think lovely 0.6.0 might have support for it?
How do I fix this, if possible
this is for something else but you ain't gonna see what it's actually for
I'm using all this as temporary stuff
I have this which is pretty close https://github.com/WilsontheWolf/DebugPlus/blob/master/docs/dev.md#watch
Are there any in depth guides on youtube or other sites that can help me start out making a mod that people could share?
This was working to animate the soul portion of the soul card before the update/before I pulled new steammodded (I did both at the same time because I'm silly) but now its not (just the default soul icon)
AnimatedElements = {}
local soulAtlas = SMODS.Atlas {
key = "soul",
path = "slime_soul_trans.png",
px = 71,
py = 95
}
--Update animated sprites
local upd = Game.update
function AnimatedElements.update_soul(dt, anim)
local next_frame = false
if anim.initiated then
G.shared_soul = Sprite(0, 0, G.CARD_W, G.CARD_H, soulAtlas, { x = 0, y = 0 } )
anim.initiated = true
end
if not G.shared_soul.t then G.shared_soul.t = 0 end
G.shared_soul.t = G.shared_soul.t + dt
if G.shared_soul.t > 1/(anim.fps or 10) then
G.shared_soul.t = G.shared_soul.t - 1/(anim.fps or 10)
next_frame = true
end
if next_frame then
local loc = G.shared_soul.sprite_pos.y * getRow(anim) + G.shared_soul.sprite_pos.x + 1
if loc >= anim.frames then
loc = 0
end
local pos = { x = loc % getRow(anim), y = math.floor(loc / getRow(anim)) }
G.shared_soul = Sprite(0, 0, G.CARD_W, G.CARD_H, soulAtlas, pos)
end
end
function Game:update(dt)
upd(self,dt)
for jkr, anim in pairs(anims) do
if anim.play then
if jkr == 'anim_c_soul' then AnimatedElements.update_soul(dt, anim)
else AnimatedElements.update_frame(dt, jkr, anim, G.P_CENTERS[jkr]) end
end
end
end
Don't know why I'm getting an error when playing cards and crashing when playing heart cards could someone help me
calculate = function (self, card, context)
if G.GAME.blind.in_blind and context.selling_card then
ease_dollars(card.ability.extra.dollars)
G.GAME.dollar_buffer = (G.GAME.dollar_buffer or 0) + card.ability.extra.dollars
return {
message = localize('$')..card.ability.extra.dollars,
dollars = card.ability.extra.dollars,
colour = G.C.MONEY
}
end
end,
any reason this is not making a pop-up?
selling_card context doesn't support return value messages iirc because base game doesn't need it
use card_eval_status_text or SMODS.eval_this
hold on, is selling_card when the joker itself is sold or when any other card is sold?
SMODS.eval_this
Funny looking name
Should I create a repo, where every mod for Balatro should be listed? So like an Index, which the Balatro Mod Manager could use
the WHAT
And so its filled with JSON files (or something else) and a thumbnail file, looking like this:
{
"title": "Extended Cards",
"category": "Gameplay",
"repo":"https://github.com/joemama/extended-cards",
"downloadURL": "https://github.com/joemama/extended-cards/releases/latest/extended-cards.tar.gz",
}
i dont have a mod but im answering yes to drive up votes
BROTHER WHAT IS THE <- OPERATOR BRUH
nothing in lua
but it's usually an assignment operator
what are these options 😭
some sort of walrus?
x <- 3
text = (amt <-0.01 and '-' or '')..localize("$")..tostring(math.abs(amt))
vanilla code btw
oh yeah got it
the operator in this situation is <
amt < -0.01
we already have an index repo, though not well used (yet)
link?
I see. But it would preferable to make it like this and also include a thumbnail.
because aure is famously active 
ah wait
im thinking of another person nvm
aure is indeed active i lied
because think again who you're replying to
yeahhhh
forgor....
anyways ofc nobody contributes to that because nobody knows about it
@frosty dock Would you be able to maintain it?
it's set up in a way where I don't really need to, at least not constantly. it has workflows set up to auto-merge PRs
github restricts workflow runs for new users at minimum so it's not fully automatic, but I can handle that
I can also add more maintainers
balatro elves
that's fine, it's not populated yet so we can still change the format we require
Also ideally this would be covered by the format of Steamodded metadata files
no point in telling people to add their mods if it's not being used and I don't even know how it will be used
Not convenient. BMM will not only have steamodded support, that's why a unified way of handling meta-data would be better
it doesn't have to match exactly, but I still think it's convenient to have common fields use matching keys so you can just throw in the same file
not to mention most mods use steamodded, and almost all others just use lovely
do as you please though, my repo is not populated so there's not much of an advantage of using it over anything else
use any workflow code from it if you want
Thanks, will look into it
how do you pass vars into an info_queue of any card again
ive proudly never touched an info_queue
okay i have thought of a workaround
AND GUESS WHAT TIME IT IS
THAT'S RIGHT WELCOME BACK TO NODES[1] HELL
so real
@orchid cargo Is there a way to contact localthunk? I know he wouldn't reply on discord, but something like an email or contact to his manager?
neat
What's your question?
how would i make an edition that doesnt allow the joker to be blueprinted
i think it would be like context manipulation right
I'm pretty sure you'd just have to change blueprint_compat to false on the joker
Though the issue is changing it back to it's previous value when the edition is removed
that only changes the display, the blueprint check needs to be manually changed
Oh wait you could just prevent the blueprint context from ever being passed down actually
When a card has the edition
mhm
But you'd probably also have to change the blueprint check func if you want the UI to make sense
I fucking love OOP
lovely is easy until you need to do a regex patch
at which point i start hating myself
lovely regex is 90% "did i miss a dot" and 10% actual regex
1% "Screw you Cryptid"
https://regexr.com/ my beloved
regexr does NOT help when your pattern looks like this
Ok 1. Font hell 2. Wtf is that for
- i love 04b03
- support for blinds with more than 2 lines of description
Non monospaced bitmap font 
cry
I am
ptid
so true
you can email balatro@playstack.com. as you may expect, thunk is a busy dude and the best way to get something in front of him is probably through playstack.
Where the fuck is the odds field on a tag's config used
I'm going insane how are tags made rarer
odds might be from when tags had a chance to
on you
really unpopular mechanic, so thunk removed it
there are still other remnants of it in the code too
Wait do all tags have equal pull chances
some can't show up in ante 1 but apart from that yeah I believe so
I've been gaslight by the game
some tags also have unlock conditions that the game doesn't tell you about :))))
Yeah I knew about that from the wiki but I always thought negative would rarer than the other editions and the rare tag would be rarer than the uncommon tag
ah, nice. pretty sure the wiki also mentions that all tags are equally likely though
Probably
I can't read :(
fun fact
Huh that is such a weird design idea
yeah that's the one
Time to add it back 
how do i make a edition not able to be removed
i dont think it really matters
ok nvm im not doing that
this works for ui right
for UI only, actually
how do i save whether a joker was blueprintable per joker
is there anywhere that has a base that i can refrence?
it's just baked into the calculate function, there's no way to change it dynamically for any given joker the way it's set up
hook calculate_joker and just make it return nil if context.blueprint
yea but on_remove it has to be set back to original blueprint_compat
i love ui, not the making of it 😫
how do i check if a joker is blueprint compatible without spawning it
I wonder if building in a blueprint compat check to the blueprint context calls would make sense
i mean it would make more sense
but i think it rarely comes up
when does blueprint_compat really differ from what the modder inteded?
where is the joker caluation files
i found it
so id append the function like if context.blueprint and joker edition == pure then return nil end?
also what is the context for retriggers
context.repetition?
^
ok it did not work
post code
if (context.blueprint or context.repitition) and (self.ability.edition and self.ability.edition.e_TGTM_Purified) then return nil end``` After lovely patch
maybe i messed up the edition
oops
repetitititition
how do you check for a modded edition
iirc you check edition.key
ok so thats what i messed up
message just displays "error"
in my infinite wisdom i have determined that the "x_mult" key does not exist
however i am too lazy to scour the smods docs for the localization keys
if context.joker_main then
return {
x_mult = card.ability.x_mult,
message = localize { type = 'variable', key = 'x_mult', vars = { card.ability.x_mult } }
}
end
what perchance might be the key for displaying xmult
isnt it a_xmult?
that would make sense
yuh
how can i check how much money the user currently has?
G.GAME.dollars
thank
thank
thunk
i'm trying to raw dog my code but i gave up with the wild goose chase of trying to find variable names
If you want to test variables DebugPlus's eval is handy for that
you
hi guys can i change the meta for mods rq
reading save files is the new meta apparently
yes it actually works
i need to set in the config though i want it to be configurable per save file
some cards are going to be locked behind certain completion marks from isaac as well
has anyone done time/date cards yet, bonuses based on time of day or day of the year
seasonal bonus jokers lmao
wait that's a cool idea
probably honestly
tbh though the isaac save data was a PAIN in the ASS to get lol
halloween joker that has a mediocre buff on normal days but halloween it's CRACKED
it's all byte data 💀
obviously you could cheese it but like fundamentally speaking not crazy right
surely there's a lua library out there already that gets time and date then it's just fiddling with whatever output
I have a secret in a mod based off the current day
was it trivial enough to get the data?
yeah theres a lua api
knew it
why do the heavy lifting when someone else has done the work already better than you ever could
i might have a fiddle see how far i can take it
ahh, first of april, nice
so many silly ideas bouncing around in my head based on time, like a night owl card that becomes more powerful depending on how late at night it is
or a card that buffs a card based on what time it is, so 3pm would buff 3s
can you make a joker usable like a consumable?
like specifically i need the "use" tab
i probably have to patch the main game tbh
Irs been done but yeah I think you need a loclwt parch
whats the dependcy string for a specific smods version in the manifest file?
where
has it been done*
it'd be nice to just reference someone else's code lol
how specific?
the one I just pushed xD
I got it working by just throwing the whole version string in there
(>=1.*) didn't work though
yeah that only covers non-beta versions
you can always put >= the specific version to be precise
so "Steamodded (>=1.0.0~ALPHA-1213a)" this is the way to do it?
yep, no more concise way to require a specific version or newer
Idk I don't actually use mods
that's cool
I've just seen screenshots a long time ago with stuff
it's not like it affects anyone else
if you're not as particular, could go for (>=1~)
I guess that's implicitly >= the recent json dep change
as previous versions will fail to recognize it
I forget does >=1.0 match 1.1~
bro why does deck adding have to be confusing....
Im seeing people use stuff that Im seeing NO where in the wiki
all the mods ive seen that are decks are all using the deprecated sprite stuff and the SMODS.Deck instead of Back so I have no clue what to base any of this on
the docs tell me a good amount, but theres little things missing that make it a lot harder
function SMODS.INIT.SoulDeck()
local soulback = SMODS.Atlas('SoulBack',
71,
95,
'SoulBack.png'
)
local souldeck = SMODS.Back('Soul Deck',
{name = 'Soul Deck', text = {'A Really Stupid Deck.'}},
config = {},
pos = {x=0,y=0},
atlas = 'SoulBack',
unlocked = true,
discovered = false
)
end
This is about what I have for what I think it should look like?? I dont really know cause I havent loaded it but
i got it to work btw
am i going insane or should this work? it's getting mad at the set_ability thing but i don't know what i'm overlooking. is there a different thing for putting in custom enhancements that i'm missing?
consumable.use = function(self, card, area, copier)
for i = 1, #G.hand.highlighted do
G.hand.highlighted[i]:set_ability(G.P_CENTERS.cosmic, nil, true)
end
end
prefix?
so G.P_CENTERS.sdoc_cosmic?
presumably, i don't know much about enhancements
there's also a class prefix, so if the rest is correct, this should be m_sdoc_cosmic
shoot, okay
THERE WE GO
thank you so much :>
ironically i tried both m_ and sdoc_ seperately
there's some example mods like e.g. https://github.com/Steamopollys/Steamodded/blob/main/example_mods/Mods/AbsoluteDeck.lua
as for your example specifically, it should be loc_txt = {...} (you always need to assign it to something, no unordered arguments)
ah, I see, I ended up having to use the legacy thing because R2modmanager is only updated to 0.9.8, but if it works for newer versions aswell its honestly unneeded to change it
function SMODS.INIT.SoulDeck()
local loc_def = {
["name"] = "Soul Deck",
["text"] = {
[1] = "A Really Stupid Deck",
},
}
local mymod = SMODS.findModByID("SoulDeck")
local soulSprite = SMODS.Sprite:new("soulSprite", mymod.path, "SoulAtlas.png", 71, 95, "asset_atli")
local soulConfig = {hand_size = 75, joker_slot = 100, consumable_slot = 100, dollars = 100, spectral_rate = 100, consumables = {"c_soul", "c_soul", "c_soul", "c_soul", "c_soul", "c_soul", "c_soul"}}
local soulDeck = SMODS.Deck:new("Soul Deck", "souldeck", soulConfig, loc_def)
soulDeck:register()
soulSprite:register()
end
ended up with just that
yeah you probably shouldn't be using 0.9.8
you really can't rely on new docs for an old version, and 0.9.8 never had good docs. you really should just update to 1.0 off github, it's worth it
ah alright, I had just kinda ran with 0.9.8 since R2 never got 1.0 for whatever reason
people are also very unlikely to help you with 0.9.8 code
also given only OG modders (like myself being heavily involved with its development) actually know the ways of 0.9.8, it's hard getting support for it
most of the time even I won't be willing to help with it, it's just that terrible in several ways
I feel like I need more explanation as to what the atlas thing is
I feel like im not understanding something thats trivially easy but im just glancing over it?
like im seeing people using sprites in 0.9.8, and im understanding that, but atlases im just kinda blank on
SMODS.Sprite in 0.9.8 and SMODS.Atlas in newer versions have the same purpose
it's just that the old version was poorly named, so we changed it
both are just sprite sheets
so in the backs, where it says atlas = 'centers',, if im using a custom sprite, what would I do wit hthat??
cause I cant tell if centers is like a global atlas for all the base game content?
there's several base game atlases. you can find the corresponding files by extracting the game executable with 7-zip
somewhere in the code, there's a section that relates these file names to atlas keys
0.9.8 docs have a reference, actually
so If I wanted to make my own atlas, it would just be lua SMODS.Atlas{ key = "soulAtlas", px = 71, py = 95, path = "SoulAtlas.png" }
then plug soulAtlas in for the key in the SMODS.Back?
or
not the key
the atlas
yeah
oh alr, cool
note that you can't regularly specify base game atlases this way without an additional argument, this is needed to avoid conflicts
also means you don't need to worry about your keys being unique from other mods (that was not the case in 0.9.8)
alrighty, thank you!
just saw i forgot to answer this. mostly the reason is that thunderstore was always kind of unpopular with our modding community, and even if we started uploading newer versions of steamodded, it won't work because it needs a newer version of lovely than is present on there (not a huge deal admittedly, we could always ask metherul to update), but also it's been in ongoing (alpha) development for a while and maintaining that on TS would mean always having to keep it updated or have people use outdated versions
oh so do I also need to install the newer lovely?
yeah, steamodded doesn't strictly require the very latest version feature-wise, but the one on r2mm is way too ancient
https://github.com/ethangreen-dev/lovely-injector/releases/tag/v0.6.0 this is the latest version
ok yeah very simple to set up
thats actually a cool idea
one day of the year is REALLY op... other than that its a ok joker
obviously very niche but could be balanced, especially with having them appear conditionally
could always add a special card that let's you change your season
yep made that mistake seconds ago haha
if == !Halloween then return false end
i'm rusty on my lua, the formatting has really jumbled my wires
pretty much as simple as that yeah
honestly this lua framework scared me for a minute, but looking at it for a bit it got easier on the eyes
calculate = function(self, card, context)
local current_date = os.date("*t", os.time())
local is_halloween = (current_date.month == 10 and current_date.day == 31)
if context.joker_main and is_halloween then
return {
message = localize{type='variable', key='a_xmult', vars = {card.ability.extra.halloween_Xmult}},
Xmult_mod = card.ability.extra.halloween_Xmult
}
elseif context.joker_main and not is_halloween then
return {
message = localize{type='variable', key='a_mult', vars = {card.ability.extra.default_mult}},
mult_mod = card.ability.extra.default_mult
}
end
end
still quite crude but it's truly just get date and apply whatever
you've made a friend
one of them can't find the main file...
strange
the other one loads fine tho
OH
IM STUPID
I left the legacy header in my main file
which probably confused it
which is why theres one
with no version
(legacy header one)
and one with a version
from the JSON manifest
would this be the correct file structure?
special card that changes the date and time of your pc with os.execute('date MM-DD-YYYY')
i think having users glance at their time and date and be shocked it's christmas in the middle of july might be a bit much 
looks right to me
could have a separate joker that overrides the os.date check if in hand
and lets certain checks pass anyways
the spooky joker
literally just makes it halloween
nothing else
i was thinking a tier 2 voucher maybe
ooh
depends how op they are really
maybe tier 1 it chooses a random season each ante, tier 2 you decide which to pick or something
A joker whose xmult scales with the time of day
3x mult because its 3pm
yeah got one in the works
making one called night owl
actually, might have to work off a 24 hr clock
me changing my time to abuse this joker
yea
wicked
closer to unsociable hours you are the more powerful it gets
make it time of day in 24hr clock /2 = xmult
so playing at around midnight would be a 12x mult
eh people will find a way to cheese it regardless, it's inconvenient enough where people won't bother unless they're properly sweating it
I mean this jokerset isnt really like... balanced is it?
yeah but you don't want it to be unfun by being too easy or too hard
spot the problems (:
I would make the sweet spot anywhere from 1000-400
almost forgot to show the best part
what people think cryptid/jen's almanac is in a single screenshot, colorized
how can i poll the edition of a consumeable
imagine making a card based on a smart watch where the mult is decided by health goals like steps taken and how much sleep you got
like let's say i want to know if card[1] is negative or not
in the consumeable area
garmin integration
you walked 12000 steps today here's +120 mult
what next, a joker that gives {10,001} mult? /j
i ALREADY have instances of these cards, but for some reason, it isn't working lol
force the player to plug in a garmin watch to play the game, and make it so their BPM = their xmult
artificial adrenaline just for optimized mult
each 0.1 degree over your baseline body temp is a x2 multiplier
link the user's spotify account and mult is based on their taste in music
country drains all of their money, 0x mult, hand size 1, destroys all jokers
balatro ost most listened to, x10000 mult
quicj question, how would I do something like checkered deck does except with all spades?
I will mitm it
I just want nothing but spades
do y'all know why this crashes, but only when more than 1 card is played?
code: ```lua
consumable.use = function(self, card, area, copier)
G.E_MANAGER:add_event(Event({trigger = 'after', delay = 0.4, func = function()
play_sound('tarot1')
card:juice_up(0.3, 0.5)
return true end }))
for i = 1, #G.hand.highlighted do
G.E_MANAGER:add_event(Event({trigger = 'after',delay = 0.15,func = function()
G.hand.highlighted[i]:flip()
play_sound('card1')
G.hand.highlighted[i]:juice_up(0.3, 0.3);
return true end }))
G.hand.highlighted[i]:set_ability(G.P_CENTERS.m_sdoc_cosmic, nil, true)
end
for i = 1, #G.hand.highlighted do
G.E_MANAGER:add_event(Event({trigger = 'after',delay = 0.35,func = function()
G.hand.highlighted[i]:flip()
play_sound('tarot2')
G.hand.highlighted[i]:juice_up(0.3, 0.3)
G.hand:remove_from_highlighted(G.hand.highlighted[i])
return true end }))
end
end
nuh uh
G.hand.highlighted[i]:flip() is indexing nil somewhere, maybe when you use the thing the cards aren't counted as highlighted anymore?
could be when using tarot cards, they technically aren't highlighted while they're being flipped or whatever?
i suspect because you're trying to modify G.hand.highlighted during the iteration?
Ok
it's legitimately impossible
try with a local variable instead
okay
how would I make my deck act kinda like the checkered deck?
except all the suits are spades
I just want if not spade then make spade
apply = function()
G.E_MANAGER:add_event(Event({
func = function()
for k, v in pairs(G.playing_cards) do
if v.base.suit == not "Spades" then
v:change_suit("Spades")
end
end
return true
end
}))
end
I kinda tried here, but I have no clue what the apply thing does
I just saw it in an example and kinda threw it at the wall
for reference, this is inside SMODS.Back{}
(if you want "not equals" you can do ~= instead, so in this case if v.base.suit ~= "spades" then)
ooh, good to know
but yea, I have no clue what the apply thing is doing there, im assuming its acting like the Back:apply_to_run function in the src code?
cause thats what triggers the checkered deck aswell
yeah, it's triggered at the start of the game
apply is?
yeah
it's about the same thing
iirc
so if you want to do something at the start of the game you'd use the apply() function
how would I call it at the start of the game?
like ensuring they're actually selecting my deck and not any others
for instance here's something i made that sets all heart suits to wild cards
deck.apply = function(self)
G.E_MANAGER:add_event(Event({
func = function()
for _, card in ipairs(G.playing_cards) do
if card.base.suit == 'Hearts' then
card:set_ability(G.P_CENTERS.m_wild, nil, true)
end
end
return true
end
}))
end
presuming they're a part of your selected deck (so like a function within it) the game should do that by itself
idk, this is just kinda what i've had from when I modded this deck straight in to source code
I dont know if the change_suit function works here? I dont even know if im using apply correctly
as long as that's in SMODS.Back you should be fine
it is, but it doesnt affect the deck ingame
try ipairs() instead of pairs()
this is in the middle of a run, thats why theres like 7 king spades
that worked!!
glad to help!!!
thank you!
i find generally in modding if you're trying to iterate through a table with a for loop you want ipairs() instead
it entirely depends on the table
ipairs is for indexed tables, pairs is for key-value tables
yeah
i dunno i'm a little dumb but i do know that if you're messing with playing cards you're probably gonna want ipairs, i'm not an expert 
programmer art is best art
can anyone figure out why this is firing 4 times at the end of the round?
am i missing an extra check or something, it's always exactly 4 times regardless of triggers or jokers activating
don't worry about the scrappy code it's just so i can see the odds when it prints for debugging
if context.end_of_round and not context.repetition and not context.game_over and not context.blueprint then
local rand = pseudorandom('Test_J')
local pOdds = G.GAME.probabilities.normal / currentOdds
print(rand, pOdds)
if rand <= pOdds then
bonus = card.ability.extra.money
if bonus > 0 then return bonus end
end
end
Anyone know what the code is for referencing a gold seal in the text section under the loc_txt in SMODS:Back?
"a deck of {C:attention,T:m_gold}Gold{} cards with {C:attention,T:m_}Gold Seals.",
it's being triggered on the held in hand effect. check context.end_of_round and not context.repetition and not context.individual and not context.blueprint
ah so it was, good eye thanks
I just stole the check from the wiki
it's not that bad
it's not, i'm the bad one
yeah just need to use it more
i think i saw someone else with this issue earlier today but selling cards is not proc'ing the upgrade localization for a joker
i think i saw that "theres no architecture for it because base game doesnt need it" but like what about campfire?
yeah idk what im doing uh for future reference how would I detect if a played hand has an exact amount of cards
try looking in the code for square joker
I would do that but idk how to like, extract the game's files
oh
its as simple as using winrar or 7zip on the game's exe file
the joker code is contained in a file called "card.lua"
got it, for some reason searching up told me that winrar will not work
reddit being dumb I suppose
strange
...does making a specific card type count as a wild card require Lovely patches directly or replacing the original functions is unavoidable? Don't want to break compatibility of other mods and what not.
what does Oops! The game crashed: engine/moveable.lua:263: attempt to index field 'VT' (a nil value) mean and is it related to my mod or the game engine file?
It means on some object the field VT is undefined. There's not enough information for me to tell you more than that.
what is the field VT?
Idk. This is a moment when you have to go look at the lovely dump for yourself
once I'm in Movely dump in Balatro -> Mods -> Lovley -> Dump-> where should I look

