#💻・modding-dev
1 messages · Page 145 of 1
It's a function which you MUST call when you're doing any rng-related stuff which depends on seed
e.g what it says here:
if you want to use the same RNG
when do blue seals trigger?
yeah ive learned
After winning hand
And for getting random element from table you should use pseudorandom_element function
also works through calculate in context.end_of_round with better calc ^
common better calc win
okay so I'm thinking i just "fuck it we ball" merge voucher calc
target = "game.lua"
pattern = "{voucher = 'v_telescope', consumable_slot = -1}"
position = 'at'
payload = '''{voucher = 'v_telescope', `v_observatory', 'v_planet_merchant', 'v_planet_tycoon', consumable_slot = -1}'''``` isn't working either
I see it
target = "game.lua"
pattern = "{voucher = 'v_telescope', consumable_slot = -1}"
position = 'at'
payload = '''{vouchers = {'v_telescope', `v_observatory', 'v_planet_merchant', 'v_planet_tycoon'}, consumable_slot = -1}'''``` is the code now
Yes, because you need to change it to vouchers = { <vouchers-list>}
Just did that, still tweaking
wait you're trying to change the config of nebula deck?
Yes
you don't need lovely patches to do that
Or ownership
…
like you literally just do
I will use my headphone cord as a whip on somebody
I feel like I've totally done and I still need to make the art.
SMODS.Back:take_ownership('nebula', {
config = {
vouchers = {...},
consumable_slot = -1,
}
})
Toml or lua for that
Lua
So - 1 file for that
I should pay attention to other stuff going on next to what I'm working on some of the time
Would this also do the thing I want to do with the fool or is lovely patches what I do for that
Too cursed?
i could have told you an hour ago how to do what you were trying to do if I were paying attention
haven't we been here? that one's easier with lovely patches because you just need to change one line and that line is not directly tied to config values of the fool
Still isn’t working
Ok, just making sure
I forgot that I was doing this to put off the laundry I needed to do
That will take 5 minutes
Is there any documentation on how to write a toml patch?
Thanks
is there a way to detect a blue seal triggering?
easiest would be to patch into Card:get_end_of_round_effect()
Yes, no clue how though
this is what im trying to do
oh that one you can actually take ownership of blue seal i think?
Nice art
hm actually you'd have a hard time telling whether the blue seal filled up your slot or if they were already full to begin with
so maybe you do patch get_end_of_round_effect
ok how do i do that
you look at the code for blue seal, find a (preferably unique) target that you can use for your patch, and go from there
no like
how do i make a patch
i dont know how to do that
Not working whatsoever
Voucher calc aka better calc 2.2 is officially merged
i see
What does that do?
thanks!
do i need to update again if i ever want to use that?
allows vouchers to be calculated like jokers
or is updating yesterday good enough for that
Ah
updating yesterday is not good enough for a feature that was just merged
so yes you'll have to update
config = {
vouchers = {'v_telescope','v_observatory','v_planet_merchant','v_planet_tycoon'},
consumable_slot = -1,
}
})``` any help on this not working?
newer calc
is your mod being loaded?
okay then anything but that code is the issue
leave it out and make a json metadata file
headers are not cool
im trying to upgrade Xmult and destroy the discarded cards if the first discard is a two pair
it upgrades Xmult but doesn't destroy the cards
can anyone help?
with an enhancement, what would cause the game to crash with card.lua:256: attempt to index local 'center" (a nil value) when applying?
for i = 1, #G.hand.highlighted do --flips cards
local percent = 1.15 - (i-0.999)/(#G.hand.highlighted-0.998)*0.3
G.E_MANAGER:add_event(Event({trigger = 'after',delay = 0.15,func = function() G.hand.highlighted[i]:flip();play_sound('card1', percent);G.hand.highlighted[i]:juice_up(0.3, 0.3);return true end }))
end
delay(0.2)
for i = 1, #G.hand.highlighted do --enhances cards
G.E_MANAGER:add_event(Event({trigger = 'after',delay = 0.1,func = function() G.hand.highlighted[i]:set_ability(G.P_CENTERS[card.ability.consumeable.mod_conv]);return true end }))
end
for i = 1, #G.hand.highlighted do --unflips cards
local percent = 0.85 + (i-0.999)/(#G.hand.highlighted-0.998)*0.3
G.E_MANAGER:add_event(Event({trigger = 'after',delay = 0.15,func = function() G.hand.highlighted[i]:flip();play_sound('tarot2', percent, 0.6);G.hand.highlighted[i]:juice_up(0.3, 0.3);return true end }))
end
G.E_MANAGER:add_event(Event({trigger = 'after', delay = 0.2,func = function() G.hand:unhighlight_all(); return true end })) --unselects cards
delay(0.5)
end```
this is the code that applies the enhancement, which i believe is ok since i took it from the base game's src
well there's nothing here to destroy the cards
give me a sec
i don't think you can remove in context.pre_discard?
it only works for context.discard iirc
if card.ability.name == 'Glass Card' then
card:shatter()
else
G.hand.highlighted[i]:start_dissolve(nil, #G.hand.highlighted)
end
end```
should work in theory
my guess is you forgot to add the mod prefix to your mod_conv
nope
mod_conv = "TWT_luckshit",
and the key is defined as "luckshit"
do i need to define a name?
m_TWT_luckshit
centers have a class-specific prefix
i have a feeling that this causes ghost cards
"id": "QOL",
"name": "QOL",
"display_name": "QOL",
"author": ["QOL"],
"description": "QOL",
"prefix": "QOL",
"main_file": "qol.lua",
"priority": 0,
"badge_colour": "#000000",
"badge_text_colour": "#FFFFFF",
"version": "0.0.1",
"dependencies": [],
}
SMODS.Back:take_ownership('nebula', {
config = {
vouchers = {'v_telescope','v_observatory','v_planet_merchant','v_planet_tycoon'},
consumable_slot = -1,
}
})``` should work, right?
or is something tweaking
this is the code from the game's source so
no, put the take_ownership lines in qol.lua
yeah but running it with different timing is known to do weird things
yes, the json is just for the metadata
So like <head> in html
qol.json
{
"id": "QOL",
"name": "QOL",
"display_name": "QOL",
"author": ["QOL"],
"description": "QOL",
"prefix": "QOL",
"main_file": "qol.lua",
"priority": 0,
"badge_colour": "#000000",
"badge_text_colour": "#FFFFFF",
"version": "0.0.1",
"dependencies": [],
}
qol.lua
SMODS.Back:take_ownership('nebula', {
config = {
vouchers = {'v_telescope','v_observatory','v_planet_merchant','v_planet_tycoon'},
consumable_slot = -1,
}
})
how would i display little bubbles alongside a card if it has an enhancement? like how the wheel of fortune displays foil, holographic, polychrome etc
It works
by making a loc_vars function
is that the info_queue segment?
yeah
e.g. info_queue[#info_queue+1] = G.P_CENTERS.e_polychrome adds an info box with the description of the polychrome edition
can i define a custom one?
Not entirely sure why but this does not seem to be patching in. Not getting any indication in console that it's failing either
is high or low numerical priority higher priority? (if that makes sense at all)
Lower is executed earlier
where are you checking if it's applying?
I have a debug message in that patch that's not firing off when it should. Unsure where/how to get a dump with patched smods files
dump would be at lovely/dump/SMODS/_/src/game_object.lua
I do not have that folder then
within the quotes?
so...
what exactly should i be patching of the blue seal code to add the ability for it to level up hands directly
my first thought is to replace the if statement to also check for blue seals + full consumable slots, then throw a bone to my joker so it can do its magic
your goal is for blue seals to level up hands directly rather than generating planets?
yep
can i kill him? do i have permission to grab the ceremonial dagger and put him next to it?
I think I'd personally keep that if block and then add an elseif self.seal == 'Blue' below it
mmmm
just to avoid changing anything I don't have to
fair
so what's the bone id throw to my joker?
some kind of context?
or would i have to patch in something else to do that
yes
tbh I've just been looking into balatro modding as of the last 5 minutes 🤣
i see
how hard would it to set up a new context to use
and how worth while would it be to use that to detect when a blue seal is there but not able to create a planet card over other potential methods im not yet aware of
Alright new weird issue. After updating SMODs this joker stopped working. This worked just fine a couple weeks ago and I guess it stopped recently. I put a debug message under the contexts and it didn't fire, so my guess is something changed with the retriggering contexts?
yeah we made retriggering jokers an optional feature that you need to enable
SMODS.current_mod.optional_features = { retrigger_joker = true }
Ah how about that
@frosty dock can i have some input on this?
for most use cases you can just lovely patch in something like SMODS.calculate_context({ ... }) wherever you need it
should work just fine for this
is that in the utility functions page on github?
there's no complete docs on better calc features as of yet
i think the only trap you could run into is having your context trigger checks for a different context
mhm
but that's fairly easy to avoid by just making sure the context is different from anything that already exists
what's initSteamodded doing here
oh its not needed?
just thought it was important bc of the example thing over at lovely's github
no that's just the patch steamodded uses to plant itself into the startup routine of the game
duplicate calls of it probably make the game implode
noted
I'd go for something like this
[[patches]]
[patches.pattern]
target = 'card.lua'
match_indent = true
position = 'before'
pattern = '''if self.seal == 'Blue' and #G.consumeables.cards + G.GAME.consumeable_buffer < G.consumeables.config.card_limit and not self.ability.extra_enhancement then'''
payload = '''if self.seal == 'Blue' and #G.consumeables.cards + G.GAME.consumeable_buffer >= G.consumeables.config.card_limit and not self.ability.extra_enhancement then
SMODS.calculate_context({ blue_seal_failed = true, card = self })
end'''
oh so indent does actually matter
forgot a thing there, oops
wdym
how do i get a random number between 1-3?
indent matters in that match_indent is a required field for pattern patches
'match_indent = true'
you can use match_indent = false but it probably makes your dumps look ugly
i use it sometimes when I have to work around not being able to outdent
take the random number generator, multiply by three, and take the ceiling of it
i see
pseudorandom('whatever', 1, 3)
nvm it doesn't work exactly like math.random it needs both a min and a max
so as a final thing i presume that context.blue_seal_failed is the thing im looking for in my joker?
yeah
usually you want contexts you add to have your mod prefix in some form, just to avoid overlaps with other mods
i have so much more dialog to write 😭
How hard would a Joker effect of "first hand of the round using Plasma Deck scoring" be?
"I could feel it in my potassium" 🔥 ✍️
context.final_scoring_step for plasma deck timing
then just check for first hand of round, idr what the exact G.GAME value is for that
Imma plan my mod out and then just do what's achievable
Hopefully I'll get all of it
how do i round to 2s
like 2,4,6,8
well its kinda working, the joker does indeed make blue seals directly upgrade it when full
just
leaves a trace behind
heres the code
update_hand_text?
how
idk
🤔
not sure if this is weird timing or if steamodded isn't handling level ups correctly
well i think the main thing is its happening during end of round
when there's no hand displayed
kinda
also retriggering the card isnt copying the blue seal trigger
(like via mime)
ok i'm super confused after a while of trying to work the card skin template mod, how do i do this
it keeps failing to load and gives me this error and i've tried to understand what i'm doing wrong but i don't know code well enough to figure this out myself
i've tried naming things in a billion ways and i also don't get what "prefix_key" means and that's probably part of it
how can i make a challenge to appear in the challenge section, I believe I have everything correct
you might be able to return {extra = {func = function() update_hand_text(...)}, card = card, level_up = true, message = ...}
pretty happy with these so far
think the green on the left is a bit too saturated though
also if someone has an answer to this please ping me with it + try to explain it like i'm 5 cus i've never done modding in any capacity but i sadly have to to reskin the cards (i wish i could just replace a file instead)
i haven't experimented with deck skin modding yet but if you're trying to use the steamodded one i wouldn't particularly recommend it
from first gleam that's like an actual amount of coding
there's frameworks to do it in a much easier fashion
that's probably more digestible
look into Malverk
this is the entire code for a malverk skin, for example
dang that looks a lot simpler, where would i find malverk
thanks a bunch
i don't entiiiirely understand how you use it to only overwrite one joker but you should be able to find a mod that does so somewhere in the discord
then just crib what it does
(if that's what you're trying to do, of course)
does it work for the playing cards cus i'm trying to do it to cards specifically and not just jokers or something
also i assume overwriting one joker would just be pasting all the vanilla textures and then ur 1 edited joker on a sheet or something
though idk how that'd interact with other mods because i don't do this stuff often lol
not sure, i'd guess that it's moreso just putting it on the same place in the sheet then leaving the rest transparent
looking through the wiki quick
where do u find the wiki, i should take a look at it too
there's none for malverk, i was looking at the smods wiki
but it turns out malverk isn't the right mod for this 
there's an Example folder on this mod page on how to make it compatible
ahhh i see malverk is for the other stuff then, got it
i might still end up using it though at some point so that's fine
oh wow this one is Simple
so your mod directory should probably look like
assets
-1x
-2x
skins
-(your skin lua)
info.json (for steamodded)
and that should be it
of course, this is just me looking at the examples
i am so glad people smarter than me made tools for this lmao, thank u again
Is there a way I can make a suit skin change the name of the suit its over? I.E. King or Hearts -> King of [Skin]
My question still remains, what is a simple way to program a Joker that lets Ace Straights wrap around
Do I have to override the function if I'm changing something in SMODS?
Patch the get_straight function 😛
so i've run into another issue this time lol
slightly changed it
funnier this way, i think
deck skins lite crashes on startup if there's any lua files in the skins thing at all, even the examples
Idk how to do that
what's the crash, specifically
attempting to call a nil value
screenshot?
No worries. I'm asking to see if it's possible to patch it with a toml file or if you have to override the function because I'm modifying that exact same function
that sounds like you didn't provide a value
i also checked the readme for help but beyond changing the name it's not workin'
oh wait
are you trying to put them in deckskinslite's directory
you want them to be in their own mod
oooooohhh ok that explains it
Anyone know if it's possible to write a patch for another mod's function, and if so, how you would do that?
oh yep that fixes it thank u once more haha
i don't know and this is speculation but i THINK take_ownership is the start of what you want
not sure of anything else
Won't take ownership just let me modify the properties on another GameObject?
I really just need to change one line in a function used by SMODS
not entirely sure then
that's just what i saw come up skimming through the docs
I don't want to have to change the whole function if I can help it, but I will if I need to
@frosty dock sorry for the ping if you're not the right person to ask
but minor bug
steamodded seems to handle negative money in calc_dollar_bonus visually fine, EXCEPT when numbers get so large that it turns to just actual values
(actually, should probably have filed this as a git issue...
eh, already pinged)
a snippet of the most crackhead code i have ever written
Is it okay to use code from other mods as reference if they have done something similar to your idea
this is the only source on it
so if you're copying an entire joker, you probably want to ask ahead
but if you're copying a function or whatever
something small
you're almost certainly fine
Yeah that's what I meant
that's OSS babey
Depends on the author, but... legally you're not getting in trouble
I mean it'd be easier if I knew which file in Balatro contains the actual code for shortcut
It seems to be one of the most complicated Jokers if its effect is scattered throughout like ten different files
Do you have your environment setup?
What does that mean (Sorry if this question sounds dumb)
The function you're looking for is get_straight in src/overrides.lua in SMODS and functions/misc_functions.lua from lovely
But, if you haven't downloaded those two yet, you won't find them 😛
I have them both, I've already begun coding my mod, it's just this Joker I'm trying to make
The SMODS override rewrites the function, though, so... you'll probably have to rewrite it, too :/
Either that, or take ownership of the _straight PokerHandPart and add another check to that for a wrap-around straight
Okay, I think this is too advanced for me
I've literally just started trying to make a mod, thanks for the help tho
A wrap-around Straight is... harder than an average mod
balatro has specific code to prevent wrap‐around straights; disabling that protection is simple
im smoking on that abusing the parser shit
Can you patch out that code, or do you need to rewrite the function, though?
so if I do get around to making it, would I use Pokerhandpart or get straight function?
If you want the easy way to do it, just copy the get_straight function and remove the line of code that's stopping wrap-around if you have your joker
Which part stops wraparounds, also, will it work if I copy the function from Overrides
considering shortcut seems to be baked in the solution is gonna be hacky no matter what
So I've written local can_wraparound = next(find_joker('tes_mobius')), now I need to find how to make it wraparound
If you just copy the function from overrides, you'll be totally fine, but the line you're looking for is probably... if not next(vals) then break end
I'm assuming it's line 191
Yeah. I think that line stops the search if you hit the last value in the list of ranks without finding a straight
I'm not a Lua dev, so I'm really stretching my programming knowledge, lol
I just wrote some nonsense so i'll boot up balatro to see what the code doesn't like about it lol
Ok it worked up until I tried to discard a card
I mean i didn't manage to test if the function worked, it just didnt crah until then
Nice. It's always nice having things worrk until they don't!
I found the problem, I wrote find.card instead of find_card
so far every mistake I've made has usually been some spelling error
I'm bad at typing lol
That does tend to be most of the errors for me, too
I'm too used to IDEs that stop me from making mistakes
ok that wasn't it
It doesn't consider it a straight yet
judging by the shortcut and four finger code I'll have to add something, I just don't know what
No, removing that line isn't going to fix it. It'll need to have the ranks reset back to the original after that
Oh wait, maybe it should
It's not a bad change, but it sadly doesn't work for me. I'm looking to add in a card that's any other type of card, and I had to rewrite the function to accommodate Rank wilds.
i'm so sad that require doesn't work in smods mods
I also had to fix the hand thing to show as Royal Flush
I'm gonna give up
how does smods priority work actually
not worth the effort
It's less about the effort and more about learning. I think you're pretty close
looking for feedback from ppl better at math if this is too strong at X1.5 for an uncommon
(art by lyman
)
If you had 100 chips, then it would set that to 60 and gain 60 mult
I would say yes, definitely
hmmmm
It's kinda like the one deck, but way less strong
well with this, if you had 300 chips and 1 mult you would end up with 180 chips and 121 mult
Is it? You need to have a Chips build, and Chips builds are inherently less strong
with plasma, you would have 150 chops and 150 mult, which I think is better
But, it does provide another avenue to make a chips build work
Yeah, but you go for mult builds with plasma
And the halving is done at the very end, which is a major contributer to it being strong
you can put xmult jokers aftet this effect too tho
Buuut, being that it's a deck, maybe it is too strong
I assume this applies after card enhancements and hand effects, though?
it applies on the joker
i would probably say "at a 2:3 rate" so nobody looks at this for half a second and goes "wow!!! xmult!!!"
That's more confusing
or "(2 chips -> 3 mult)" if you want to be less ambiguous
and techincally wrong
its the way it is so pokermon energy scales the ratio bc it is xmult internally
It's strong, stronger than most jokers. Maybe just lower it to converts chips to mult at a 1:1
it just applies to its own mult
ah
What if it turned 50% of chips into mult at a 1x rate?
other joker number changes work probably too
what if it simultaneously turned 50% of chips into mult and 50% of mult into chips, both at a 1x rate?
Red herring joker
So, basically, it does the Plasma effect
ohoho no, thats not plasma deck, its transfusion!
What if there was a red herring joker that just said +1 Joker slot
(if it just turned 50% of chips into mult, then 2 x 100 would become 1 x 101, which is not what plasma deck does)
goes hard as negative i suppose
Also gives you something to sell for that one Boss Blind
Funnily enough I never seem to encounter that one anymore
I only ever get violet vessel
oh no!! it'll make the hands jokers obsolete
the run killer
is there example code for Hiker for modding?
you can find it inside lovely/dump/card.lua in your mods folder
it seems like it just increases the other card's ability.perma_bonus by 5
Hiker actually seems pretty simple
elseif context.individual then
if context.cardarea == G.play then
if self.ability.name == 'Hiker' then
context.other_card.ability.perma_bonus = context.other_card.ability.perma_bonus or 0
context.other_card.ability.perma_bonus = context.other_card.ability.perma_bonus + self.ability.extra
return {
extra = {message = localize('k_upgrade_ex'), colour = G.C.CHIPS},
colour = G.C.CHIPS,
card = self
}
end
If I finish this mod, I might get round to making the ZOdiac one
i got a joker thats so similar to this 😭
the lua dump is always a life saver for me... until i find out that the function i'm looking for has been replaced in steamodded outside of lovely and i have to look there instead
It''s a sad day every time
smells like incorrect behaviour
i thought that in most lua oop libraries you'd use something like c_number.super.__new(self, v)
instead of self:super(v)
nah, this is my own
makes sense
what is c_number.super?
or self.super i would assume is the same
oh that's a special value
it's actually not
wow
self.super doesn't exist outside of the constructor
i love lua
i love lua so much
i need a proxy object here, actually
maybe even two
the weird functions (_unpack et al) are to maintain compatibility with every version of lua past 5.0 (which introduced metatables, which this uses to great effect)
scary language imo. like at first i was like "wow this is really convenient and intuitive" and then every time i try to figure out how it works on a deeper level it's just The Horrors idk
javascript core
the horrors are the best part of it
python actually enables much worse horrors but i don't know it
or well i do know python but i don't know the horrors
i have heard that that's the case
As someone who has just begun modding (and coding, really) I have no opinion on lua
also you think this syntax is scary, you haven't seen what this library can do
ok anyone know how I would make a joker than turns scoring wild cards polychrome
i'd look at midas mask
to check if a card is a wild card i think you use c.ability.name == "Wild Card"
and to turn a card polychrome i think you use c:set_edition({ polychrome = true })
where c is the card you want to modify
ok thanks, i'll try it
what midas mask does is it first counts up all of the face cards and stores them in an array, does nothing if the array is empty, and iterates through everything otherwise
that way it can display the thing that says "Gold" only when it actually does anything
so I've got this here, do I wrap it in a calculate function? If so the context should be card scored right
or no... i have no reading comprehension sorry
it does the effect inside the loop
midas mask applies its effect in context.before, same as vampire
do you want it to happen at the moment the card is scored?
I want it to be like midas mask in that sense
alright
so (self, card, context.before)?
i think you'd do
calculate = function(self, card, context)
if context.before and not context.blueprint then
local wilds = {}
for k, v in ipairs(context.scoring_hand) do
if v.ability.name == "Wild Card" then
wilds[#wilds+1] = v
v:set_edition({ polychrome = true }, true)
G.E_MANAGER:add_event(Event({
func = function()
v:juice_up()
return true
end
}))
end
end
if #wilds > 0 then
return {
message = localize('something or other'),
colour = G.C.DARK_EDITION,
card = self
}
end
end
end
those are the arguments to the function, i don't think you want to ever touch them
Thanks!
if you don't want the edition sound to play 3 times at once (and therefore possibly be really loud), maybe you could pass #wilds > 1 as a third argument to v:set_edition
Nah I think its funny
alright
also i love how nobody pointed out the undertale font lmao
i forgot that this is an actual screenshot from the game so i assumed it was just like you didn't have the balatro font on hand lol
I thought it was a compression thing tbh
its so slightly different i love it
Where in the source code does it render the crystal thingy for the Soul card
I want to try the sprite overlay effect like it has
Oh damn that easy?
yes
What if I want to change the soul sprite mid-game? I plan for my Joker to change it whenever a certain condition is met
I have tried to change the soul sprite mid-game via changing atlas coordinates, but for whatever reason it doesn't change until the entire card stops rendering
Man
Here's the attempt I made btw
My guess is Thunk never expected the soul sprite to change and therefor doesn't have a handler in vanilla to update the sprite frame by frame
if you change pos or soul_pos it changes for every instance of that joker btw ( god i love pointers and references )
wonky
and yea once a sprite is readied for a card its left as-is, you have to handle that
Wack
I’d imagine it wouldn’t be too tricky to implement a handler for that, you’d just have to dig for where that soul rendering code is to begin with
So who wants to be the first to invent proper soul sprite swapping
How can I ha e an update run every second
I want to do something every second until I tell it not too
I’d recommend taking a look at Cryptid’s code, specifically Jimball or The Clock. I have an implementation of it for my own uses as well but I currently do not have access to it
hmmm
trying to brainstorm how to add all broken cards back to deck
something something
if context.cards_destroyed then
add_card yadda yadda
but i don't know how to actually retrieve what just broke
Idk what the dt is
Lobotomy Corporation (mod) does a version of it
All being every destroyed card in a run or in a hand?
Price of Silence updates and plays every second
every card destroyed (e.g. hanged man, glass card) should get re-added to deck
when it gets destroyed
i'm just not sure how to retrieve that
dt is short for “delta time,” which is the time that passes between frames
ah, so just accumulate that to 1000
Actually just 1 since dt is a float value
okay that's something
now to learn what that colon actually means in a broader sense
so i can get the full card's details
and add it as a thing
The colon signifies a function the object class can execute
okay it just means it's adding itself as the first parameter
so it's effectively calling get_id(other_card)
Yep
but that's happening in that context
i think i get it
now to find where in the documentation i can look at the list of permissible outputs...
If it helps, context.cards_destroyed is a table of all cards that are to be destroyed
Or one of the contexts that has to do with destroyed cards, I forget if that’s the correct one
Check the Joker Calculation page on the SMODS wiki, I’m positive the correct one is listed there
i really want it to be this easy but i just know it's not going to be
Ok I was right, context.cards_destroyed is a table/array of all cards that are to be destroyed. You could probably loop through that to get the cards back
Stone card build time.

It works
*kind of
*once
Things went sideways I see...
yeee
Why the Mars font?
its undertale font idk
Yeah, the uh name of that font.
I accidentally was referring to a different font Undertale used. 🤦♂️
It's neat that you were able to do that.
...okay, huh
this isn't doing anything
like, there's no log output when i destroy cards
Literally Forgot To Give Myself The Joker
Anyone knows why it keeps triggering?
...does glass_shattered not actually mean shattered glass cards?
this game eludes me.
it hits itself
its perishable and it doesnt fit the other criteria
💥
hmmm
won't it always return true
if not (X)
it's not perishable
so it isn't not perishable
so it, itself, counts
context.other_joker.config.center.key to see what it is
or am i insane
it's [not perishable]
the check is if it's (not [not perishable])
do vanilla jokers use j_ in the key
or can I just type "Egg"
yes
Anyways ive figured out the issue
It kept activating because it had xmult as ability, I changed it to extra (like baseball)
a glass card just broke and nothing happened
i'm so confused
...okay, apparently i was supposed to use these
okay, i think i get it now
now to figure out how to add it to deck
I’d say for every iteration of the loop, do local new_card = v:copy_card(parameters) and do the typical add and emplace cycle from there
...huh, i thought copy_card would add it to hand but reading it seems more like it just returns an actually digestible version of that card?
it just makes a new card object based on the old one iirc
so you then can add_to_deck and emplace it somewhere
huh, i was gonna use table.insert and just call it there
it's hard to read this game's code
grah
oh right i need to initialize it with add to deck or something
i miss SMODS.add_card now i actually have to figure things out
(since add_card seems to only work for non-"cards"), like tarots and jokers
guys why doesn't overriding the localisation with take_ownership work properly 😭
SMODS.Consumable:take_ownership(
'lovers',
{
loc_txt = {
['default'] = {
name = 'The Lovers',
text = {
"Enhances {C:attention}#1#{}",
"selected cards to",
"{C:attention}#2#s",
}
}
},
config = {
mod_conv = 'm_wild',
max_highlighted = 2
}
},
true
)
loc_vars?
wouldn't that use the default ones if I'm not overriding it?
not that i know of
loc_vars is what corresponds the positions of #1#, etc
to actual variables
so that you could, for example, insert game variables like odds base
It would yes, however I think you may need to change it to adapt to your new config
I thought it would just use the config I provided since I'm changing the config
this is default loc_vars = {_c.config.max_highlighted, localize{type = 'name_text', set = 'Enhanced', key = _c.config.mod_conv}}
I’m actually not sure, but I think it’d be worth trying to re-input it
alright trying it now
hmmmm
You’re creating two different copies. You should be setting a local variable to hold the copy and then go through the process
I’m not sure G.playing_cards is a valid area to emplace a card
oh wait, is that the hand
No, I think that’s the info of the full deck
Still saying nil for both, did I do this correctly?
local new_config = {
mod_conv = 'm_wild',
max_highlighted = 2
}
SMODS.Consumable:take_ownership(
'lovers',
{
loc_txt = {
['default'] = {
name = 'The Lovers',
text = {
"Enhances {C:attention}#1#{}",
"selected cards to",
"{C:attention}#2#s",
}
}
},
loc_vars = {
new_config.max_highlighted,
localize{type = 'name_text', set = 'Enhanced', key = new_config.mod_conv}
},
config = new_config
},
true
)
it's a start. i guess?
they're just sitting there now
hmmm
i'm just stealing most of the code from marble joker
This is uncharted territory for me at this point, my apologies
Best of luck
In my experience that’s typically a sign of a failed emplace
I got it working, didn't know loc_vars had to be a function
SMODS.Consumable:take_ownership(
'lovers',
{
config = {
mod_conv = 'm_wild',
max_highlighted = 2
},
loc_txt = {
['default'] = {
name = 'The Lovers',
text = {
"Enhances {C:attention}#1#{}",
"selected cards to",
"{C:attention}#2#s",
}
}
},
loc_vars = function(self, info_queue)
info_queue[#info_queue+1] = G.P_CENTERS[self.config.mod_conv]
return {
vars = {
self.config.max_highlighted,
localize{type = 'name_text', set = 'Enhanced', key = self.config.mod_conv}
},
}
end
},
true
)
Ah there ya go
thanks for the help 🙂
i mean. i can move them around now?
i think this is actually working though?
they're getting destroyed and immediately recreated
they're just not uh. moving to the deck
GOD IT'S WORKING
for anyone message searching how to add cards to deck, destroyed cards or otherwise (since it's hard to find)
calculate = function(self, card, context)
if context.remove_playing_cards then
sendWarnMessage('card destroyed', 'muuyo')
for i,v in ipairs(context.removed) do
G.E_MANAGER:add_event(Event({
func=function()
sendWarnMessage(inspect(v), inspect(i))
card.ability.extra.resurrected = card.ability.extra.resurrected + 1
local copied = copy_card(v)
-- here's where the deck shenanigans happen
copied:add_to_deck()
G.deck.config.card_limit = G.deck.config.card_limit + 1
table.insert(G.playing_cards, copied)
G.deck:emplace(copied)
play_sound('myo_greenzwin')
return true
end
}))
end
end
end
you want this
Huge
That is huge
Pretty sure you can just use SMODS.add_card right?
the shit i do for balatro
i wrote this library to make writing my own mods easier
but uh hey that's like
real object orientation
in lua
real
What’s the need for this?
mostly making it much easier on me to build custom systems
i don't expect anyone else to use it within balatro though it is a very useful tool for general use in lua
doesnt smods already provide this
you can just make something that extends SMODS.GameObject
not sure, but it's lua 5.4 compatible so i can take it outside of smods and make whatever i want with it even outside of balatro
i guess
were i at home id show the code for joker Stamps
you can just make a new kind of SMODS object and register them like Jokers or Consumables or Seals or whatever
that's neat that this scaffolding is already in smods
yea i havent had much experience making whole new systems because im lazy
but its totally doable
also balatro has an object system built in it uses
however baaltro also has a ui system but that didn't stop me from making my own
ok but like the balatro ui system
nodes[1].nodes[1].nodes[1].nodes[1].nodes[1].nodes[1].nodes[1].nodes[1].nodes[1].nodes[1].nodes[1].nodes[1].nodes[1].nodes[1].nodes[1].nodes[1].nodes[1].nodes[1].
thats only if your modifying the ui
if your making stuff from scratch it's fairly reasonable
this hopefully addresses the issue of nodes[1] chaining
see changes for more info
Should document that
i like writing lua because it's a lot of fun so writing my own class system is just something fun to do also
no other language lets me get this level of fucked up, except maybe python my girlfriend's been telling me a lot about python's metaprogramming capabilities
I think that it’s also easy to visualize in one’s head what the UI is going to look like just from its construction
writing things from scratch is a great way to understand how they work, can recommend
I wonder about Julia
Making my own ui system made me have a lot of respect for how well
s ui works. Like sure the code is a bit messy but it's super stable, flexible and looks and feels quite good
Yeah there’s a lot of weird stuff in the code but what thunk has done is very impressive
I mean a system written, maintained and ysed by only one person is likely to have a bunch of werid quirks to outsiders
I bet there's a bunch if weird stuff in DebugPlus that just makes sense to me
you can patch into smods files with Lovely 0.7 just fine
huh okay
I'd like to see what you came up with, I've tried to implement rank wilds but didn't arrive at anything that would have been sufficiently efficient
SMODS.load_file:
I still think lazy DFS is the way to go
I don’t know how you could do better with an arbitrary graph
elaborate
With vanilla ranks you can aggregate different nodes in the graph per rank since each set of nodes only connects to the next and previous ranks
With quantum ranks, it could be anything so you’d have to walk on the full graph
I know, but what do you mean by lazy DFS
It only looks 5 deep then moves on
So it gives up instead of going on
so how do I know a path of the desired length is actually a straight? the bipartite graph of cards to ranks needs to have a matching with n edges for that to be the case
If you find a path of length 5 it’s a Straight
in what graph
The graph of cards
oh alright, I was looking at the graph of ranks
But you need to avoid cycles
Which DFS should already do
Also with the original graph you could cache results
But I’m not sure about the arbitrary graph. I think you should but I don’t quite see it right now
yeah I think I see where you're going
can't have it be lazy because it should find longer straights if they exist
so I find longest paths in each component of the directed graph of cards...
What do you mean longer Straights?
There are no longer Straights
if I'm looking for 5-straights, I'm allowing 6-straights
But you don’t need to look for them
Surely it should look for X-straights where X is the number of played cards?
No it should look for (find_card(“j_four_fingers”) and 4) or 5-Straights
if I'm including 5-straights when four fingers, clearly I need to include 8-straights when no four fingers
i thought this meant like
straights don't exist anymore
That’s just an argument
There are only Gays now
well shit
And what about for mods that look to increase played hand size and add longer straight support? It makes sense to build the functionality in at a base level
Again
It’s just an argument
no what I'm saying is this
lazy_dfs(depth)
am i interrupting something
well if there's no straight this long then you're not going to get that deep before there's nowhere else to go
what
The Straights are fighting
that's not good is it
the graph of cards doesn't have a 4-path if there's no 4-straight
the only time it gives up at 6 is when there's already a 5-straight
at that point I'm going out of my way to not find the extra card
that's now what I'm saying but okay
how easy would it be to have a joker that checks if your played hand consists of one three and two unrelated cards and transforms them into that three? for example if you played ace of spades, four of clubs and three of diamonds, you would get three three of diamons
Also I think there's still some issues here. Like what cards a card is adjacent to changes depending on what rank it's acting as
like what if I have a (A,2) (3,4) (5,6) (7,8) (9,T)
yeah so one would have to make some weird splitting graph that separates outwards vertices by rank
I think I’m not understanding what you mean
Maybe instead of cards as nodes it needs to be some kind of hypercard
Actually maybe not
The “rank” of a card is only important as whichever edges are used
So it’s like
Duck-typing
yeah but the incoming edge decides which outgoing edges you're allowed to use
with info_queue i've found the appropriate format in localization files, however i'm not sure how to define my own custom bubbles. how could i do this?
i looked at the chocolate die in cryptid and found this:
elseif not center.added_to_deck then
for i = 1, 10 do
info_queue[#info_queue + 1] = { set = "Other", key = "ev_cry_choco"..i }
end
else
SMODS.Events["ev_cry_choco"..center.ability.extra.roll]:loc_vars(info_queue, center)
end```
though im not exactly sure what it is doing
Do you have a localization folder with default or en-us file in it?
yeah you should do separate localization
well the way cryptid does it is by concatenating a string
"ev_cry_choco1" is the first entry then it loops through every entry with the for loop
mhm
you can do it like that too, or you can do it by looping through a list with all the names of the localizations in it
are you on the uh
pretty similar to what im used to
json metadata
and i'm assuming you're still using the loc_txt for stuff
ok in the json file make a new value called dump_localization and set it to true
How can I use a joker to stop all sounds
remove all your other content mods, then boot up balatro and close it again
In your mod, you can add a localization folder, with a default.lua file and put
return {
descriptions = {
Other = {
new_desc = {
name = "New Description",
text = {
"This is my awesome description!"
...
yea i saw this
that will automatically dump localization for your mod to localization/dump
Yea
the auto dump is super nice for starting it
ill just do it manually tbh im particular about formatting and i dont have a lot
i think you should still do it with the auto dump
itll be faster and ensures you don't mess anything up
thats the fun part
alright suit yourself then
this is common
note that cryptid specifies the "set" of the entry, you should put these in the other set like cryptid does
the set is the group they're in yh
and make sure you remove all loc_txt from your mod when you're done
yep
wdym
especially when the joker gets an edition or a sticker
oh if you're only doing the one thing
If your object has a child with an info_queue too, all children info_queue will show up
you dont need to do any extra localization stuff
well because of how i've structured the edition, it needs info_queues
(This sound weird lol)
you can just put the center for the edition in
otherwise the box doesnt render properly cause there's too much text
im going to start modding balatro what text editor should i use? VS Code? Sublime text?
vscode with the lua plugin
just the one named Lua right no others
ok cool thanks
i have everything set up should i just download another mod and look at its structure and how it does things and stuff?
thats what ive been doing
yeah that's a good start. you can also look at steamodded docs
cryptid has been pretty handy since it does so much though it structures things slightly differently from regular steamodded
yeah i have that open i think as well
so should i start by lookingat that?
can also recommend ortalab as a reference mod
and if you have any specific questions you ask here and wait for one of the bigger fish to help you with it
ok thanks
like what would be the best way to check if the played hand contains three 7s in a row
so i put everything (lik all the code) in the main.lua?
yea its also helpful
or just stuf that executes when mod is opened
ive tried a lot of things that either have triggered on every hand, or on no hands, regardless of how many 7s they have
you can structure your mod into different files too, but just putting everything in one file works just fine starting out
yea
the way i've split it out is put the separate files in a src folder
then in the main lua, this:
for _,v in pairs(NFS.getDirectoryItems(path)) do
assert(SMODS.load_file('src/'..v))()
end```
where do i find the cryptid mod is it on nexus
github!
i just put everything in one file cause i cant be fucked with all the extra file shenanigans
real
yea idk ig ill just do that at the start too and maybe ill start making more files but idk
it's fine so long as you don't have like 10k+ line files
how does one define localized variables for a localization file?
you need to put them in a specific area for them to do that
under misc and under v_dictionary in misc
Do the 7s have to be next to each other?
misc where
ideally yeah
in your localization file
and then how are they referenced?
i'll just get a screenshot hold on
ty!
what mod shouild i use for debugging?
Loop trough the scored cards, if you got a 7 and the next one isn't you reset the count to 0, if the count reaches 3 or above then gg
localize { type = 'variable', key = 'my_key', vars = {'a', 'b', 'c' } }
for simple dict entries (that don't need changeable vars), you can just put them in misc.dictionary
and reference like localize('my_key')
the vars are like the
well thats the thing
yea i know this part
to make the values show up in those places
the problem is that idk how to reference the variable i want, since its a property of the edition
and it can change
it should just use the base variable
well we can't tell you if we don't know what property you're referencing
unless the edition changes globally
my code crashes if the card is at the very right side, and the UI tab has no color
@stiff locust
You can call the editions loc vars function and use that
on the edition it's card.ability.extra.count, the intent is that it can be changed globally
by boss blinds, jokers, etc etc
chat am i cooked
It's because of the G.jokers.cards[i+1], do #G.jokers.cards - 1 instead
isnt that just always the right most card?
If you reach your last card and check for G.jokers.cards[i+1], it will crash because it doesn't exists
#G.jokers.cards - 1 stops before the last card in the loop
or you could do #G.jokers.cards to check every single one
since lua arrays start at 1 for some reason
Seeing other_joker, I think they're trying to do something with the card on the right of the joker
what you should do is you assume you're incompatible if you're the rightmost
yea, blueprint
ahhhh
its just the blueprint thing
i mixed up who was who
the issue is still alive
Can we see the crash log?
when i open balatro its doing this:
I have enabled developer mode i think i did the thing with the if not _RELEASE_mode and stuff and i have a few mods
it works now
does anyone know a base game sound (or custom sound) i could use for when a joker doubles probabilities
i think it'd be cool if it made a noise
actually wait
i've got the perfect sound
so how do I play a custom sound
Where are you playing it from?
fixed it
i don't know yet lol
i had to add card.ability.name = 'Blueprint' at the start
i'm assuming i drop it in sounds folder
is there any specific format or is it just anything common
ohh wait i get what this means now
a joker
You can add sound = ‘soundkey’ to the return table assuming you have a message
there is no return table on it
Sounds are generally .ogg format
it doesn't return anything
can i still put a return table in without it messing things up
Could someone help me diagnose a game crash?
i want the sound to play when the 1 in 7 hits (yes it's hardcoded and that is intentional)
Okay cool, instead of card eval status text just return your message, colour and sound
Oh replace that too
oh what why
I guess you don’t have to
Anyway, before the else put your return table
After you’ve adjusted the probabilities
nvm i think it was a mod or smth
so what's the sound key
does it have any prefixes
do i include the file extension
why is there two...
SMODS.Sound({
key = ‘key pls’,
path = ‘filename.ogg’
})```
assets/sounds iirc
ohk
Deck idea: odd hands provide the chips for a mega-hand, and even hands provide the mult, which are then multiplied again after every even hand
And to counter balance that ludicrous scaling you would start at ante 9 or smth
i believe you're looking for the meme suggestions thread
#1187936299655647313 that would be here
i moved main end to the end and it still occurs
why do you have card.ability.name = 'Blueprint'?
at the start? because thats the only thing that gives it the color
well then you're making blueprint give you its UI
also we can't have nice things, there's no negative indexing
the sound is not playing but everything else works
what do i do then
i defined it here
SMODS.Sound({
key = "probability_tm",
path = "lucky.ogg"
})
and here's where it is meant to play
return {
message = localize("k_probability_tm"),
colour = G.C.GREEN,
sound = "probability_tm"
}
with or without tsun_ at the start of the sound = argument it just plays the regular message sound
and i made sure the file's there and it works
and it's an ogg
it definitely needs the prefix
okay well the sound still won't play
What smods version are you on?
People still developing on old calc smh
i'm still waiting for cryptid to go to better calc
not even old calc, that's old calc - 1 week
it's close to done
that's nice to know
i suppose I will leave this joker as it is here then
it'll work on better calc so i trust it
that means it's done
and apparently people gamble on like, boats
do i need too open and close the game everytime i change something to test it or is there an easier way?
so they get international waters and international laws for gambling
okay, i just did this and it works fine
loc_vars = function(self, info_queue, card)
card.ability.name = 'Blueprint'
return { vars = {card.ability.name == 'Blueprint' }, main_end = main_end
}
you can hold m to let steamodded restart the game for you. there's also DebugPlus' watch command which could be useful depending on what you're doing
when i installed debug plus it doesnt let me do any debug things not even vanilla
hold tab
ID = "test mod"
NAME = "Test mod"
function preload()
aml.patch(aml.game,"init_window",aml.prefix,function()
aml.game.SETTINGS.screen_res = {
w = 1920,
h = 1080
}
end)
end
function postload()
for _, value in pairs(aml.game.P_CENTERS) do
if value.set == "Back" then
value.config.joker_slot = 10000000
end
end
aml.patch(aml.globals.Card,"redeem",aml.postfix,function()
if aml.game.GAME.current_round.voucher == nil then
aml.game.GAME.current_round.voucher = aml.globals.get_next_voucher_key()
end
end)
end
thoughts about this modloader usage syntax
i was it wasnt making a menu show up when i uninstall it the vanilla goes back to normal and works tho
do i need to set the vanilla debug to not debug
do you have a different mod that enables debug?
well i went into the config and did it myself does that affect it
yes
you should
ok
how do i print only the name of JokerToSelect
if G.jokers then
local jokers = {}
for i = 1, #G.jokers.cards do
if G.jokers.cards[i] ~= card then
jokers[#jokers+1] = G.jokers.cards[i]
end
end
local jokertoselect = #jokers > 0 and pseudorandom_element(jokers, pseudoseed('crypto')) or nil
print(jokertoselect)
jokertoselect.ability.name
okay, how do i make sure it only selects once per hand
because its now just a loop
Where did you put your block of code?
okay, this is gonna be a bit of a stupid question - but where can i find the documentation for psuedorandom_element?
ModdedVanilla.lua
Is this all? Are you doing context checks?
let me put the code
where can I find this lua file?
calculate = function(self, card, context)
if G.jokers then
local jokers = {}
for i = 1, #G.jokers.cards do
if G.jokers.cards[i] ~= card then
jokers[#jokers+1] = G.jokers.cards[i]
end
end
local jokertoselect = #jokers > 0 and pseudorandom_element(jokers, pseudoseed('crypto')) or nil
print(jokertoselect.ability.name)
end
return {
}
end
}
i do think i need context
Yea your code is running for every context that exists lol
I recommend checking this https://discord.com/channels/1116389027176787968/1247703015222149120
smods / Steamodded folder
thanks
i think id use if context.other_joker as i plan to make this card like blueprint
how exactly does in_pool work for boss blinds?
Oh yea blueprint jokers don't check contexts
okay I'm probably not looking at the right places because I can't seem to find ModdedVanilla in my smods-main folder
my apologies
Check line 2303 of card.lua