#💻・modding-dev
1 messages · Page 111 of 1
The latest "release" is... the WIP isn't so far.
Ah okay, I can test it on my dev branch tomorrow if you send me a copy
But I should probably get to bed now
If I don't forget, sure. And rest well.
Rest well, thanks for the help thus far
Do you have the crash screen btw? It might help see the problem
Do you want the entire thing?
Yeah I'm not sure which part of the crash log to give ya, but here ya go, tell me if you need more
@hardy viper i'm curious about how deepfind helps with nodes[1] spam
And which line is 131?
Try updating smods
also did you try making a new save and then getting your joker again
I'll try it later
Also damn SMODS got an update? I just started modding like 4 days ago
It updates most days
Funny
the other day we had at least 7 updates in a day
Oh what the fuck I made a new run and then it worked 💀
probably old save before you added extra
the other month we got one update a week

local uinodes = thisUIFunc()
--lets say we have some object, with something in the config, but we cant use get_uie_by_id.
--so we'll look for value "this_val"
local df = SMODS.deepfind(uinodes, "this_val")
--the value can be anything, a string, a number, a table (although it would have to be a reference to a table. {3} == {3} is of course false
--its important to note that we can use ANY table, not just ui stuff
local firstMatch = df[1]
--order is undefined. ideally theres only one match, but all that are found are returned.
local tblfound, index, tree = firstMatch.table, firstMatch.index, firstMatch.tree
--tblfound[index] is our value
--tree contains the way we'd get to our object.
--since the index is inside a table, we dont want the last object in the tree (which is index) or the second last (which is tblfound). we want the third
local traverseTarget = uinodes --we modify this. this will end up becoming the third last.
for i = 1, #tree - 2 do --since we don't want the last 2 objects in the tree
local ind = tree[i]
--the indice to find the next step in the tree towards our desired object
traverseTarget = traverseTarget[ind]
--and set traverseTarget
end
--[[
now traverseTarget points to the target we wanted, without any need for nodes[1] shenanigans!
and while yes, this is a bit longer, it's better because
1. it's more flexible (so if a node is inserted at index 1 somewhere, this will still work, whereas nodes[1] chaining will break)
2. it can become shorter if you define a small helper function
]]
edit because there's a link to this on the thing: this can be done much easier with objtree:
local uinodes = thisUIFunc()
local objtree = SMODS.deepfind(uinodes, "this_val")[1].objtree
local target = objtree[#objtree-2]
--done!
{3} == {3} is of course false WHAT
Gotta crank out the beta before the version system breaks
yeah, youre creating two separate tables, and tables work via references in lua, including in comparisons
There we go, I discarded 3 cards next to it and got this
Now I just need to add some flair like a popup that comes up when you discard a card next to it, and a tracker in the description (like the "Currently" grey text trackers that jokers have)
But Enhancements don't have return statements, what can I use?
since you're making two different tables, even though they share the same values, they have different references
so they compare as false
same thing goes for functions
(and userdatas)
not anything else though
that is not a thing in lua
Behold,
James
Either SMODS.eval_this or card_eval_status_text
-# or wait 😉
God that's cursed
I'm talking about other languages that have two comparison shorthands
i am so confused
depends on the language
most use them for "looseness"
this joker is supposed to give x mult when only 1 card with a red stud sticker scores
but it does nothing
like in javascript, "3" == 3 is true, but "3" === 3 is false
=== is for things that are absolutely the same, and == allows you to be more loose with your comparisons
I ISPELLED INDIVIDUAL
😭
Cheers, I found someone's code using card_eval_status_text
card_eval_status_text(card, 'extra', nil, nil, nil, {message = "...."}, G.C.RED)
Better than me making repetition plural xddd
The Programming Experience tm
I spent so long trying to debug my Enhancements only to realize I forgot a comma
from what i've seen, theres 3 ways to compare whether tables are the same (at least in lua)
- use a recursive comparison function that will test for differences between the table, and return early if they're different anywhere
- use the same metatable for all the objects of a certain type, so that two different table objects constructed the same way can be seen as equal if they have the same metatable
- assigning objects ids and checking those against each other
you can also use a non-recursive comparison function but thats kinda lazy and doesnt usually work when things are nested
and everyone knows recursion is the best thing since butter on toast
how's it compare to sliced bread tho?
Not me just looking through chat history trying to figure out how to use card_eval_status_text more and then dropped on my knees when reading this
om nom nom
Well, I technically can pass them through as I now have a Lovely patch of my own.
(the effect being 1 mult from what I understand)
js has === because == will change types (so 2 == "2" is true but 2 === "2" is false)
oh yeah string coercion exists
🐌....
Yo, what's good?
chillin
Trying to figure out how to give text to a playing card
Card on the left uses the default from hiker, but the card on the right gives a bonus mult
Wonder how can I add this tracker into my Enhancements? Does SMODS.Enhancement take in loc_var?
someones done this already let me find the thread
you can
tkqae that code
I'll reference it while I look at how card_extra_chips works
What is programming but not stealing from one another
truly nothing
strange
oh because I think i put it twice
lol
Now I can make the minor arcana
I'll probably do wheel of fortune style for the xmult and dollars
Wahoo
I know it's crazy to have chance for xmult and yet someone could just perkeo the 2 of Cups to constantly get a 50% chance
or just ace of wands it to get +15 guaranteed each time
But Perkeo is Perkeo
it'll break everything
Perkeo does whatever it wants
The only balancing is that you can only do it to 1 card each time
max_highlighted is 1
Is there any way to easily retrigger a Joker in this context?
-# wait all you need is context.carearea == G.jokers to make a joker retrigger?
Maybe? I'm not even sure myself
isn't it context.other_joker?
naw its other_card
i've been curious about it, but i've always forgotten to ask
also context.repetitions is missing
ah wait
context.individual is smth else
Ah ok
context.repetition no s btw
oops
also pretty sure for context.repetition the card in the return is the card doing the repetition
and by pretty sure i mean 100% sure
(this is vanilla code, self in this and card in an smods calculate are the same)
Doesn't card get autosupplied if it's missing?
..?
Forget whatever I said, I can't make sense of it in my head
it had meaning at one point
try context.other_joker instead of context.other_card
is there anyway to stop an enhancement from spawning in booster packs? cant see anything on the docs
are you trying to make a vanilla consumable be removed from the pool or a modded one
Is there even a time when context.repetition and context.cardarea == G.jokers are passed at the same time?
a modded one, my own one
i want it to be only be attainable through a joker, so raisedcateyebrow~2
okay so you want to use the in_pool function
i think you can just return the result of #SMODS.find_joker("j_prefix_key") > 0
still a no on that. If it helps, the idea of this joker is to retrigger jokers that are perishable
hmmm
in the in_pool?
try removing the context.cardarea check
yeah
It did not like that one
revert back to other_card and try again
i thought that was a valid field, guess i was mistaken 😭
?
if context.retrigger_joker_check and not context.retrigger_joker and context.other_joker and context.other_joker.ability.perishable then
return {
message = localize('k_again_ex'),
repetitions = 1,
card = card,
}
end
🍞
I'll give this a go rq
Nope
btw where are you getting those retrigger contexts?
That's how my Start Menu Joker retriggers other Jokers with the edit to include perishable check.
No I meant like where did you find them? Are they Steamodded contexts that I just haven't seen on the wiki?
I was suggested such back when I made it originally.
¯_(ツ)_/¯
Set a console message to send whenever it tries to trigger and it apparently doesn't make it past the checks
I just removed the perishable check and that wasn't it either. Huh
SMODS.Enhancement {
key = "devour",
loc_txt = {
name = "Devour",
text = {
"Discarding cards adjacent",
"to it will grant {C:mult}+5{} Mult",
"Resets when played",
"{C:inactive}(Currently {C:red}+#5#{C:inactive} Mult)"
}
},
atlas = 'Enhancements',
config = { extra = { mult = 0 } },
pos = {x=1, y=1},
I want to add a tracker in the description of an Enhancement, but since they don't use return functions, how am I going to track additional mults added to it?
Actually, my full line for it is if context.retrigger_joker_check and not context.retrigger_joker and context.other_card ~= card then...
Changed back to this and still no sign of it trying to trigger. I am so confused
No wait I got it working, just had to add loc_vars
key = "devour",
loc_txt = {
name = "Devour",
text = {
"Discarding cards adjacent",
"to it will grant {C:mult}+5{} Mult",
"Resets when played",
"{C:inactive}(Currently {C:red}+#1#{C:inactive} Mult)"
}
},
atlas = 'Enhancements',
config = { extra = { mult = 0 } },
pos = {x=1, y=1},
loc_vars = function(self, info_queue, card)
return { vars = { card.ability.extra.mult } }
end,
calculate = function(self, card, context, effect)......```
Try if context.retrigger_joker_check and not context.retrigger_joker and context.other_card.ability and context.other_card.ability.perishable as last resort?
very useful, ty
What is the extra value in the return block?
For message stuff.
Funny mushroom Spectral Card....
Well yes, but why is it not a regular message return?
how would i make an option like this in my mods config page
I guess I'm moreso asking what the function of extra is as opposed to what it is
common_events.lua, card_eval_status_text function may provide more info.
huh
I see
I am so confused. I've literally done this same thing before and it worked fine
still crashing with that included
yep
there is more
calculate = function(self,card,context)
if context.joker_main and card.ability.extra.streak > 0 then
return {
mult_mod = 15 * card.ability.extra.streak,
chip_mod = 30 * card.ability.extra.streak,
message = 'Streaked!',
colour = G.C.MULT
}
end
if context.after and context.cardarea == G.jokers then
card.ability.extra.hands = card.ability.extra.hands + 1
end
if context.end_of_round then
if card.ability.extra.hands == 1 then
card.ability.extra.streak = card.ability.extra.streak + 1
return {
message = 'Streak ' .. card.ability.extra.streak,
colour = G.C.CHIPS
}
else
card.ability.extra.streak = 0
return {
message = 'Reset',
colour = G.C.RED
}
end
card.ability.extra.hands = 0
end
end
Genuinely no clue how it thinks the variable isn't a number
Yes
I want to try adding an Enhancement that ranks up cards, but I'm a bit lost on where to start
It's not just as simple as just incrementing the card's id right?
smods rank system has a function for this iirc, it's not documented though
and it's not the above one
i would go to wherever that function is in the smods source code and just look above and below it and see if the increment function is around there
Which part or file of the source code should I look into?
the part where the change_base function is
which is probably in src/utils.lua but you can just ctrl f the entire source code
Is this it?
-- Change a card's suit, rank, or both.
-- Accepts keys for both objects instead of needing to build a card key yourself.
function SMODS.change_base(card, suit, rank)
if not card then return false end
local _suit = SMODS.Suits[suit or card.base.suit]
local _rank = SMODS.Ranks[rank or card.base.value]
if not _suit or not _rank then
sendWarnMessage(('Tried to call SMODS.change_base with invalid arguments: suit="%s", rank="%s"'):format(suit, rank), 'Util')
return false
end
card:set_base(G.P_CARDS[('%s_%s'):format(_suit.card_key, _rank.card_key)])
return card
end
Holy shit there's a bunch of good shit in utils.lua
Debuffing cards, adding cards, finding cards, insert pool, etc
deepfind when my pr gets merged 
I also want to make another Enhancement where if you discard it, it adds +N mult to the next hand, but I'm not sure if there's a context or anything that detects the next hand starting, or whether it can add the mult in the background without scoring a card
I've tried so many different contexts and rewriting of the definition trying to get this fixed but it won't budge. I am beside myself
SMODS.Joker { -- Streaker
key = 'streaker',
loc_txt = {
name = 'Streaker',
text = {
'{C:chips}+30{} chips and {C:mult}+15 mult',
'for each consecutive {C:attention}blind{}',
'beaten in {C:attention}one hand{}, {C:red}Resets{}',
'when streak is broken',
'{C:inactive}Current streak: #1#'
}
},
atlas = 'Jokers',
pos = {x = 5, y = 0},
rarity = 3,
config = { extra = {
streak = 0,
hands = 0 -- I know there's an tracker in vanilla but I can't access it at context.end_of_round
}
},
loc_vars = function(self,info_queue,center)
return {vars = {center.ability.extra.streak, center.ability.extra.hands}}
end,
calculate = function(self,card,context)
if context.joker_main and card.ability.extra.streak > 0 then
return {
mult_mod = 15 * card.ability.extra.streak,
chip_mod = 30 * card.ability.extra.streak,
message = 'Streaked!',
colour = G.C.MULT
}
end
if context.scoring_hand and context.cardarea == G.jokers and not context.blueprint then
card.ability.extra.hands = card.ability.extra.hands + 1
end
if context.end_of_round and not context.blueprint then
if card.ability.extra.hands == 1 then
card.ability.extra.streak = card.ability.extra.streak + 1
return {
extra = {message = 'Streak ' .. card.ability.extra.streak, colour = G.C.CHIPS}
}
else
card.ability.extra.streak = 0
return {
extra = {message = 'Reset', colour = G.C.RED}
}
end
card.ability.extra.hands = 0
end
end
}```

Yep that did it. Not sure why it was giving me the other error then. Thanks a bunch
This is a fun guy when you get him early lol
I'm trying to double chips at joker trigger, but it's only multiplying by the base chip total of the hand type. Any ideas on how I can get it to calculate from the chip total at the time of trigger? Setting the context to final_scoring_step does make it work but it doesn't visually trigger the joker
if context.joker_main then
return {
chip_mod = G.GAME.current_round.current_hand.chips * 2,
message = 'x2',
colour = G.C.CHIPS
}
end
Even then, it doesn't trigger in the order it should, as I want position in hand to have an effect on the scoring
joker_main is close but has the aforementioned problem of taking hand type chips instead of current total
Oh I see
Alternatively, hand_chips for currently scored chips.
just hand_chips? no extra specifiers to add on?
Like so?
nvm just tested it. Thank you!
Yeah I realized that and changed it lol
Yeah I'm also very surprised
I saw that variable mentioned in state_events.lua but would have never guess it was globally accessible
hand_chips and mult are global for current scores values
Is there a context for checking if a hand is played? There's context.first_hand_drawn but not sure if that's what I'm looking for
It's for an Enhancement that adds +N mult to the next hand played, and I'm a bit lost
Not sure about a context but I know G.GAME.current_round.hands_played exists, I feel like that may help with that fuctionality
local last_hand = G.GAME.last_hand_played
if card.ability.extra.mult > 0 and G.GAME.current_round.hands_played > last_hand then```
Apparently one of the conditions of the if statement doesn't return a number, which one doesn't?
Could always do a print(card.ability.extra.mult, G.GAME.current_round.hands_played) before the if to check what is nil.
Last_hand would be a string here
INFO - [G] EXTRA MULT: 10 CURRENT HANDS PLAYED: 1
Maybe I can use something like tonumber?
Ohhh like "Five of a Kind" or something?
Shit
Yes
What can I use instead to track the last hand played
Or track the number of hands played
No wait
I already have it it's just G.GAME.current_round.hands_played
Is there an easier way to track hand transitions?
Yeah I'm scrapping this idea haha, gonna do something else
The Enhancement could now add mult to the mult score with every card alongside it getting discarded, but I got an error talking about attempt to perform arithmetic on global 'mult'
Does SMODS.Enhancement not have support for the global mult value?
i see you there Ali
The value doesn’t exist when you’re discarding
What does that mean anyway, does it mean that once I discard, the mult value is just inaccessible?
The mult value only exists when the game is calculating a hand score
Is there a function that destroys a card?
card:remove() is quick and easy.
card:start_dissolve() has an animation
I was warned about "ghost cards" or something
Is that for actually destroying the card or checking if a card is destroyed or not
You saying former made me think that context.destroying_card is the one doing the destroying so lemme get this straight
context.destroying_card is for checking for destruction
card:remove() is for actually destroying the card?
remove is for destroying a card outside the card calculation loop
however, context.destroying_card (in a card's calculate function) must be used during calculation (instead of before, after or joker_main contexts)
I see I see, I'll see what I can do, thanks for the help
And card:start_dissolve() is just playing the dissolve animation right?
why the fuck is it not above white stake
wtf happened 😭
my stakes arent stakin
Does it do anything functionally different from the two card destruction methods
no
you need to do the destruction during context.destroying_card or it makes ghost copies of the cards right
it destroys the card and plays the dissolve anim
yea
card:start_dissolve() is the fancy animated removal.
card:shatter() is used for Glass cards.
card:remove() just removes without anything fancy.
Aye thanks for the clarification
Gay jokers should be a mod too ngl
"genderfluid joker : when you play 5 cards with 3 cards of them same suit, make the other two that suit"
i don't know how to explain that there's something wrong with attributing genderfluid to gay
if you were going to make a mod that included this it would probably be better named "gendercast" or something like that
LGBTJ+ Jokers, the J is for Joker
genderfluid isn't a sexuality
Should card:remove() or card:start_dissolve() or anything with card: be used with G.E_MANAGER:add_event?
Or can it just be used on its own
How would the cis react to a lgbt mod
I would love to make a mod just to piss em off
who woulb even care?
like genuinely i bont think i know a single person like that anb i've talkeb to like 1000 people on this biscorb
hold on so let me get this straight
was that on purpose
no
pun not intenbeb ):
you want to make a mod for a poker roguelike game to annoy "the cis" you speak of them like a negative group and i'm confused by that
honestly i just think the concept makes for funny gameplay ibeas i bont know what that other person is talking about
"saphic joker : all hearts give x1.5 mult when scored"
is this not just
bloodstone
bloobstone 2: heart boogaloo
but better
oh my god
i bont think thats a healthy minbset
"Gay Joker - +4 Mult" wowie its so much better than the olb homophobic joker! i am very goob at besigning jokers!

i can't count how many enhancements I have made that there's another Joker which does the same thing
holy shit it's madeline
Omg I know
I can not for the life of me keep track of 150 jokers
It could be stamps
Like red stamp gold stamp
What is it called again
Seals
But its flags
i just think you're being uncreative with the ibea now
no but that sucks because thats alreaby been bone by like 500 people
you cant just
take that ibea
when its alreaby been bone
Up your creativity game mate, if you want a Lesbian card
"Score +N mult for each Queen when two or more Queens are played together"
yeah this is what i mean
bloobstone clones are NOT it when it comes to creative jokers
you have a problem with your D key typing B
no i just bo that since i bont have the b key on my keyboarb
i just use b to replace it
oh
Did it break
kid named on-screen keyboard
you should get a replacement
kib nameb thats really annoying to use ngl
i woulb but i have a laptop
you can get replacement laptop keys
Just copy paste the letter
i'm on a laptop i've done that before
you can? thats cool ill try that somebay
Yes
Typing d probably just as fast as copy pasting
yeah sometimes i do that but i need my clipboard a lot for other things; ill just do that tho
windows key +v for clipboard history
oh ok
Or bind a key you dont use a lot to d
yeah i don't think being on topic here is a good idea
Flags
i meant about moddng-dev
not the specific topic
this idea would be absolutely tragic if this guy was involved uhh
any splatoon players
other than you
what does that have to do with it
Yeah see
shit i accidentally bold my text how does that even HAPPWNEWNE
You're bad too
what??#
You assume splatoon players are lgbt
like every couple months maybe
what did i even say
Not good
Not you marie
i code for a splatoon mod
i was going to ask for effect ideas.
because the last effect we had didn't work since talisman doesn't like playing cards
Huge bruh moment over here
i didnt even know that stereotype existed, you should stop assuming things magistas - slotmachineTBOI
can't do xchips
I know how
how is it one line of code and talisman hasn't done it yet
Idk
everything is one line of code if you're willing to sacrifice readability
No
i guess that's true
Its a tiny line of code
if pneumonoultramicroscopicsilicovolcanoconiosis then
That you add before applying xchips
and what would that be
question mark
they'll probably need some time
this method is
very flawed
yeah you did
lmao
chips_mod = hand_chips * (config.Xchips - 1)
that doesn't solve the message problem
i'd assume seals also have calculate functions
the message isn't localized and can't be changed with the value
haven't read the documentation for that
yeah but you have to use self.config.extra instead of card.ability.extra
same for vouchers (kinda)
you can define a loc
the message works but it doesn't change with the value
You need to use a variable
it's in misc.v_dictionary
you can define something like this
then use that for your localization
calculate = function(self, card, context, effect)
if context.destroying_card and context.destroying_card == card then
return true
end
if context.pre_discard then
if table.contains(context.full_hand, card) then
local rank_sum = 0
for _, discarded_card in ipairs(context.full_hand) do
if discarded_card ~= card then
rank_sum = rank_sum + discarded_card:get_id()
end
end
if rank_sum > 0 then
card.ability.extra.mult = rank_sum
card_eval_status_text(card, 'extra', nil, nil, nil, {message = "Volatile!"}, G.C.MULT)
end
end
end
if context.cardarea == G.play and not context.repetition then
if card.ability.extra.mult > 0 then
effect.mult = card.ability.extra.mult
context.destroying_card = card
end
end
end
I'm still trying to figure out the card destruction mechanic, it's just not getting destroyed at all after the card with this Enhancement is scored
Oh yeah I don’t think enhancements have destroying contexts in main branch
Did you fix this?
Yeah it has shatter, but can I modify it to play a different sound or something?
no like Glass Card code
Can you ss your code for the stake?
Yeah Glass Card has card:shatter()
Glass card is hard coded
okay yeah you need to lovely patch a lot for enhancement destruction to work
-# just wait for better calc to fix everything
Agony
ive been waiting for bettercalc since ejwu was still here
grr
What's better calc? A part of Steamodded or something?
But now we have better calc 2!
You need prefix_config
better calc 2: electric boogaloo
Check wiki for formatting
no this didn't work
it just uses the +chips message with the amount of chips added
hell
But yeah, ejwu built enhancements in a really weird way
when in doubt, SMODS.eval_this
-# better calc 2 fixes this too
also how do i do the localization for a seal
if context.cardarea == G.play and not context.repetition then
if card.ability.extra.mult > 0 then
effect.mult = card.ability.extra.mult
card:shatter()
end
end
Something like this?
i tried doing it the way you do jokers but replacing the category with seal
and added a label area because they use those but everything is error/empty
Seals go in Other iirc
oh
I don’t recall where labels go
it didn't work
Yes
okay
Okay this works but it visually shatters before scoring, but the bonus is still applied
The + mult popups just appear in between the gaps where the card got destroyed
Any fix here?
and what do I put in misc.labels to make it work
like ["sealkey"] = "label contents"?
Yeah I believe so
it didn't work
thanks Eremel, Wizard of the Galdur but is this normal
i disabled my mod
but every stake
is an error
i cant advance either
im stuck on white stake
is my steamodded bugged or something
What version of smods are you on?
its a buggy steamodded version isnt it
ohhh
I also have the same error, I thought my save data was corrupted 
I should have Orange Stake unlocked but
There might be some things I missed when stake keys were changed
But wouldn’t be able to diagnose on mobile rn
Yeah like 2 weeks ago
dang
Did re-downloading fix the message at least?
the odds are displaying as nil in nil and the messages are not displaying but the card does work
SMODS.Consumable{
key = 'DoubleOrNothing', -- key
set = 'Spectral', -- the set of the card: corresponds to a consumable type
atlas = 'Jokers', -- atlas
pos = {x = 4, y = 1}, -- position in atlas
loc_txt = {
name = 'Double Or Nothing!', -- name of card
text = { -- text of card
'Has a {C:green,E:1,S:1.1}#1# in #2#{} chance to give 2 spectral packs else give nothing.',
},
},
config = {
extra = { odds = 2 }, -- Configuration: odds of success (set to 2 for 50% chance)
no_pool_flag = 'gamble',
},
loc_vars = function(self, info_queue, card)
info_queue[#info_queue + 1] = G.P_TAGS.tag_ethereal
return {}
end,
use = function(self, card, area, copier)
-- Determine outcome based on odds
local odds = self.config.extra.odds or 2 -- Default odds if not specified
local roll = math.random(1, 2) -- Generate a random roll between 1 and 2 for a 50% chance
if roll == 1 then
-- Success: Grant 2 ethereal tags
add_tag(Tag('tag_ethereal'))
add_tag(Tag('tag_ethereal'))
G.GAME.pool_flags.gamble = true -- Ensure 'gamble' flag is set
-- Return the success message using the correct format
return {
message = "DOUBLE!", -- Display "DOUBLE!" message
colour = G.C.GREEN,
}
else
-- Failure: No tags granted
G.GAME.pool_flags.gamble = true -- Ensure 'gamble' flag is set
-- Return the failure message using the correct format
return {
message = "NOTHING!", -- Display "NOTHING!" message
colour = G.C.RED,
}
end
end,
can_use = function(self, card)
return true
end,
}
you forgot to add vars in your loc_vars function
fixed, ty
Oh snap did that fix actual unlocking too?
try ```lua
loc_vars = function(self, info_queue, card)
info_queue[#info_queue+1] = G.P_TAGS.tag_ethereal
return {vars = {G.GAME.probabilities.normal, card.ability.extra.odds}}
end,
okay so the message isnt fixed but unlocking is
its sorta
half fixed
I downlaoded V1.2
-# released 5 days ago
Nah need to download from main
yippee odds display properly am i doing the message wrong tho because that still doesn't display
The change I just pushed should only change the message
i downloaded from main iirc....
I don’t think consumables usage has a return, you need to use SMODS.eval_this or card_eval_status_text
Huh, I’ll have to investigate later then
I guess I'll keep it for now, since it fixed my issue
@nocturne garnet @violet void all looks good to me, that change I pushed actually broke it 🤣 I guess you both just had old versions? Downloading from main now should work perfectly
thanks Eremel, Wizard of Galdur
why on earth isn't this stopping my if block (not from_edition or (from_edition and no_x)) when from_edition = true and no_x = false
Possibly, got it from Dimserene's pack originally
can this be used to tie the sprite as well to each type?
Im using
.children.center:set_sprite_pos({x = 3, y = 4})
right now, but when I go to the menu and resume the sprite is reset
need to add it to set_sprites as well
as in?
-# maybe I understood
🫧
This one?
yeah
quick question im currently trying to learn go and is currently coding a basic mod manager for balatro; i was wondering if there was any already to see if i should release it
depends on what you mean by mod manager
to install all basic stuff and dependencies
including steammods and lovely
its my current shitty Work in progress
skyline has been working on one for a while now
do you have a link to his github repo by any chance ( im in vacation and bored lol )
I'd like one myself haha, it's not published in any way
haaaa i see; might has well see if i can make this one work and release it then
worst case nobody uses it and i learned go ; best case someone finds it usefull
there are 14 competing standards
prety much lol
right now its installing cryptid; do you know any other mods with alot of depedencies ? so i can test it some more painfull mod
mods tend to not have a lot of dependencies beyond steamodded and sometimes talisman
that is except jen's almanac
now you see giving me a good challeng is where the fun's at
ill try to install that one and see
The sprite is changed in the collection but not in the Joker list
then call set_sprites when you're changing the suit
...lol
I cant get it to work, do you know of any mod that does it?
@frosty dock what do you think about building patch targets in to evaluate play?
so putting something like -- TARGET: before calculation
sure that sounds useful
im confused i thought we were reworking calculation
wdym
i mean i was under the impression that you changed the goal of your pr to be reworking calculation in its entirety and that looks like the exact same thing as before
it's more unifying calculation so that everything is calculated the same way
I don't think calculation as a whole needs redoing
it def does
its way too wasteful
usually around 90% of the calculations done in a hand do absolutely nothing
which usually ends up being 10-20% of the time spent during calculation
sometimes more sometimes less
oh I see what you mean
newest smods has a performance issue but it's funny and relevant tbh
lmao
check_enhancement can just not be blueprintable
not me just adding context.blueprint = math.huge
this might be a little stupid, but if i gave an enhancement -9999 repetitions, would that make it unretriggerable?
-# presuming your not playing cryptid or something
probably not
☹️
nvm this doesn't work 💀
it's still tanking perf though hand eval is better
is there a way to add one of these things, both manually or automatically?
info_queue in the loc_vars function
what is p_dollars? is it played dollars? (so activates when played)
This guide does a good job explaining how to set it up. There’s a link to the example made in the video too if you just want to look at the code https://youtu.be/Zp-4U5TlbxY
...right...
does anyone know/is there a way to get the spawn weights of vanilla enhancements?
wdym? like in standard packs...?
i presume so? im trying to decide what weights to give my modded enhancements, and it'd be useful to know what base game enhancements values are, so i can base them around that 😭
How so? It contains info on how to add an info card, just as they asked
you mean editions right?
this, for enhancements raisedcateyebrow~2
right
is there a way to get the weights of steel/glass/lucky, etc etc
I think vanilla enhancements are unweighted?
would have to double check but I think so
makes sense
It does. It’s how I found out how to do it 
Oh huh, nvm. I guess the author added it to the example code after the fact, as the code provided does have it https://github.com/art-muncher/Example-Mod/blob/main/main.lua
i forgort soz
i only realized after making the video 😭
jfc what are you even going to do with these many blueprints?
Default enhancements are unweighted but they’re given a weight of 5 for weights calculations
What’s your joker set up here btw?
steamodded vscode extension when
Add the steamodded folder to your workspace
I do have it there actually lol

is that the label?
-# and how do I set it?
if you're using loc_vars then add a "label" section with text in it
if you're using separate localization then it goes in misc > labels
i think? at least that's how it works for seal labels
so I assume it's similar
["misc"] = {
["labels"] = {
["modprefix_editionkey"] = "Edition Label",
},
},
which would be this?
-# also yeah that's the label
that’s correct
:D
Label has no e_ though
No no as in it shouldn’t have one
I originally did it like this but it didnt work
you don't put the label in there
you put it under labels under misc, like this
it works now, ty
i just wanted to show my my first attempt
yeah i tried that too the first time
on the topic of localization
mine's not working :(
["descriptions"] = {
["Joker"] = {
["j_modprefix_jokerkey"] = {
["name"] = "name",
["text"] = {
"text",
},
},
},
this is right isn't it
i double checked everything and it's not working
but this works for other mods
yeah looks right, got me the loc file in full?
I dumped localization using the smods thing
i have exactly one joker and one seal in here and the seal works
i changed nothing else it simply does not work
i shouldnt care as much as i do but something in me doesn't want to share full code until it's finished
it should work then
you wouldn't happen to still have a loc_txt on the joker?
name of the loc file?
default
howdy balatro mod squad, i'm currently working on expanding milck's QoL mod to allow me to use the keyboard to navigate the game's UI but i'm running into trouble when attempting to buy anything from the shop... the game crashes and says "attempt to index field 'buttons' (a nil value)" as soon as i hit the key to execute the buy action
which i believe makes sense as i'm likely not passing the correct context to the function and in various iterations of attempting to get it to work it says that the ref_table is nil but where i get stuck is how to pass the context itself when executing the action (or whether or not i'm missing something alongside the context)
why do that when you can just emulate a controller
-# actually there's one reason, mod support for controllers is historically not great
either way the controller emulation already exists
actually the only reason I made this edition is because I needed the text for the info_queue
can I add any text to info_queue without having to make an edition/enhanchment/element in G.center?
I tried but failed
got a question, is there any documentation for the SMODS class? drawing a blank here
depends on what the condition for it is
suits and ranks support adding tooltips through loc_vars
i guess i just totally glazed over the sidebar, my bad.
the condition is the card itself. this card will always have this info_queue
but idk how to add it
what's the card then
You can add almost anything to the info queue
then use the joker's loc_vars??
im sorry if im upsetting you .-.
oh i misunderstood you, sorry
Throw it in the loc tables and use {set = whereveritis, key = key}
you can add any localization entry to use for a tooltip through a loc file
What key is responsible for "undiscovered" cards having different names, if that's a thing?
sorry to bother, is there a debug console i can use? ive tried every key and ive searched around but i want to be sure it isnt another package i need to download.
DebugPlus has a console. 🪝
thank you
I've made it similar to how its done in the vanilla's code, but the text is blank in-game
missed anything?
-# bet its gonna be something stupid
Is it possible to get an Idol-like function where the joker has a rotating variable condition that needs to be met to trigger?
Oh it needs specific_vars = {}too
hm
i want to make a planet card that upgrades two non-custom hands, how can i do this? i cant find much documentation on consumables, and the example mod in steamodded containing 'vulcan' upgrades only its own custom hand, the royal flush.
some planets in cryptid do this, you could use them as reference
the card?
might need some actual color on this tbh
i thought cryptid duplicated playing cards. is that a mod?
the mod
Yeah or maybe a black then white outline on the sprite?
got it. thanks for your patience
I'm looking at Idol code for reference and my biggest roadblock is not knowing how to handle a variable like that in the background. Can I set up global variables and functions with Steamodded?
you just define this function and steamodded will take care of calling it each round
i suck with sprites lmao
at least it has contrast
(and maybe i shouldn't have upscaled my reference by 1.5x only to scale the sprite later, time to undo that)
Where do I define the global variable that I want to change with this call? Does it matter? Here's what I have and I have no clue if this structure is right
you want the global stored somewhere in G.GAME
This looks good imo
And how would I do that? Would I have to patch that in? I have no idea how to do that if so
the 20px looks worse smh
G.GAME.impractical_hand = impractical_hand
It looks nice but gives off a vector art feel which doesn't match with everything else
So just like that? I appreciate your patience with this btw
I've put it as an empty array because it doesnt have dynamic values but it still gives empty text in-game
Im also looking at Cryptid and it does the same thing
I noticed only using "Other" as set works for some reason?
With "Other" as set
guess Ill keep it like this
thanks!
G.GAME.impractical_hand = new_hand, whoops. and just at the end is enough
It's really that simple? Dayum that's nice. Thank you for the help
🤔
made the borders less sharp and went closer to balatro black instead of pitch black
this is fine i think, maybe it should be a little smaller?
actually maybe not
there's no scrollable viewport UI component in vanilla Balatro, right?
gotcha, thanks
I've been meaning to play around with smods so this might be a fun challenge
yeah so maybe this is a bit excessive (50 non-blueprint jokers)
basically every call to get_id is asking each joker for extra enhancements
how do I print this table
and every call to is_suit is doing so twice
via a debug function i made up
ok i've just pushed my changes
I feel like I'm missing something in terms of how this is meant to be structured
you have a syntax error somewhere else
but also SMODS.maximus should be SMODS.current_mod
I think I found it as a rogue end
ok it seems happy with that now, but now it's mad at me for trying to pass it in the joker config
this should be significantly better, 50 blueprints gave me 100k calculations but check_enhancement is barely a factor anymore. for any 50 jokers it definitely still is, given talisman's calc screen still flashes
you don't need to do that
you just use the value from G.GAME when you need it
how did you fix it
you should still use a fallback in case your joker is viewed from the collection, this avoids having to hook into init_game_globals
yeah about that I have a question
If I want to add a new G.GAME var in current_round, would I need to do so with a lovely patch?
you can do that with a simple hook
local igo = Game.init_game_object
Game.init_game_object = function(self)
local ret = igo(self)
ret.current_round.my_value = my_table
return ret
end
idk if this is the right channel but can someone more experienced in pixel art tell me how I can improve the design for my consumables?
art is not my strong suit
Fascinating
i kinda want to make a slay the spire mod for balatro but not sure if i should turn a bunch of relics into jokers or smth else
thanks a bunch! the last thing I needed
-# Im becoming too reliant on lovely patches
shit i can't read
that's not how you declare a function
needs function keyword
I just realized that and declared it as such, however
😭
it's just that the malformed function declaration had everything have an extra end
because it wasn't closing the function
-# i'm part of the 98%
like this
Alright finally launching 
Ok I'm very close to having this working, I just need a way to set the card description to the right conditional when it changes. I'm also realizing I'm not too sure how to properly get a fallback set
Hand to play changes every round correct?
Use this for the fallback
it changes every round
Do I just put this at the bottom of the reset_game_variables and change my_value to the correct one?
no that one goes at the beginning like this
So the top of main.lua?
I'm doing it like this for posterity's sake lol
despite a lack of it in the main game
it's meant to be the same across all such jokers in the same round
you can do end_of_round if you want a different value on each joker
Hmmm, value is still coming up as nil
how did you write it?
Here's the setup now
make sure you're starting a new run to test
I am
isnt the fallback for when youre viewing from collection in the menu
It's coming up as nil in collections
are you sure it's still nil?
I'm looking at it right now 
even when starting a completely new run and spawning the joker back in?
yes
ew, dofile
Just started another new run to double check and it is definitely still coming up as nil in collections
require wouldnt work 😥
SMODS.load_file:
lemme try
cant assign it to a global variable
did you use any lovely patch before doing this
Ok so the fallback is working, it's the function that's changing the variable that's the issue
Looks like Jimbo failed to escape from the rage-filled bear, making him tonight's biggest loser.
Indeed he is
what issue, does it crash or anything
No, the function is setting the condition to nil instead of a hand
Yeah I just figured that out as you posted it
And that was the problem. I put that end in the wrong spot 
And it works! Thank goodness
Thank you all so much for your patience
Ok this is just silly
you can throw a random fifth card
-# it will score
Surely
mm I'd consider bumping it into uncommon
oh look my deck can access context.before
rental playing cards 
Hell yea
oh that's probably why
though I do have an idea of how to do it
just need to try and untangle whatever the hell current retrigger api is
make sure to fix #302 when you do
(i think it's just out of order from not taking into account that effects are only evaluated coming out of eval_card and not right away)
okay
from what I understand of the api, when a joker effect is calculated it should calculate all other jokers with context.retrigger_joker_check and then it should recall the current calculation with context.retrigger_joker?
yeah pretty much
there's some other stuff baked in with callbacks and post_trigger, iirc the callbacks are used by the api to actually eval the effects
do you know when post_trigger should be called?
for each joker after the last retrigger for this calculation unless context.no_callback is set or the first calculation returned no_callback
and callback is there to check that the card has an effect?
from what i can see the evaluation of the effects is moved into the callback with some really janky patches
so instead of happening when eval_card returns, it happens after all the triggers but still inside calculate_joker
right
so the evaluation pattern goes through the jokers, finds one that would retrigger other jokers, retriggers them, then carries on?
yes
ideally we don't need the callback jank and can pass multiple effects out to eval_card
the way I was thinking it would work would be that when the eval_card is initially called on a joker, it then goes through all jokers called joker_retrigger_check and then evaluates the retriggers then, but that would lead to different results I think
i guess this is imprecise. after each joker is first calculated, we call all other joker to see if they want to retrigger this joker, do the retriggers and carry on
moving retriggers out to eval_card is surely cleaner than that
i don't think it has to have different results so long as we ensure consistent use of eval_card
oh yeah I think I can move it out, let me have a quick go
what I have at the moment works for retriggering effects on playing cards at least
then to make sure the agains are in order, eval_card just needs to insert that into the effects with a way to read out the correct order
yeah, and the agains should be on the joker that causes the retriggers right?
the old one just calls card_eval_status_text on the spot
messages are individual-style on ret.card where ret is the return value of retrigger_joker_check
got it
I'm trying to have this joker retrigger any "food jokers" that I have specified in a global table, however my attempts to prevent them from retriggering at the end of a round have not been working for some reason (i.e. it will retrigger gros michel extinction chance when it should not). I've tried checking for the end_of_round context in a ton of different areas but it does not seem to care
local sold_joker_cost = card.cost
card.ability.extra.chips =(card.ability.extra.chip_gain+sold_joker_cost)
card.ability.extra.chips = card.ability.extra.chips + card.ability.extra.chip_gain
G.E_MANAGER:add_event(Event({
func = function() card_eval_status_text(card, 'extra', nil, nil, nil, {message = localize('k_upgrade_ex')}); return true
end}))
end
end
}```
@mellow sable this is what i've got at the moment, but it seems like it takes the first card sold, instead of adding on each one
card.cost is the cost of your own card
oh okay
use context.card.cost
how on gods green earth is betmma vouchers crashing here vro 😭
local O_type = type(O)
ok
it seems it overwrites copy_table
thats why
This switched it to the card being sold, but it's not stacking still
Would i need to add a loop that counts up?
oh it just switches to the most recent card sold
couldn't you directly do something like
card.ability.extra.chips = card.ability.extra.chips + context.card.cost * card.ability.extra.chip_gain
(assuming chip_gain is the chip gain per $1 of buy value)
calculate = function(self, card, context, effect)
if context.cardarea == G.hand and not context.before
and not context.end_of_round
and G.GAME.current_round.hands_played > card.ability.extra.last_hand_number then
local new_rank = math.min(card.base.id + 1, 14)
local suit_prefix = string.sub(card.base.suit, 1, 1)..'_'
local rank_suffix .......
I'm making an Enhancement that makes a card rank up per hand played, but it doesn't work when the first hand is played, but will continue to work normally after the second or further hand is played
last_hand_number is a custom value in the config tag used to track the last hand played as an int
Any insights? The full code is pretty long so I'm only showing a segment of it
where do i start making mods / where can i find docs and or a guide
This works, thanks :)
Another thing, the event i've got to say 'upgraded', is there a way to make that say whatever i want to?
most things i try make it say error lol.
do i need to define it somewhere else?
func = function() card_eval_status_text(card, 'extra', nil, nil, nil, {message = localize('k_upgrade_ex')}); return true
end}))```
it's the 'k_upgrade_ex' section i believe.
you can replace localize('k_upgrade_ex') with a string like "M"
although if you want localization support you should make a localization file and use localization calls still
Tbh, I would love it if someone here made a kind of Mcreator but for Balatro
i dont want that i enjoy coding i just need to know where to start
Start here to install the required clients and mods for modding, they're called lovely and Steamodded, be wary not to install the [DEPRECATED] version, the one we use is in Step 3's Method 3a in the "click here" text
https://github.com/Steamopollys/Steamodded/wiki
This is the documentation, if you have some knowledge of using Lua then it's a good head start
https://github.com/Steamopollys/Steamodded/wiki/API-Documentation
thank you
You'll be able to create your own blinds, jokers, enhancements, editions,e tc
Not exactly modding, but dev. I recreated some of the card logic in c++
Make it say penis
ermmm chat when was i gonna be told that copy_table was recursive
how did you think it worked?
... not recursively
how else would it be done?
for most uses yes recursion would be good
i needed it to Not do that
this hopefully addresses the issue of nodes[1] chaining
see changes for more info
well looks like you have to make your own function
already did
nice
apparently github lua syntax highlighting doesnt recognize [=[ long comments
thats funny
same
Phenomenal
I'm losing my mind, a Joker I made a couple nights ago that was working perfectly is just all of a sudden not. I didn't even touch that code 😭
make it say _G[_G] = _G

peak
Make it say @
§?
#1306355083268722728 if it was peak...
$¥£€
snake ass
Font doesn't have that :/
Sad
The greatest tool to ever grace the face of the Internet
i was talking about the @ symbol
m
lol
Jimbussy
Make it say 'Amo putas', it means I Love Card Games in my language
i have a feeling
that this is not true
It is not
Excellent.
If anyone could help diagnose this I would really appreciate it. No matter what's being played, it always detects 8 retriggers
key = 'combo_breaker',
loc_txt = {
name = 'Combo Breaker',
text = {
'Gains {C:mult}0.5x{} mult',
'per retrigger in a played hand',
'{C:inactive}Starts at 1x mult, resets every hand{}'
}
},
atlas = 'Jokers',
pos = {x = 0, y = 1},
rarity = 3,
config = { extra = {
Xmult = 1.0,
retriggers = 0
}
},
loc_vars = function(self,info_queue,center)
return {vars = {center.ability.extra.Xmult, center.ability.extra.retriggers}}
end,
calculate = function(self,card,context)
if context.scoring_hand and context.repetition and not context.blueprint then
if context.cardarea == G.play or context.cardarea == G.hand or context.cardarea == G.jokers then
-- Add retrigger to total
card.ability.extra.retriggers = card.ability.extra.retriggers + 1
sendTraceMessage('Retrigger logged. Count: ' .. card.ability.extra.retriggers,'MaximusDebug')
return {
repetitions = 0,
card = card
}
end
end
if context.joker_main and card.ability.extra.retriggers > 0 then
-- Add retrigger count and multiply by 0.5 for mult
card.ability.extra.Xmult = card.ability.extra.Xmult + (card.ability.extra.retriggers * 0.5)
G.E_MANAGER:add_event(Event({
func = function ()
play_sound('mxms_perfect')
return true; end
}))
return {
Xmult_mod = card.ability.extra.Xmult,
message = 'x' .. card.ability.extra.Xmult,
colour = G.C.MULT,
card = card
}
end
if context.before or context.after then
card.ability.extra.retriggers = 0
card.ability.extra.Xmult = 1.0
end
end
}```
do it again but make the text upside down 👿
Can someone make a simple mod that adds Dead Man's Hand as a Poker Hand above Royal Flush?
this has the same vibes as asking someone to take a picture of themselves with a shoe on their head
💀
rewrite it in rust to prove you're not catfishing us
mirrored or flipped?
shoe on head
is there a good guide for making new mods
and how much of lua do I need to know if im good with py and C
cause they seem very similar
i know this would probably be hard to do but i had a dream after working on my mod for a few hours about it and i think i was like. kinda cooking in my sleep here chat what do we think abt this
Any way to make this so that when a card gets polychromed in the hand, afterward in the same hand it triggers the polychrome effect? Currently it waits until after the hand.
calculate = function(self, card, context)
if context.individual and context.cardarea == G.play then
if context.other_card:is_suit("Spades") or context.other_card:is_suit("Clubs") and not context.other_card.debuffed then
if pseudorandom('black_rainbows') < G.GAME.probabilities.normal / card.ability.extra.odds then
G.E_MANAGER:add_event(Event({
trigger = 'before',
func = function()
context.other_card:set_edition({ polychrome = true }, true)
return true
end
}))
end
end
end
end
You'll have to iterate through each card in the context.scoring_hand and do the roll individually within context.before.
Well, I want the polychrome effect to happen when it is scored, not before the hand is scored
You apply the polychrome during context.before... before the hand is scored.
or I should also ask, is there someone who would be willing to teach me how to if there isnt a video out there
your best bet is to copy what other people have done and refer to the smods wiki / source code
def look up lua syntax because it does some weird stuff
yeah you're not going to really get any extensive guides / tuts on this sorta thing
it's all learning through osmosis
But I want the polychrome effect to also be applied when it is scored, not before the hand is scored. Like display the animation and everything once it is scored.
Unless I am misinterpreting what you are saying
how many people here post their stuff about making new consumable cards
By iterating through each card in context.before, you set up the polychrome to be accounted for when the hand actually scores.
So if I create the event in context.before, will the animation still play when it is scored, and not all at once before it is scored?
The applying of edition animation and SFX should play... although I'm not sure about it happening individually. See if it happens... if so, maybe you'll need to end up using events to try the individual route.
@faint yacht Heya do you still have the lovely patch for SFX for enhancements?
✌️
How do you use lovely patches in general? Do i just create a "lovely" folder and drop this in?
is there anyone here who has made new consumable cards that could send me over the code to look at? I'd appreciate it a lot
Root of your mod folder.
I have a somewhat outdated guide in the readme that you can follow
but I would instead checkout how smods does it
Gotcha
you can have a patch file at mod_dir/lovely.toml or as many patche files as you want in mod_dir/lovely
Why not look at Cryptid's consumables?
it'll probably be better to look at a smaller mod, cryptid is a bit of a beast
does paperback have consumables?
Thanks for both of yalls insights
But how do ya use this specific patch in an Enhancement? Do I just simply add a sound tag like how I define my atlas? Does it make card_eval_status_text support a sound parameter or something?
Inside card_eval_status_text?
Yeah.
Gotcha gotcha I'll see if I can make it work
You can also define sound when return-ing.
Ok, so I tried this, but it applies the polychrome effect in context.before and plays the sound after the hand is scored. And obviously it doesn't account for retriggers since it's only checking each card once
calculate = function(self, card, context)
if context.before then
for k, v in pairs(context.scoring_hand) do
if v:is_suit("Spades") or v:is_suit("Clubs") and not v.debuffed then
if pseudorandom('black_rainbows') < G.GAME.probabilities.normal / card.ability.extra.odds then
G.E_MANAGER:add_event(Event({
func = function()
v:set_edition({ polychrome = true })
return true
end
}))
end
end
end
end
end
Can't really go more specific than this, I'm still learning stuff myself.
is all of its source code on git
All the source code for any mod to balatro must be publicly available as stated by Lord Thunk himself
oh thats cool
Well, technically, I didn't have my mod up on GitHub when I dropped the first version, but I eventually threw it up there.


