#💻・modding-dev
1 messages · Page 393 of 1
or heavily modify existing code
you cant
is it supposed to be modprefix.Pi?
the balala font doesn't support pi symbol
is there anywhere to generate balala font text for card sprites?
the type might be an invalid key
the font on cards is handdrawn and not consistent
ok
idk i guess?
what's in the joker config?
it was modprefix_Pi
i wish i couldve made it so it need to be 3 10 4 to give that pokjer hand
but idk how to do that
what do yall think the best way to explain to a player why they lost is
i cant achievement on the game over screen nor the next run sooo
im out of ideas
Have jimbo say it?
how do i do that
this is what i have for my tarot card so far, dont know what to put on the inside
You add a custom quip and you patch where he says things on the losing screen.
could someone help me with a problem i'm having?
well depends on what the problem is
I think it's reletivly simple, just need a bit of help starting it up
Yes, but what is the problem?
where do i add quips?
localization > misc > quips
ty
Then it's like ```lua
again = {
"Again!"
}
I am making a joker that gives 1.5x mult upon scoring a gold card, but has a 1/3 chance to destroy said cards, but I cant make it destroy the cards after giving 1.5x mult, only before
Code?
what function determines what quip to use upon run loss?
Jimbo:add_speech_bubble('again', nil, {quip = true})
do most mods limit to the default 5 jokers, or do they extend this limit?
You mean joker slots?
yeah
how do i fix this? (a joker generates them)
like... how many would be seemed balanced?
Quite a few, probably.
i was thinking maybe about 10 joker slots
at first i thought it's cheese 😭
its supposed to be destroyed houses
bc they cant be maintained in an apocalypse
because i dont want to draw people
is there a context table that stores held in hand cards like how context.full_hand stores cards played? or even played and held cards combined
ohhh nice ty!
what would i return to set the quip?
i cant find where in the code this function is actually defined
only the uses of it
game.lua in Game:update_game_over
ngl i dont feel like doing it again bc i already put it in the assets folder
i literally have a joker called Jegg its not that deep
probably overlooking something obvious, but it seems that the pseudorandom function returns 1.9 as a value, but that's above the max value I've given
i thought it only did integers with min/max
i see an ice and an n, happy day
hii dilly
hello
money amount is showing as nil in card desc
you have money at #1#
Yo, Dilly
it's set to "dollars" in config, should be "money" (and #2# should be #1# in the description)
I've spent too much time just hanging out here helping people install mods, haha
Dilly 🔥
how do i get the currently selected cards for consumables?
G.consumeables.highlighted[1]
still shows as +nil
did you also change the config?
so would i use like #G.consumeables.highlighted == 2 to find if the player is selecting 2 cards rn
why doesn't this overwrite the jimbo quip on run loss?
para_jimbotalk_old = add_speech_bubble
add_speech_bubble = function(self, arg1, arg2, arg3)
if true then
para_jimbotalk_old('pineapple', nil, {quip = true})
else
para_jimbotalk_old(self, arg1, arg2, arg3)
end
end
oh i read that wrong sorry
G.hand.highlighted
yea
i dont need which consumables are highlighted
although that is interesting
ill keep that in mind
does this extend to the cards in arcana packs?
what do i change (im very stupid so sorry in advance)
so do i need an or
yea ok
im tired i need to get off work
bump
ah ok so i got it wrong lol
can i use
config = { extra = {
cards = 2
}
},
loc_vars = function(self,info_queue,card)
return {vars = {card.ability.extra.cards}}
end,
for consumables or do i need to change some stuff
thank youuuuuu
the hashtags around numbers tell the code which variable from loc_vars to reference, so even though its $2 per card, it should say $#1#
got it
perfect
SMODS.Consumable{
key = "Infection",
set = "Tarot",
loc_txt = {
name = "Infection",
text = {
"Enhances {C:attention}2{} selected cards to {C:attention}Virus cards{}"
}
},
atlas = "Infection",
pos = {x = 0, y = 0},
cost = 3,
config = { extra = {
cards = 2
}
},
loc_vars = function(self,info_queue,card)
return {vars = {card.ability.extra.cards}}
end,
use = function(self,card,area,copier)
for i,v in ipairs(G.hand.highlighted) do
v:set_ability(G.P_CENTERS["m_CGN_Virus"])
end
end,
can_use = function(self,card)
if #G.hand.highlighted == card.ability.extra.cards then
return true
else
return false
end
end
}
so would this work for a tarot that adds an enhancement
eh ill just test it
bump
tarots have config options to do it automatically
check vanillaremade :3
but the code looks correct
sorry for asking, but has there been any progress on my problem?
what is the problem?
config = {
max_highlighted = 2,
mod_conv = "m_CGN_Virus"
},
loc_vars = function(self,info_queue,card)
return {vars = {card.ability.max_highlighted,card.ability.mod_conv}}
end,
``` so just this?
yes
I am making a joker that gives 1.5x mult upon scoring a gold card, but has a 1/3 chance to destroy said gold card, but I cant get it to destroy the card after scoring, only before
No, you would localize card.ability.mod_conv in loc_vars
use context.destroy_card
bump
if you return that in loc_vars and use it in the description it's going to just be the key, not the name
You don't want to call start_dissolve on a playing card during calculations, generally. The reason it happens before is due to the way the calculations handles animation
You do indeed wanna use context destroy_card
No clue
im just using it hardcoded for the description
at least the enhancement
when I try to destroy the card after the calculations, the game crashes :(
That's why I didn't suggest you should do it that way
Because it is Card_Character:add_speech_bubble
sorry, misread it
:juice_up(0.3, 0.3) what do those 2 args do?
One's duration, other severity, iirc?
how could i tell if the player is in the shop? (from within a consumable)
I can give you the exact variable in a moment but there's a state called something like IN_SHOP. What's the reason the consumable wants to check whether you're in the shop?
it sets the current shop's reroll cost to 0, and this would not be very useful if you're not in the shop
so i'm making it not usable if you aren't in the shop
Ah, makes sense. I can gave you the exact syntax in a sec, but you could check the source code for SHOP in all capitals if you're not that patient, haha
alr, i'll go do that, thx
my game crashes when i lose a run
para_jimbotalk_old = Card_Character.add_speech_bubble
Card_Character.add_speech_bubble = function(self, arg1, arg2, arg3)
if true then
para_jimbotalk_old('pineapple', nil, {quip = true})
else
para_jimbotalk_old(self, arg1, arg2, arg3)
end
end
if G.STATES.SHOP?
I tried to replace the context.other_card:start_dissolve() with context.destroy_card(), but it crashes anytime a gold card scores
You're not inputting self
Contexts aren't functions, they're variables containing an array, number, string or a bool
tryna make a joker that's reserved parking without the 1 in 2 thing, how would i do that?
ty
oh shit i shot jimbo
what mod adds this????
oh i have that one
ah ok
jimbo noooo
one more question, but how do I make it destroy only 1 card instead of the full hand?
context.destroy_card is the card being calculated so you would check if that's the correct card, like in context.individual
sorry, but could you provide a code example? im new to this stuff :(
which card do you want to destroy?
0-all gold cards scored played depending on rng
ok let's say it's all for now
if context.destroy_card and SMODS.has_enhancement(context.destroy_card, "m_gold") then
return { remove = true }
end
ive never worked with joker retriggers before, why doesn't this work?
do you need to do :flip() and have a true/false
wdym
it does
You need to enable an optional feature with SMODS. Add this to your main file:
SMODS.current_mod.optional_features = { retrigger_joker = true }
its not
ive already done that
what's the code
Hmm I see
i'm trying to make a deck that gives you a card whne you start, but when I use it I get this:
too much, gimme a sec
keep in mind that flipping is not done in events so if you do it twice in a row it's going to be the same as not doing it
when is it done
does this reads well?
Try removing the card area check.
here are the docs
you're checking the context incorrectly
it's done in update so you need to make it into an event yourself
the deck also displays as "ERROR"
where'd you find that
I took too long and let eremel beat me to the punch 😔
in my secret special place
my code is 400 over the discord limit
gimme a second here
Also Eremel ty for the hand limit API, very pleased with that implementation 
trying to copy the tarot card flipping and juicing and upgrading and allat
been waiting a while to merge that one 🤣
I put it in, but even when removing the rng function, it still wont destroy any of the cards :(
func1 and func2 don't exist
how would i check when a specific joker caused me to lose in a function hook? (the joker has an effect that makes you lose)
It finally went thru yesterday lol
anyone knows how to exclude cards from SMODS.add_card?
oh i thought that was just for naming a thing
somehow, that causes a crash when discarding?
so its one big part of the table
no, func is a specific field, you need to put everything there
para_jimbotalk_old = Card_Character.add_speech_bubble
Card_Character.add_speech_bubble = function(self, arg1, arg2, arg3)
if true then -- Replace true with if the pineapple made you lose
para_jimbotalk_old(self, 'pineapple', nil, {quip = true})
else
para_jimbotalk_old(self, arg1, arg2, arg3)
end
end
SMODS.Joker{ -- Pineapple implementation.
key = 'pineapple',
config = { extra = {
xmult = 3
}
},
atlas = 'Jokers',
pos = {x = 4, y = 0},
pools = { ["Food"] = true },
rarity = 1,
cost = 2,
blueprint_compat = true,
eternal_compat = false,
perishable_compat = false,
loc_vars = function(self,info_queue,card)
return {vars = {card.ability.extra.xmult}}
end,
calculate = function(self, card, context)
if context.joker_main then
return {
xmult = card.ability.extra.xmult
}
elseif context.end_of_round then
G.STATE = G.STATES.GAME_OVER
G.STATE_COMPLETE = false
end
end
}
card here is your blind
you can't AFAIK
a
you can create an ObjectType or make a list yourself
how would i put a message in between two of the events
SMODS.calculate_effect({message=""}, card)
how would i save something between runs?
how can i change the color of that?
add it to the message table like you would in a return
or just until the next run starts
Put it on the profile.
how do i do that
would this work or am i still messing smth up
yeah
G.PROFILES[G.SETTINGS.profile].variable = value
bump
loc_txt not loc_text
also it's SMODS.add_card
is that a custom ObjectType?
do you have any check for that?
(in the calculate for an enhancement)
canInfect is to stop cards that just got infected from infecting
hasSoap makes it so having soap = instant no infection
no clue why they can pick the same one tho
hmm but don't you set the enhancement at the end?
yea
thats why im confused
do context.after's run at the EXACT same time?
not like one after another?
if you set up an enhancement in the return then context.after is not going to see it
because calculations are done before events
oh, i thought it was something else
so set the enhancement to some placeholder thats not no enhancement instantly
then change it to virus
i assumed it was like create card but different
you can also just do card.virus_infected = true
tysm i never noticed
no smods adds SMODS.create_card and SMODS.add_card
the syntax is also different
so is context after run as
1st card non events
2nd card non events
1st card events
2nd card events
yeah
as in a function inside of a deck
what do you want to add? i dont know what that is in the description
can i just make up variables out of nowhere like that?
or do i have to set it somewhere first
i feel pretty stupid not understand i could have done another extra with my extra simply like this, well i'll die less stupid tonight
yes
they get deleted on reload but you don't care in this instance because you only need them while scoring
nice
okay wait
if its infected
then vampire'd
then can it be infected again?
or will that break it
wait i can just set infected false again
you would need to set the variable back to nil after scoring
like here where it creates a card when you start the deck
no, yeah but what exactly are you trying to create?
a deck where you start with a joker
i get that but which joker
this is an incredibly flimsy solution, but it works so idc
that's what lucky cards do in vanilla basica
lly
SMODS.add_card{set="poolkey"}
(i just hate LOVE2D with my entire soul)
how would i implement this? like as a seperate object? (very new to smods and lua so i'm a bit confused)
@daring fern dont ? me, LOVE2D is ass
Why LOVE2D specifically and not lua?
hi AGAIN :D
how do i check if the selected blind is the boss blind
blind.name returns the name
love both ❤️
love2d has NOTHING
except balatro
python
How do i check for a specific joker? similarly to how this checks for a specific blind
seems like something caclled object oriented
SMODS.find_card("j_modprefix_key")
literally any other game making system is better
tyty
??
horrendously bad take
no just replace add_card() for that
love2d is fun because you can make silly prototypes easily and also make proper games
it is a good engine
well i do not like it
okay fair. but it is not objectively bad
maybe not objectively
i never said that tho
i just hate it bc if youre gonna make smth with lua
id rather go and make it in roblox tbh
have i missed something here?
What’s the extra in soul pos?
"batteries not included" (for lack of a better term) engines are common and good
middle layer
you need next() with find_card because it always returns a table
there's three layers for exotic jokers
i'm assuming that this is an error with the custom pool. do you know what could be wrong with it?
next(SMODS.find_card(...))
ah
oh i thought it was an objecttype
i dont know if those pools do anything
hm, it still has no effect
you need to make an SMODS.ObjectType
it looks like it is an object type
?
you want to create from a pool of jokers? or just a specific one?
yeah from a pool
then make one of these
i've mostly been going off of code that i've seen from other mods(yahimod and cryptid)
it's weird that the way they did it just doesn't work
they may have set those up somewhere else
checking the yahimod, the jokers have pools defined in them and then consumeables can create jokers from that pool no issue
ig consumeables are different from decks in this case
I just checked and yahimod makes objecttypes
is there a detect for when a poker hand level is changed?
Hook level_up_hand?
will do that, thx !
ah ok, do you know where those are defined?
G.GAME.hands[hand].level needs to be to_big too right?
where i linked lol
nvm found it
not sure what the issue is here, it clearly states that chips should be set to mult and vice versa, but ingame it has no effect
does somone know what the key for showman is? I'm trying to make a joker that creates a showman
j_ring_master
yeah of course what else? thx!
localthunk moment
Hey I’m new to modding, does anyone know if there’s a way to put a new image on screen? Like if I wanted a joker to put an image of a cat on the screen when it triggers?
does anyone know why in the world G.STATE == 999 when opening a booster pack?
i can find nothing about this in the codebase
im frankly baffled
AAAAAAAAAAHHHHHHHHH
why
why does smods need to do this
does it just bypass all other booster states?!?!?!?! @daring fern
how does one make a rarity badge be ✨ gradient ✨
When a booster pack is opened yes.
SMODS.Gradient
i mean like
i kind of need the old state for what im working on. how do i disable this
how do i put it in there
like, i need to know when the state is arcana/celestial/buffoon/etc
i have the gradient i just dont know what to put in badge_colour
local gradient = SMODS.Gradient{} then put gradient there.
how do i work around this and infer which booster state is which @daring fern
Put the gradient first then put it in a variable and use that.
added pool as an object type in the main lua file and getting same error
smods also adds a value for the current booster that's opened something like SMODS.opened_booster
thank you
the key might need your mod's prefix? idk
okay yay this worked
i'll try that
it's in SMODS.Gradients.prefix_key btw
SMODS.OPENED_BOOSTER.config.center.key to check key of said booster, yeah.
yeah
thanks
center.kind might be useful as well
True, if you want to "theme" any given booster packs together.
tried, same error
now that im checking you shouldn't need the prefix..
can i see the code for the deck again?
i figured but i couldnt find anything about the prefix key?
prefix is your mods prefix, key is the key you set in the gradient
oh, that's not the syntax
ohhh
i'm having trouble figuring out how probability works (card is a 1 in 3 chance of x7 mult)
SMODS.add_card{set="gcmember", area=G.jokers}
so like Gradients.OCJ_Concept
just this with no other paramaters?
what's exactly the problem?
card.ability.extra.odds
oh sorry for a custom objecttype it might also need the area
there
oh ok i understand now
how do i check if the selected blind is the boss blind?
also in the card description it's saying "nil in nil chance for x7 mult"
G.GAME.blind.boss
oh bruhh
you need to modify the loc_vars function
like this
loc_vars = function(self,info_queue,card) return { G.GAME.probabilities.normal or 1, card.ability.extra.odds } end
can i change the keybind for debugplus cuz there is no / on my keyboard i need to press shift + 7 to get it so the console doesnt work
or more beautiful
loc_vars = function(self,info_queue,card)
return { G.GAME.probabilities.normal or 1, card.ability.extra.odds }
end
german found
same
im not german tho
alr it works
np
Das ist schade
okay
update: its in the DebugPlus/debugplus/console.lua folder
function global.consoleHandleKey(key)
if not consoleOpen then
if key == '/' or key == 'kp/' then
if util.isShiftDown() then
showNewLogs = not showNewLogs
else
openNextFrame = true -- This is to prevent the keyboard handler from typing this key
end
end
return true
end
you can also use the numeric key
can i just do it like .
this code at 460 right?
function global.consoleHandleKey(key)
if not consoleOpen then
if key == '.' or key == 'kp.' then
if util.isShiftDown() then
showNewLogs = not showNewLogs
else
openNextFrame = true -- This is to prevent the keyboard handler from typing this key
end
end
return true
endis this good
cuz i want it to be ''.''
are you by any chance on a non english keyboard layout?
qwerty
well ok, my nordic layout keyboard is also qwerty haha
is the code aight
like is your slash button here
try
I was asking eymen 
quick q again: how do i change the amount of joker slots by 1?
but cool, mine's there too. it's a silly spot to push a slash
sry didnt want to sound rude
i swear 😭
I've been adapting to this layout and it's been awful as a developer haha
but no worries
no i have it also like this
ye it worked
G.jokers:change_size(1) iirc
does this card reads well?
is it supposed to say shadows
yeah
it isn't very clear
i just used G.jokers.config.card_limit = G.jokers.config.card_limit + 1 now
imma try tho
it's almost there, everything displays and updates properly w/ the oops all sixes and stuff like that but i feel like it still never triggers
joke tuah
try adding a print("test") before the pseudorandom to see if it fires
it won't ever trigger because a joker will never have a context where context.main_scoring is true
should it be context.joker_main?
yeah
I'm trying to code a joker that only gives 3x mult when the played hand is only 7s, this runs, but it still gives 3x mult for all hands, any ideas why?
your local notallsevens variable is set to 0 in every context, you need to either set the flag on the object or do the check in the joker_main context
you need to have a "if context.joker_main then" in the calc
...funky loop.
@tall wharf I have cleaned up your patches, if you could test it works fine for you I'm happy to merge
ty
-# Oh god the rescoring even affected the held in hand stuff.
i think you can just merge i haven't actually coded anything
is there anyway i can force a boss blind to spawn on an ante?
did you not have some descriptions that utilised it?
i do
(eg, if i want a certain boss blind to forcefully\ spawn every ante thats a multiple of 12)
do they still work?
it feels weir asking the whole time but how do i get the amount of cards with a specific rank in a calc func?
now i feel like it's triggering everytime
cute art
i dont think the balatro font has japanese support
cause it also worked really weirdly when i tried special characters
this is the very pr that is adding support for custom fonts
this mod looks so cool i love teto(can you tell)
yes
also hi aikoyori!!
hi
well now you're doing the check on every played card
it's just, not there?
local _suit = pseudorandom_element({ 'S', 'H', 'D', 'C' }, pseudoseed('crackers'))
local _card = create_playing_card({ front = G.P_CARDS[_suit .. '_K'], center = G.P_CENTERS.c_base }, G.hand,
nil, nil, { G.C.SECONDARY_SET.Enhanced })
G.GAME.blind:debuff_card(_card)
G.hand:sort()
card:juice_up()
return true
end
}))
playing_card_joker_effects({ true })```
what do i change in order to create a stone card?
what would be a good value for an Xmult-giving enhancement?
unless the implementation changed
lower than glass card, maybe 1.25
I dont think I changed how it loads stuff
oh i totally forgot about glass
when trying to add the curate voucher(from cryptid) the game gives me this error upon starting the deck. the voucher works fine normally so i'm wondering if something else is happening
not using the cry_ prefix btw if it helps
hmmmm
also
-# dear god, unintended side effects of the hooking...
I can just download your dev build right?
yeah
just remove ui_text.toml (the patch i contributed) and change stuff in fonts.lua
why do you have yen
exact same error when using prefix
one sec
what's the key name for the ace?
The heck, you got YEN!?
the id you mean?
like K is king
ah, think i saw it was A in strength code
Man, I'm too smooth brain for this lol
okk
yeth.
yen
human brains were not built for this
so i found the cryptid code that causes the issue
i don't need for a not context.blueprint in add_to_deck() nor remove_from_deck() right?
we should be farming wheat and dying of dysentery
I'm failing so horribly coding this
OH I see what's happened
also i forgot about the hardcore challenge
what the hell did i just find
Prevents Death
Adds 66 debuffed Stone cards to deck
Self-Destructs
(in someones mod wiki)
yeah iirc he has a joker that removes all debuffed cards from deck
the effect is fun
finally font
right down one yes
Consumes lead from Steel Cards
Gains +25 Chips every time lead is consumed
(Currently +0 Chips)
where?
how would i make a boss blind disable face_cards?? i dont know if im understanding this right, but heres my current debuff table:
debuff = {is_face = true},
plant
thank u sm (it works now)
could i get the link to that?
i mean like where in the source code?
uh actually i dont think vanillaremade has blinds
it doesn't
check your error
yeah. :P
modifiers.lua
alr
No?
heres what the page says for debuffs:
--debuff = {}: Configure vanilla Blind effects with these fields:
--Disallowing hands in full:
hand = { ['Hand Type'] = true} --for a specific set of hands,
h_size_ge = n, --must play at least n cards,
h_size_le = n, --must play at most n cards.
--Debuffing cards:
suit = 'Hearts' --for one specific suit,
value = '2' --for one specific rank,
nominal = n --for all ranks scoring n base chips,
is_face = true --for all face cards.
no
wait
math is on hiatus
What?
i coulda sworn it said it was on his somewhere on there
custom fonts in steamodded
idk
what's the one for the stone card?
my go to is to check for SMODS.has_enhancement(self, 'm_stone')
stil confused, what about this causes the voucher to not work when added through a deck?
Yes.
you can also card.ability and card.ability.name == "m_stone" (or "Stone", i dont rememebr)
yeah but im using it to create it, not to check if you have
idk
do you think that {X:mult,C:white} being for X mult was intentional
cause background totally couldve been B:
well the key is m_stone
kk
what's the key for the vanilla eternal sticker? looked through source code and couldn't find it
when in doubt, check vanillaremade
eternal
what do you need it for
i have ```lua
debuff = {is_face = true}
but its not debuffing face cards for some reason??
cause you can directly do some stuff
a very silly seal that makes eternal jokers when scored and doesn't need room
that is indeed quite silly
do can just do joker:set_eternal(true)
oh right
You just do SMODS.add_card({set = "Joker", stickers = {"eternal"}})
i need to make the peakest non joke mod of all time
Yes.

SMODS.add_card is better.
then whats with the ❓
okay
yeah, just was checking to make sure i didn't need to add a prefix like everything else in vanilla
Since curate isn't working, is there an alternative way to make everything have an edition
as in things you find in the shop
What do you mean curate doesn't work? It works fine for me.
key = "banana",
set = "food",
loc_txt = {
name = 'Banana',
text = {
'Create a {C:attention}stone card{}',
'and add it to your hand'
}
},
atlas = 'banana',
cost = 1,
pos = {x = 0, y = 0},
can_use = function(self,card)
return G.GAME.blind.in_blind
end,
in_pool = function(self,args)
return true
end,
use = function(self,card,area,copier)
G.E_MANAGER:add_event(Event({
func = function()
local _suit = pseudorandom_element({ 'S', 'H', 'D', 'C' }, pseudoseed('crackers'))
local _card = create_playing_card({ front = G.P_CARDS[_suit .. '_K'], center = G.P_CENTERS.c_base }, G.hand,
nil, nil, { G.C.SECONDARY_SET.Enhanced.m_stone })
G.GAME.blind:debuff_card(_card)
G.hand:sort()
card:juice_up()
return true
end
}))
playing_card_joker_effects({ true })
end
}
checking if a card is a face card is just card:is_face(), right?
when trying to make a deck where you start with it, the game crashes
it works perfectly fine if you obtain through the shop
You would replicate what curate does then.
i'll try
okay yeah i got it to work :)
what's the difference between apply and init in the context of a deck
what's the error here?
hi again
apply exists, and init doesn't.
init is a cryptid thing iirc
how do i check if a card is enhanced
next(SMODS.get_enhancements(card))
if next(SMODS.get_enhancements(card))
would poll edition work as a function to replicate curate?
bump
Yes, that's what Curate uses.
what's the condition for the played hand being a pair
if context.scoring_name == "Pair"
poll_edition(nil, 1, false, true, {"e_foil", "e_holo", "e_polychrome", "e_negative"}) so would this work or do I need to change it? and how would I implement this into the apply function?
what's the center?
@wintry solar what was the fix to my issue lmao
did anything weird appear in my codebase
<@&1133519078540185692>
I changed how render_scale works so you just need to multiply your values by 20
oh
right
ok thanks for the heads up
like this?
oh they got him
Don't return the scaling.
the mods are REALLY fast
other than that its fine though?
I think so.
trying to maker a Joker that makes a copy of The Fool on blind select, the same way Cartomancer works. I copied the code from Cartomancer and modified it to be specific to The Fool, but it does nothing:
calculate_joker = function(self, context)
if self.debuff then return nil end
if context.setting_blind and not self.getting_sliced then
if not (context.blueprint_card or self).getting_sliced and #G.consumables.cards + G.GAME.consumable_buffer < G.consumables.config.card_limit then
G.E_MANAGER:add_event(Event({
func = (function()
G.E_MANAGER:add_event(Event({
func = function()
local card = create_card("Tarot", G.consumables, nil, nil, nil, nil, G.P_CENTERS.c_fool, "fool")
card:add_to_deck()
G.consumables:emplace(card)
G.GAME.consumable_buffer = 0
return true
end}))
card_eval_status_text(context.blueprint_card or self, "extra", nil, nil, nil, {message = localize("k_plus_tarot"), colour = G.C.PURPLE})
return true
end)}))
end
end
end
any suggestions?
The key needs to be "c_fool" not the center.
So "G.c_fool or just "c_fool"? Just tried "c_fool" and still doesn't work
calculate_joker was the name of the function that activates Cartomancer's ability, at least as far as I could tell. Modified the code from the git and it worked perfectly. Thanks
yeah the vanilla code and the smods code differ greatly in a lot of places
alright I'll keep that in mind, thanks for the help. I'm new to modding this game lol
What mod should i reference to help me make a joker that buffs rates of shop appearances of uncommon jokers
I don't know what mod does it but I think you need to change G.GAME.uncommon_mod
tried to refrerence the cryptid mod's deck of equilibrium but it seems they use their own custom functions for that
is there any documentation i can read to understand how shop rates work for balatro?
(it's the same for all weights)
alright!
G.GAME.uncommon_mod is a multiplier to the base rate iirc
so would i make a weight function within the joker and replace edition_rate with uncommon mod and multiply is by a value
no that part is just for editions
ohh
you would modify it in add_to_deck and remove_from_deck
imma look at how the hone voucher works and try to work from there
makes sense considering what my joker is intended to do
🔥🔥🔥🔥
would i set the uncommon mod to an integer value to signify a buff in rate of appearance?
bump
the game does base_rate * G.GAME.uncommon_mod iirc
ah shit i asked for the wrong thing
whats the case for when the played hand contains a pair
You would do poll_edition(nil, nil, nil, true) I think.
I see
next(context.poker_hands["Pair"])
so would that guarantee an edition including negative?
how do i check a card's suit?
i dont wanna check if its a specific suit, i just want to get its suit
It would include all editions.
card.base.suit
Kinda lost on what to do from here
completed the extra tarot card
omg is that shadow milk
yep
i was litterally just thinking about a shadow milk joker and how cool it would be
that W needs an extra pixel
that was just an example of that the game does, you want to do G.GAME.uncommon_mod = 2 to double it for example
or two pixels less
pretty sure i'm doing this wrong
how would i even add that? there's barely any space
oh no wait it's even pixels
1 pixel less could work too
maybe the ";" can be 1 pixel large
poll_edition returns an edition but you're not doing anything with it
ah ok
it's supposed to say of 😭
like this?
so how would i use it to force the edition on everything in the shop
im wondering now, if i wanted for example only for uncommon jokers to spawn in shop / boosters, would it be the same way, or would i need for a hook?
ouch
something like this
or setting all others to 0
base_rate doesn't exist as a global and new_rate should be card.ability.extra.new_rate
1st one works well
also i wish i could draw this good
probably patches or hooks
alrighty thx
So if i'd want to reset it would i need to find what the original base rate was and set it equal to that?
like when selling the card
if not suit_table[card.base.suit] then
print("inserting")
table.insert(suit_table, card.base.suit)
print(#suit_table)
else
print(card.base.suit)
end
its saying that #suit_table is 0??
it's more like probabilities where you want to double it or halve it
Gotcha
Okay question, how do I take ownership of a challenge?
or at least add custom jokers to existing challenges?
wait i think i figured it out!!
something like this probably based on what you said
makes sense
oh, looks better now (also made the "of" more obvious)
the add to deck one should be a multiplication too
got it
G.GAME.uncommon_mod = G.GAME.uncommon_mod * card.ability.extra.new_rate
this should work then
now to think of an interesting tarot card mechanic
which script is the weight defined in?
I would maybe try something like this for the of too
Still got nothing
how does the game prevent Jokers from being sold if they are eternal? I have a Joker that gives +1 consumable slot and it shouldn't be able to be sold if selling it would overflow (having 3/2 consumables for example)
knowing how to prevent selling could fix that for me
ok i just tested setting uncommon_mod and rare_mod to 0 and only commons appear
you would need to do something like that for every rarity even custom if you want to leave only 1
what function would i hook to change something when a run starts?
not sure if it looks better or not
way better
Game:start_run?
can you show it full art?
ah then doing it like this would be unlikely to work with other mods that set custom rarity
rarity_key:lower()?
I would maybe make each of the O and F one pixel taller, but I think it's pretty good like that
and i guess i'd need to store base values somewhere if it wasn't a hook
bump 2: desperate boogaloo
you would need to patch create_card_for_shop probably
how do I patch things? apologies for being braindead
me jump scare

you!!
you'll probably want a pattern patch, should be simple
what is rarity_key:lower() for?
you replace that for the key of each rarity in lowercase
huh, when looking at this it appears that playing cards in the shop cannot spawn with modded editions on
so smth like this? or i msunderstood it completely?
if rarity_key ~= "uncommon" then
G.GAME[rarity_key:lower().."_mod"] = 0
end
This code seems to have a strange interaction with hologram, where hologram only gains the mult for duplicated cards at the end of the round, and it only adds mult for the amount of cards copied instead of the amount of cards added to deck, can anyone figure it out?
calculate = function(self, card, context)
if context.before then
for i = 1, 2 do
for k, v in ipairs(context.scoring_hand) do
if v.seal or v.edition or next(SMODS.get_enhancements(v)) then
G.playing_card = (G.playing_card and G.playing_card + 1) or 1
local copy_card = copy_card(v, nil, nil, G.playing_card)
copy_card:add_to_deck()
G.deck.config.card_limit = G.deck.config.card_limit + 1
table.insert(G.playing_cards, copy_card)
G.hand:emplace(copy_card)
copy_card.states.visible = nil
G.E_MANAGER:add_event(Event({
func = function()
copy_card:start_materialize()
return true
end
}))
end
end
end
end
if context.destroy_card and context.cardarea == G.play and
(context.destroy_card.seal or context.destroy_card.edition or next(SMODS.get_enhancements(context.destroy_card))) then
return {
message = localize('k_copied_ex'),
colour = G.C.CHIPS,
func = function()
G.E_MANAGER:add_event(Event({
func = function()
SMODS.calculate_context({ playing_card_added = true, cards = { copy_card } })
return true
end
}))
end,
remove = true
}
end
end
so how would i format a pattern patch to do that? never used patches before
although i have no clue on how to store the original values, through a hook and a global?
something like this
-- this is pseudocode do not use literally, i dont know what the actual names are
for rarity_key, v in pairs(SMODS.Rarities) do
if rarity_key ~= "Uncommon" then
G.GAME[rarity_key:lower().."_mod"] = 0
end
end
Hello im new to modding and I have a joker working fine but when an invisible joker tries to copy it i get a stack overflow. does anyone here have experience with this issue and know why its happening
where can i find all the context.something?
i have talisman and debug on
ill grab the code one sec
car
is there a better way than just dropping a giant code block in discord
coudl i send a txt instead
you could probably paste the whole file
it shouldnt be that much code if its ur first joker tho
sounds good i just didnt want to paste too much and have it take too much space
How do i edit the rate of rare and legendary jokers?
i keep getting errors at the line for rares in add_to_deck
legendary shouldn't matter they dont appear in the shop
Legendary jokers don't have a rate?
Wait they don't appear in the shop?
reading the docs and smods patches i am still confused on what i do
yeah? they're only from soul
put a triple ` around this
loc_txt = {
name = 'Roxie Volkov',
text = {
"Retriggers joker to the",
"right twice."
}
},
-- config of the joker. Variables go here.
config = { extra = { active = "Inactive" , bptarget = 0 } },
-- rarity level, 1 = common, 2 = uncommon, 3 = rare, 4 = legendary.
rarity = 4,
atlas = 'roxie',
pos = {
x = 0,
y = 0
},
cost = 8,
unlocked = true,
discovered = true,
blueprint_compat = true,
perishable_compat = true,
eternal_compat = true,
allow_duplicates = false,
loc_vars = function(self, info_queue, center)
return { vars = { center.ability.extra.active} }
end,
update = function(self, card, front)
local _myid = getJokerID(card)
if G.jokers and G.jokers.cards[_myid + 1] then card.ability.extra.bptarget = G.jokers.cards[_myid + 1] end
end,
-- loc_vars works with the config and gives you text variables to work with.
-- these are formatted as #n#, where n is the position in the variable table.
-- calculate is where the scoring and effects of the joker are handled.
calculate = function(self, card, context)
local once = false
if context.retrigger_joker then
return{
repetitions = 2,
retrigger_joker = retrigger_card
}
end
if context.retrigger_joker_check and not context.retrigger_joker and context.other_card ~= self then
if context.other_card == G.jokers.cards[getJokerID(card) + 1] then
if context.other_card.bptarget and context.other_card.bptarget ~= 0 then
return {
repetitions = 2,
card = context.other_card.bptarget,
}
else
return {
repetitions = 2,
--card = card,
}
end
else
return nil, true
end
end ```
type your code like this:
```lua
-- your code here
```
trib appeared in a shop once but i guess that was with the cryptid mod installed (not to deck of equilibrium)
that look good?
ya
@meager pumice also do this for colors (helps debug)
sick alrihgt
is invis joker to the right of yours when you sell it?
Wait so no commas at all?
try selling it to the left
yes but not hte immediate right. like there was a joker separating the two
ill try it to the left tho too
weird
i'm still getting errors at the rate_mod line in add_to_deck
theres still a comma there
yeah still crashes on the left too
try ankh
when i have mods loaded the collection crashes on open. is there a way to give myself ankh without going to the collection
or is there a way to fix that crash
Fixed that, also for legendaries, could i make it to where appearances of the soul in tarot packs could be buffed as well?
would there be any other way to force editions without patches? i can't seem to figure out how to use them
reinstall steamodded and lovely
on what?
sounds good ill give that a shot
if youre creating the card then you dont need patches
You loop over G.shop_jokers in update and give it an edition if it doesn't have one.
so how do i loop over in update?
on reroll and on entering the shop
ik there's a calculate function for rerolling but idk about one for entering the shop
Does The Soul have a unique rate variable in the game that can be edited
i cant find one either
does anyone know any contexts for entering shop
update = function (self, card, dt)
if G.shop_jokers and G.shop_jokers.cards then
for k, v in pairs(G.shop_jokers.cards) do
if not v.edition then
v:set_edition(poll_edition(nil, nil, nil, true))
end
end
end
end
```?
is there any documentation or place i can see all variables for card appearances to know?
would this work?
bumping this
I don't think update works with decks.
is there an alternative?
Hooking card:update and checking if the selected deck is that deck.
what is hooking (my brain is mush atp)
In LUA, it is a very important concept to understand that everything is a variable and all variables may be edited in runtime. This includes functions. With modding other peoples' LUA files, like Klei's basegame code, you may find yourself wanting to run your code before or after the original fun...
let me rephrase: how do I hook in smods?
that tells you basically everything
alr
just put the function hook in main.lua and find the right function
how do i create a playing card and add it to deck?
Does anyone know if the rate for The Soul appearances can be edited with a variable?
Tried looking in the source code
does anyone know how i can time sounds better? i wanna have a message saying "let's go gambling" from the joker but i'm not sure how to do that and the sounds overlap
but i'm a bit lost
from the source code i think the 0.997 is the threshold
whoops i accidentally updated something it looks like this
So question: How do I add custom jokers to pre-existing challenges?
Gotcha ok
could anyone provide just like a basic example/pseudocode of hooking card:update? the guide helps just barely
this was from the common_events.lua file. idk if itll help much but maybe you could change it to a variable
I'm trying to make a Joker that works the same way as the Observatory voucher and it almost works, but only procs once, not for each Planet card like the voucher does:
calculate = function(self, card, context)
if self.debuff then return end
if context.consumeable and context.other_consumable.ability.set == "Planet" and context.other_consumable.ability.consumeable.hand_type == context.scoring_name then
return {
x_mult = card.ability.Xmult,
message_card = context.other_consumable
}
end
end
whats the area for cards that were played (including unscored cards)
ive been stuck for more than an hour trying to figure out how to make sure the boosterpack you open came from the shop
so, uhm, some art-to/from-code questions, so, someone's making some art for me, involving transparency, and, issue is, the art is supposed to have, like, a sheen to it, you know? like seethru plastic, and uhmm, the sheen is building a shadow behind it, any tips here? (wasn't sure to ask in here or in fan-art, but something tells me the answer here is more code related lol)
bump
has to do with the basegames shadow shader
unless its fully transparent, full shadow
mhhh
got it, its G.hand
wait
no
G.hand is your held cards
got smth that works, although i'm not sure as to how store the original rarity weight's value to return them when joker's remove_from_deck()
for rarity_key, v in pairs(SMODS.Rarities) do
if rarity_key ~= "Uncommon" then
G.GAME[rarity_key:lower().."_mod"] = 0
end
end
now i know this doesnt work because by the time context.open_booster is triggered, G.STATE is no longer the shop
so idk what to try now
card.ability.extra.defaults[rarity_key] = G.GAME[rarity_key:lower().."_mod"]
something like this?
in the add_to_deck before setting it?
jolly bump
why is game not reading the json file for mod metadata?
can you send it?
local card_update_ref = Card.update
function Card:update(dt)
-- do stuff here
card_update_ref(self, dt)
-- or here
end
bump
works, thanks you a lot !
(gonna revise the question) how do i get all of the cards that were played including non scoring cards
because G.play is just for scoring cards
do you want context.full_hand
bumping this. I don't get why but invis joker stack overflows the game when copying this joker. My other custom jokers work fine with invis but not this one
would context.cardarea == context.full_hand work like == G.play but including nonscoring?
Just context.full_hand
oh for individual contexts it's a bit different
iirc you check if it's a string (maybe 'unscore'? idr offhand)
im trying to context.destroy_card every played card
you might need to enable an optional smods feature
it's context.cardarea == 'unscored'
does that include scored cards too or just unscored cards?
i could just do an or tho
just unscored
you might want to iterate through the consumable slots to do it for each
im trying to make a card that adds mult when theres both a King and Jack in a played hand, i was thinking of looking at the code for flower pot as a refrence but i realized that flowerpot checks for suits, is there anything similar to what im trying to do that i can look at for reference?
You could look at trib.
yea use trib
alright thanks
Anyone have experience with card copying?
is there an easy way to make a joker check if a specific joker is in your deck?
SMODS.find_card
ok so i found the code for trib
that seems to be what i need
but i want it so that It needs both a king and jack
if i change that 'or' to an 'and' would it still work
eremel merged all my PRs so i felt empty https://github.com/Steamodded/smods/pull/717
whats the vanilla sound that plays on Xmult triggers?
I can fill this void

how
i already have my own UI problems in my mod sorry
I have a void for you to fill too
is there a list of vanilla sfx anywhere
Editions dont use get_current_pool and I cba doing that
INFO - [G] file not found: functions/button_callbacks.lua: No such file or directory
INFO - [G] file not found: main.lua: No such file or directory
INFO - [G] file not found: main.lua: No such file or directory
INFO - [G] 2025-05-26 17:35:15 :: ERROR :: StackTrace :: Oops! The game crashed
stack overflow
Stack Traceback
===============
(1) Lua upvalue 'orig' at file 'main.lua:612'
Local variables:
msg = string: "stack overflow"
(*temporary) = Lua function '?' (defined at line 31 of chunk [SMODS _ "src/logging.lua"])
(*temporary) = string: "Oops! The game crashed\
This is in my logs when my game crashes. The functions/button_callbacks.lua file exists in the balatro directory but it says that its not found. Would verifying my file integrity through steam mess with lovely or my mods at all?
ok, I will look at it
I also want to see some stuff with get_current_pool for my individual card weights thing
since Ice is going to use it
anyone know how to kill a brainstorm or bp if it triggers an effect
is a tarot card that creates three random negative consumables too OP?
consumables or tarots
consumables? yes it can make soul and spectrals in general
Still struggling with this joker. Hologram now gains the right amount of xmult, but it still counts up for every single increment, and only adds the xmult to itself after the scoring.
calculate = function(self, card, context)
if context.before then
for i = 1, 2 do
for k, v in ipairs(context.scoring_hand) do
if v.seal or v.edition or next(SMODS.get_enhancements(v)) then
G.E_MANAGER:add_event(Event({
func = function()
local new_cards = {}
G.playing_card = (G.playing_card and G.playing_card + 1) or 1
local copy_card = copy_card(v, nil, nil, G.playing_card)
copy_card:add_to_deck()
G.deck.config.card_limit = G.deck.config.card_limit + 1
table.insert(G.playing_cards, copy_card)
G.hand:emplace(copy_card)
copy_card.states.visible = nil
copy_card:start_materialize()
new_cards[#new_cards + 1] = copy_card
SMODS.calculate_context({ playing_card_added = true, cards = { new_cards } })
return true
end
}))
end
end
end
end
if context.destroy_card and context.cardarea == G.play and
(context.destroy_card.seal or context.destroy_card.edition or next(SMODS.get_enhancements(context.destroy_card))) then
return {
message = localize('k_copied_ex'),
colour = G.C.CHIPS,
remove = true
}
end
end
tarots? thats just emperor but better
planets? thats one of them but better
spectrals? too OP
does anyone know where i can find the documentation on functions like add_to_deck() and G.deck:emplace()
for the vanilla functions there's none
for the add_to_deck in smods, here: https://github.com/Steamodded/smods/wiki/SMODS.Joker
https://github.com/Steamodded/smods/wiki/SMODS.Consumable
yeah i saw that but is that really it? is it just a case where i have to play around and look at examples to get a better understanding of it
ig three negative tarots might be the way
Anyone know why this only give hologram the xmult after joker scoring?
yes
is it possible to do an event and a message at the same exact time
in a return of a calc
i said screw it and instead of spending any longer trying to get my specific use case to work i just botched it together. was trying to simply make a joker that creates a playing card on scoring triggers (card scored, hand played) but the method i used to create playing cards before was not working because it uses draw calls. instead, the code now just copies jokers like dna in a way, creating a temp card, copying that card and therefore adding to deck, then deleting the temp card. I LOVE SMODS
there should be an easier way to make playing cards honestly
im spoiled by SMODS.add_card
yeah it makes no sense to me tbh
i think i may have overcomplicateed it a bit haha because i couldnt get that to work properly so i took the long way around
question, i'm trying to make a joker that gains xmult whenever a specific tarot is played, and im a bit confused about the definition of "card"
if "card" is referring to the played tarot then
how do i refer to my joker
do i need to make a variable
how do i find this pr
no yeah add_card doesn't work with playing cards so adding them is complicated
Keku accidentally merged a bunch of prs together
oh i see i see that makes sense then. well now that that is done, i will move onto editing playing cards and destroying playing cards which hopefully should be easier
card is the joker
i see
do you know how to use the event options
in that case how would i refer to the consumable getting used
the consumable is context.consumeable
yeah but i kinda do it by trial and error
why is this part crashing my game?
key = 'tarot24',
set = 'Tarot'
loc_txt = {
name = 'Carnival of Shadows'
text =
'Creates 3 random {V:1}Negative{}'
'{C:attention}Tarot{} cards.'
},
}```
you're missing a comma
where?
isnt the text a table
wait sorry, you're missing a comma and brackets around the text
actually 2 commas
oh yeah
since the text's bracket doesnt even exist to have a comma after
is there a way to make an event happen literally as the last event did
i know that theres something there 1 sec
oh, the text part needs brackets too
i dont know exactly but i would mess with blockeable and trigger = "immediate"
