#💻・modding-dev
1 messages · Page 641 of 1
yeah I've been learning how patches work and how to make them since
Yeah, you'd want to patch a check in, though you'd still use a regular set up for your localization file, haha
Oh I should make that auto format at a certain point actually
yeah no I just didn't realise you could add a dictionary to your localization file
does this mean it's impossible or would it just be kind of difficult
In this case, I'd choose to use v_dictionary and pass along a variable, instead of hardcoding the $20 in, btw, so you don't need to change it if you rebalance it
that makes sense
its impossible via the api but patching it is easy
idk how many places you need to patch tho
that's what I figured (and hoped)
Definitely isn't impossible. Difficult if you're new to messing with code and uncomfortable, but if you're comfortable just tearing apart the source code to find where you insert a patch, it's pretty easy!
yeah I do think I'm making progress, just kind of slowly
Probably a lot less slowly than you'd reckon, haha
so theres no way in newer smods to register a item from a pre-existing table?
wdym by that
SMODS.Object(table)?
G.I.CARDAREA?
<@&1133519078540185692>
ANOTHER ONE BITES THE DUST.
kaCHOW
okay I've been working on this and I actually managed to get it working... in the collection. It displays $20 like I want it to, and everything else is normal. However, no matter how hard I try I can't get it to work for the actual blind in-game. I figure this is beyond my skill level so I turn to help
Here's the code that successfully makes the blind in the collection display a different reward:
{
n = G.UIT.O,
config = {
object = DynaText({
string = {
blind.key == 'bl_mysingingjokers_crop'
and localize('b_crop_custom_reward')
or (_dollars and string.rep(localize('$'), _dollars) or '-')
},
colours = { G.C.MONEY },
rotate = true,
bump = true,
silent = true,
scale = 0.45
})
}
}
Here's the code for the in-game blind that I figured would work, as it uses some of the same logic, but it doesn't.
{
n = G.UIT.O,
config = {
object = DynaText({
string = {
blind.key == 'bl_mysingingjokers_crop'
and localize('b_crop_custom_reward')
or {
{
ref_table = G.GAME.current_round,
ref_value = 'dollars_to_be_earned'
}
}
},
colours = { G.C.MONEY },
shadow = true,
rotate = true,
bump = true,
silent = true,
scale = 0.45
}),
id = 'dollars_to_be_earned'
}
},
Oh and also with this code, when a blind is loaded, the game crashes and displays the error "attempt to index global 'blind' (a nil value)"
Where are you putting that code?
I'm patching it in so it replaces the code that generates the blind reward strings (usually a bunch of dollar signs). In theory, it should work like the first bit of code I sent, but it crashes instead
the code is mostly identical to the original, except I add the following logic to it:
blind.key == 'bl_mysingingjokers_crop'
and localize('b_crop_custom_reward')
or {
it should detect if the loaded blind is The Crop and replace the reward string with a custom string, otherwise just work as normal. That's how the code for the blind in the collection book worked, I thought this would be the same
my assumption is that it's something about how blinds are loaded that makes it different, but I'm not sure how to mitigate that
Yes, blind doesn't exist, it would be G.GAME.blind.config.blind.key
I just replaced blind.key with this but it still crashes with the same error
Hi! I've been working on making a reskin, and managed to get some new K/Q/J skins in pretty easily
but I've been trying to add a toggle in the config menu, and for some reason its state never saves. The toggle exists, but will always return to off when the game restarts
actually it's slightly different, it says "attempt to index field 'blind' (a nil value)" instead
Huh, normally that means the variable doesn't exist/hasn't been declared (in my Very limited experience)
what's the code for the toggle
also what's the toggle for
` unbal_nodes[#unbal_nodes + 1] = create_toggle({
label = "Disable Reskinned Jokers",
active_colour = HEX("E01BDE"),
ref_table = UNBALATROABLE_config,
ref_value = "disabled",
SMODS.save_mod_config
})
This is the toggle code, with the config file set up as well
the toggle is to disable reskinning the jokers, but for now I'm just trying to get the toggle to save states between launches
what's UNBALATROABLE_config?
That's the variable where the config reference is stored
you could also make the reskins into a malverk mod inside your mod btw
hmm it should save then..
I did just debate separating it out, have a separate mod for the joker skins that can be enabled or disabled separately yeah
Oh, sick!
I'm still having major issues with this and have made almost zero progress in figuring out how to fix it
Blinds in the collection get rendered differently, and have their own set of variables for the tooltip, iirc, so it wouldn't surprise me if there's a separate instance in the code that you also need to tackle
the second code block is my attempt at trying to do that
I tried using the same logic but it doesn't work unfortunately
and since then I haven't had any epiphanies
I sadly don't have time to help you out right now, much, but feel free to ping me another time this week if you're still struggling
which line does this match up with?
am I right in understanding that you just want to replace the 20 $ signs with a $20?
I believe it was the one with blind.key in which I was told was wrong anyway (replacing it with the right one didn't fix it)
only for a specific blind, all other blinds should be unchanged
oh, why only a specific blind?
The Crop (the blind) gives a $20 reward unlike any other blind, but as it is, a $20 reward looks really ugly in game as it makes the blind really wide
so I just want to replace the blind reward string (usually a bunch of dollar signs) with "$20"
yeah I was trying to judge whether it was just a "this display looks awful" or a specific reason
I will try and remember to fix this through smods so that blinds with a reward greater than whenever it starts to stretch get converted
this would be so good actually
that would be such a useful (if niche) addition
I don't think it's too niche actually
modifying blind rewards seems reasonably likely to be done imo
I'm surprised I haven't seen it in more mods, I've maybe seen one mod do something interesting with it (can't remember what one right now)
do you know when you might be able to implement this? it's fair if it might take a while, I'm sure there's higher priority stuff that needs doing, I'm just curious
so i made a joker that alters denominators of probabilities, and for some reason it applies internally to my custom jokers but not visually on the jokers in-game?
actually it's just not.
applying to my custom jokers at all
you need to use SMODS.get_probability_vars for loc_vars and SMODS.pseudorandom_probability for the probability roll for it to work
I'm currently working on a larger feature when I have the time, but I should be able to get in sorted for the next release (I am aiming for a monthly release schedule moving forwards rather than the sporadic ones we have had the past few months)
that sounds awesome, thank you
should i be using extra_slots_used or card_limit to change how many slots a card with an edition uses?
extra_slots_used
so its just based on if youd rather your counter say 0/4 or 2/5
or does setting card_limit to negative numbers mess things up
I honestly have no idea
yea it's the semantic distinction between "this card modifies how many total slots the cardarea has" and "this card takes up x many slots in the cardarea"
at least in theory, i have no reason to believe setting a negative card_limit or extra_slots_used would have any unintended effects. it's just that it's more reasonable to use extra_slots_used for cards that actually use extra slots
so i have a joker that gives random tags, excluding orbitals or boss-reroll tags, and it was running just fine, until now it crashed
because it couldnt find tag "unknown"
hm, this card is meant to make all debuffed and/or unscored cards scored and undebuffed, but for some reason if an unscored card gets undebuffed it won't get scored as well
ohh does context.modify_scoring_hand ignore cards that were debuffed before context.before happened or smth
cause if so. that sucks a lot and i have no clue how to fix this
awesomeee
is there a way we're supposed to do tags?
send your current code for the joker
i'm not too familiar with tags but i know of some code i can reference for properly creating tags
that code can also help get orbital tags functional if you'd like to include them
SMODS.Joker
{
key = "sunday_comic",
atlas = "jokers",
pos = {
x = 8,
y = 0
},
unlocked = true,
discovered = false,
rarity = 1, -- Common
cost = 6,
blueprint_compat = true,
eternal_compat = true,
perishable_compat = true,
-------------------------
config = {
extra = {
tag_amount = 2
}
},
loc_vars = function(self, info_queue, card)
local config = card.ability.extra
return {
vars = { config.tag_amount }
}
end,
calculate = function(self, card, context)
local config = card.ability.extra
if context.setting_blind and G.GAME.blind:get_type() == "Small" then
for i = 1, config.tag_amount do
repeat
local tag_key = get_next_tag_key()
until tag_key ~= "tag_boss" and tag_key ~= "tag_orbital"
-- potential TODO: orbital tags can be added but it takes a fair bit to do
add_tag(Tag(tag_key))
end
return {
message = localize { type = "variable", key = "v_j_o_y_plus_tag", vars = { config.tag_amount } },
colour = G.C.FILTER
}
end
end
}
interesting
do you happen to have any other mods installed?
and could you post a screenshot of the crash
very strange
everything you're doing looks fine, just something managed to mess up the tag creation process
do you have any other mods installed and turned off?
extracredit, all in jest, jokerdisplay, talisman, paperback
but i dont think those should be affecting...
WE GOT IT
oh?
the local tag_key creation here is local within the repeat loop only
the add_tag can't reference it
ohhhhh that's fucked up
very subtle issue lmao
yea you'll have to add just a local tag_key before the repeat loop
ok i have no clue how to fix this
ive been trying
ive got nothin
modify scoring hand is before before
use press_play instead of before probably
is that a new context
its a year old
in fact i think it was added alongside modify scoring hand
or before
huh
i never did hear of it
press_play doesnt have a context.full_hand so will i want to be looping over G.play.cards?
or have they not moved there yet
they havent, you can use G.hand.highlighted
trying to set up something like drivers liscence and its just not working?
anyone know whats up here
got it im actually just rusty 💔
am i doing smth wrong here
yes, you shouldn't include the assets folder in the path. it already starts in the assets folder
oh right you need the modicon to have the 1x and 2x versions like other assets do
it works! thank you
no problem
how do i make enhancements not show up in standard packs or shops?
thank you!
Making a Joker that has 1 in 5 chance to create a random consumable for every $5 spent, but it keeps crashing, also I had Talisman installed in case this is relevant
SMODS.Joker {
key = "king",
blueprint_compat = true,
rarity = 2,
cost = 5,
atlas = 'Joker',
pos = { x = 7, y = 0},
config = {extra = { money = 5, odds = 3} },
loc_vars = function(self, info_queue, card)
return { vars = { card.ability.extra.money, G.GAME.probabilities.normal or 1, card.ability.extra.odds } }
end,
calculate = function(self, card, context)
if context.money_altered >= card.ability.extra.money and (pseudorandom('fnaf_king') < G.GAME.probabilities.normal / card.ability.extra.odds)
and #G.consumeables.cards + G.GAME.consumeable_buffer < G.consumeables.config.card_limit then
G.GAME.consumeable_buffer = G.GAME.consumeable_buffer + 1
G.E_MANAGER:add_event(Event({
trigger = 'before',
delay = 0.0,
func = (function()
local sets = {'Tarot', 'Planet', 'fnaf_item'}
SMODS.add_card {
set = sets ,
key_append = 'fnaf_king'
}
G.GAME.consumeable_buffer = 0
return true
end)
}))
return {
message = "GAME WIN!",
colour = G.C.Gold,
}
end
end
}
context.money_altered is just true or false
oh
if context.money_altered is true, then context.amount is the actual amount of money being used
also you wanna make sure it's less than -5, because it can be gaining or losing money
also you aren't using probabilities properly, there were some new utility functions updated back in july and now that's the proper way to interface with content that modifies probabilities
read through this changelog it's at the top
https://github.com/Steamodded/smods/releases/tag/1.0.0-beta-0711a
then if context.money_altered == true and context.amount == -5 ?
well it'd be <= -5, but yea
you also don't need to explicitly have == true, just if context.money_altered is the same thing
if i use SMODS.current_mod.extra_tabs could it act as another config tab?
chat is "All Consumables are Free" too good or too bad for a vanilla-type legendary
perkeo is the only monetary legendary joker so think on that :)
i think so, yea. not too familiar with config stuff but you should be able to save that sort of data from anywhere
astronomer is uncommon, in the context of vanilla only i feel like yours would probably just be rare
SMODS.Joker {
key = "king",
blueprint_compat = true,
rarity = 2,
cost = 5,
atlas = 'Joker',
pos = { x = 7, y = 0},
config = {extra = { money = 5, odds = 3} },
loc_vars = function(self, info_queue, card)
return { vars = { card.ability.extra.money, G.GAME.probabilities.normal or 1, card.ability.extra.odds } }
end,
calculate = function(self, card, context)
if context.money_altered and context.amount <= -card.ability.extra.money and SMODS.pseudorandom_probability(card, 'fnaf_king', G.GAME.probabilities.normal, card.ability.extra.odds)
and #G.consumeables.cards + G.GAME.consumeable_buffer < G.consumeables.config.card_limit and G.STATES.SHOP then
G.GAME.consumeable_buffer = G.GAME.consumeable_buffer + 1
G.E_MANAGER:add_event(Event({
trigger = 'before',
delay = 0.0,
func = (function()
local sets = {'Tarot', 'Planet', 'fnaf_item'}
SMODS.add_card {
set = sets ,
key_append = 'fnaf_king'
}
G.GAME.consumeable_buffer = 0
return true
end)
}))
return {
message = "GAME WIN!",
colour = G.C.Gold,
}
end
end
}
still not working
Also this
it crashes when I cash out
what is line 927, that's where one issue is
(also srounding context :)
for this one: i don't think you can have more than one set in an add_card call, you'll need to randomly pick the set before then
for this one: talisman issue i think, does your mod explicitly depend on talisman?
also you still aren't using probability quite right, you shouldn't use G.GAME.probabilities.normal at all. the utility function handles that for you. you also need to use a second utility function, documented in what i already sent you, for the loc_vars stuff
no, but I still kinda want to have support
you have to convert -card.ability.extra.money to the big-number format that talisman automatically converts money into, and add a bit of extra code to the mod to account for if it's being played without talisman
ah so its the to_big function again
for line 927, it honestly looks right to me
the error says attempt to compare table with number so make sure one of your vales isn't coming out as a table, because that's the only way i think it could break, also typos can be a killer lol
it's the talisman thing
OH
talisman automatically converts money into its bignum format, which is a table
that's weird
honestly you should be using amulet instead
I already have a bit of code in ase it doesn't support talisman, so half of it is done
lua physically cannot represent numbers larger than about 1e308 as a simple number format, so talisman implements a custom table that represents larger numbers
it automatically converts all money to that table format for. reasons. idk lol
ah that's good, so then it should just be throwing a to_big onto -card.ability.extra.money
Yeah no it didn't work
SMODS.Joker {
key = "king",
blueprint_compat = true,
rarity = 2,
cost = 5,
atlas = 'Joker',
pos = { x = 7, y = 0},
config = {extra = { money = 5, odds = 3} },
loc_vars = function(self, info_queue, card)
return { vars = { card.ability.extra.money, G.GAME.probabilities.normal or 1, card.ability.extra.odds } }
end,
calculate = function(self, card, context)
if context.money_altered and context.amount <= to_big(-5)
and SMODS.pseudorandom_probability(card, 'fnaf_king', G.GAME.probabilities.normal, card.ability.extra.odds)
and #G.consumeables.cards + G.GAME.consumeable_buffer < G.consumeables.config.card_limit and G.STATES.SHOP then
G.GAME.consumeable_buffer = G.GAME.consumeable_buffer + 1
G.E_MANAGER:add_event(Event({
trigger = 'before',
delay = 0.0,
func = (function()
local sets = {'Tarot', 'Planet', 'fnaf_item'}
local random_set = pseudorandom_element(sets, 'random_consumable_set')
SMODS.add_card {
set = random_set ,
key_append = 'fnaf_king'
}
G.GAME.consumeable_buffer = 0
return true
end)
}))
return {
message = "GAME WIN!",
colour = G.C.Gold,
}
end
end
}
try using to_big on both sides of the <= then
given the error before, i'm fairly sure context.amount is a bignum sometimes but i guess not in this instance that caused this crash
perfect it worked ow thanks
i'm trying to get tooltip to work but i don't know how
Is there a way to detect a card when changing suits
context.change_suit should work I believe
How do you make a joker with the effect of retriggering other jokers?
context.retrigger_joker_check
How is that implemented? I haven't seen that used before
if context.retrigger_joker_check then return {repetitions = 1} end would retrigger every joker, if you have it enabled.
Oh
Wow it's really that easy
thanks a bunch spent way to much time trying stuff that didn't work
if context.retrigger_joker_check then
return {
repetitions = 1
}
end```
I'm using this but it doesn't seem to be working the way it should
Joker Retriggers are an optional feature that needs to be enabled
Ah is there anything online that goes over that or is it just a line of code?
It's a single line of code. The smods wiki does explain it somewhere, though I sadly don't remember exactly where
I'd check the wiki for mentions of optional features. Alternatively, you can check the code for other mods that use triggers and search all for 'optional'. My mod Kino does, and I know Cryptid does
Does anyone knows how to make a changing-color text just like in the Perkeo description ? can't find it anywhere :c
Like the way the word negative, right?
Yes
You'll want to make an SMODS.Gradient object with your colours. There's a bit more detail to it, but I'd start with looking into that!
Okay thanks ! that should help me a lot
I'd offer a better explanation but I don't remember by heart. I can check later if you're still stuck!
Check SMODS.Drawstep
Does anyone know what the code would be to check for the least played poker hand in a run?
https://github.com/nh6574/VanillaRemade/wiki#how-do-i-get-the-most-played-hand this, but swap out the starting -1 for math.huge and change the play count check to hand.played < played
Tyyy
is it possible to get the next joker in the joker order? (like the next one you're gonna get if you reroll or open a buffon pack), and then show that in a joker description?
Yes, though it's not easy to set up
The misprint legendary or epic (I don't remember it's name) in Cryptid has this as a secret effect, showing you the joker order of the next joker that will spawn, so you could see how it works in that code. If you're lucky, it's been rewritten to be readable, but there's a chance it's still the old spaghetti, or that feature has been removed. But the idea is basically that you just check what the next randomization seed will be, so you can predict what the shop will roll
alright imma check it out then
Hi how do i make a deck in balatro what starts with a specific joker and debuffs and buffs??
omg the code looks so complicated😭🙏
for some reason i can't send the code here tho
I recommend not opting to mess with the randomness unless you're very comfortable with programming, yeah. Before Ruby rewrote the way Cryptid handles that code, I had to untangle the old code's implementation of spawning cards, and prediction was such a huge chunk of it that was littered throughout, and it made me scrap any similar ideas from my own mod, haha
godamm, i guess i'll think of another effect my joker would do
I guess you can have an effect like polychrome but for x chips
what do u think about this concept of a joker
thought it seems nice at first
but now realizing what's the point of the mult gain for Cavendish when u can just feed it Michel
how can i get the jokers in the current shop when exiting it
also we made a C4 joker to possibly be a command for the twitch intergration but not sure how it should function
Ice, out of interest, have you ever experimented with the predict seed flag in pseudoseed? I noticed it recently but haven’t had chance to play with it?
I've not touched it at all. I made a note of it to mess with it, but after I saw what cryptid tried to do to make the same mechanic I wanted to work, I moved that to the lowest priority and have yet to give it a second chance, haha
It would make sense to work like that, yeah
what cardarea contains the shop jokers
G.shop_jokers
Is there a way to check if a joker appears in the shop or do u just have to keep rerolling to check I have a joker I want to not appear in the shop at all
But not sure how to check
theres in_pool
its a function to check whether to spawn the joker you want
returning true makes it elegible for spawning
otherwise it wont
something like this (from vanillaremade's cavendish)
look at just the bottom part
Cool thanks
np
No, it's in_pool = function() return false end
Being using a mixture of joker forge and my own code so
It's be kinda of a pain

Thankfully been getting better at Lua
Appreciate it
my cardarea wont make cards show up inside it
it still counts cards inside it but they dont get moved there
change trinket to jokers
in the type
im using my own center type
oh
cardarea type just determines how the area behaves and not the actual contents
same thing
sorry it's 'joker'
can the low contrast and high contrast parts of a deckskin have different loc-txt variants?
what does that have to do with their question
nw i could have explained it better
like for a deckskin it would have a loc-txt that shows in the customization menu right
but for the high contrast version it would have the same loc-txt
is there a way to make a different text show up
you want to check when high contrast is enabled or do you want the color to stay the same regardless of contrast
i guess check when its enabled? the color isnt what im focusing on
im checking the wiki and it says you can have a loc txt per palette it seems
this should be it i think
yeah, you can add to each palette it's own loc_txt
oh nice ok
but i use the lc_atlas and hc_atlas is that two separate palettes?
sorry im not super familiar with this stuff
ive never made a deckskin so i dont know the options too well, can i see your code
the example has this
in each palette you can add a loc_txt
im on my phone right now so ill send when i can
oh ok mine is kinda different but i can see how to make it like that
thanks ill show you my code if i need any more help
how can i directly change a center's size when its being created? the way i have it rn just doesnt seem good to me
generate_ui is for the hover description
i noticed, i just dont know what other function i could put it in
this doesnt work? https://github.com/Steamodded/smods/wiki/API-Documentation#display_size
worked, ty
is there a function i can use to determine which poker hands a given poker hand contains? using name of hand, not a table of cards
it would be easy enough to just check for all hand types manually but that feels hacky
yea no there's no function that does that afaik
and if there was it'd just offload the "check all hand types manually" work to the function
what are you planning to use it for tho?
To check if final played hand of round contains a full house
In the end of round context so there's no cards to look at
So I use G.GAME.last_hand_played
well G.GAME.last_hand_played is a string no?
you can really get the played cards at that point
Yeah so I can check if it's "full house" or "flush house"
I'm just wondering if there's a better way cuz if there are modded hands that contain a full house then it's borked
you would need to save the contained hands when the last hand is played
getting it from the string is impossible
honestly what i'd do is just check for whether every hand contains a full house, save that status as a boolean variable in the card's ability table, and then just act on that variable in end_of_round
Yeah seems fine
Thanks y'all
if context.before and next(context.poker_hands['Full House']) and not context.blueprint then
card.ability.extra.fullhouse = true
else
card.ability.extra.fullhouse = false
end
This appears to not be doing the thing
because of how the condition is set up, the else clause runs in every context that isn't context.before and the variable just gets forced back to false
ohh duh
thanks
I feel like I've gotten alright at coding these things but something like this trips me up once in a while lol
How do I set the order of my Jokers in the collection? Is the only way to literally reorder them in the code?
yes
amazing
changing the way smods loads objects for that would be a lot of work tbf
i think its a case of someone needing to sit down a work out some kinks the order problem has when the solution is already very easy and unless you have a million jokers it doesnt matter
Does the collection have to display things in load order tho? Maybe it could be patched to look for a variable in every object and order them according to that if the variable is present
how am i meant to use setability
Per mod maybe, so objects from different mods don’t get jumbled up
no, it is totally possible to do that i have a custom collection myself
what im saying is that there are decisions you have to take for that that no one has taken yet because the problem is kinda niche
for what
setting up initial values
i would appreciate a more detailed explanation of what you're trying to do
im trying to make an value in extra get randomized as soon as the card gets generated in the shop instead of after getting bought
you can just do card.ability.extra.whatever = random in set_ability
check to do list in vanillaremade
is therea a upper limit to how many things there can be in a table
theoretically no
well
run out of memory
there always is
and love2d has a very small hard limit
don't remember exactly what it is rn
i say "very small" but its fine
you wont hit it
you do not have to care unless you're doing crazy shit
thanks N
neither of these are strong enough to be legendaries
stanczyk's essentially a sidegrade to dna, and skelton is not nearly likely enough to be worth holding onto
make them give 100x mult
make them _ _
make them...
buffed
Chance based revive kinda sucks in general
Skelton sounds really unfun. Most RNG in the game has some way to either improve consistanxt (making the trigger occur more often, getting more of the card, etc.). This is just if you lose there's a chance (worse than wheel of fortune) you don't. It can't be relied on or manipulated. I feel like some sort of activation would make more sense, (such as maybe a counter like loyalty card or invisible) or maybe a condition (like Mr. Bones)
Its really unreliable unless you have enough probability increases in which case you just win
well i accounted for that by making it fixed chance
it still sucks
Oh okay
Its still rng yeah
yeah i might redo skelton completely
Randomly not losing is just kind of an instant sell usually
Its RNG with no way to effect it
anyway thoughts on the new stanc?
its only good if you're doing bad
you just got a legendary lmao
What if it was just prevents death, and destroys all other jokers (or maybe just a random one)
probably have a decent build or you got scammed
And you're very lucky
then destroys itself if you have none?
Probably something like that
Ant sort of renewable ibstant win is hard to balence and keep fun
@coral flume Best to discuss such here. Check for context.mod_probability and context.identifier being either 'lucky_mult' or 'lucky_money'.
im currently reworking "the whip" boss blind bc it doesnt work, so i went with a different approach
Oh cheers!
SMODS.Blind {
key = "hatch_whip",
dollars = 5,
mult = 2,
debuff = { h_size_ge = 3 },
pos = { x = 0, y = 2 },
boss = { min = 1 },
boss_colour = HEX("cbb9a3"),
atlas = 'CustomBlinds',
loc_txt = {
['name'] = 'The Whip',
['text'] = {
[1] = 'All consumables',
[2] = 'are debuffed',
},
},
calculate = function(self, blind, context)
if not blind.disabled then
if context.debuff_card and context.debuff_card.area ~= G.consumables then
return {
debuff = true
}
end
end
end
}```
it no worky
what do i do
ignore the min = 1, this is just for testing purposes
how do i fix this? What im intending is for it to start like a timer and update every second?
who
oo
Of course it is 
Did you look at update on the wiki
For SMODS.Joker
Or any center for that matter
make it a chargeable revive only usable once every couple rounds. "Beating a round charges this joker 33%. When at 100%, prevent death."
im dumb lmao mb
gets it up to 99% and dies
i want it to update every second, how can i make that work if its even possible?
the dt argument that gets passed to update is the time elapsed since the last call of update, in seconds iirc
you can add dt to a variable stored in the joker until the variable reaches 1, then reset that variable to 0 and do the thing you wanted to do
ah
whats the best way to get started in mod development:)
tysm!
ok i read up on installing and using vscode for modding but i dont quite think i understand this part
where exactly would i put that in the workspace settings or what exactly would i put in the .luarc.json file?
okay i managed to get it to update
thing is, how can i make it update while viewing the description of the joker? will I have to mess around with dynatext like how misprint works?
is the path relative to the path of the mod or relative to the system?
Both should work
i got it
for some reason i saves my .json to the steamodded folder and not my mod's folder
similar but it doesn't have to be dynatext
https://github.com/nh6574/VanillaRemade/wiki#how-do-i-add-text-to-the-description-of-my-card-that-updates-in-real-time
Thx
whats the easiest way to make soul cards only spawn the vanilla legendaries? im thinking of just taking ownership of each and adding them to a pool to then edit soul to spawn from that pool, but im sure this is a common problem that might have easier fixes
You would put in_pool = function() return false end in your Legendary jokers.
ok makes sense, in my case i do need to keep those modded legends in a pool for a separate consumable, so maybe its best to set up a pool for the vanilla ones
No, you would check if the source is the key_append you might be using when you create the joker.
Hi, i'm a complete beginner and i'm using jokerforge
I tried to make a baron-like joker but i immediately crashed
When i tried to use it
Idk what to do right now
This channel is more for traditional coding, not jokerforge support. I’d recommend either learning Lua (as you can do more fun/interesting things) or joining the JokerForge discord server (found here https://discord.com/channels/1116389027176787968/1386843228330004611)
What distinguishes this channel from #⚙・modding-support?
modding-support is for support installing and playing mods
this channel is for discussion of making and developing your own mods (including support in that aspect)
So, could any of you be a dear and tell me why this Blind's innermost function never gets called?
-- The Gale
SMODS.Blind {
key = "gale",
unlocked = true,
dollars = 5,
mult = 2,
boss = {
min = 1
},
boss_colour = HEX("B1DDBF"),
calculate = function(self, blind, context)
if not blind.disabled and context.before then
print('A')
if #context.scoring_hand > 1 then
for i = 1, 3 do
print('B')
G.E_MANAGER:add_event(Event({
trigger = 'immediate',
func = function()
G.E_MANAGER:add_event(Event({
func = function()
context.scoring_hand:shuffle('bl_lapsems_gale')
play_sound('cardSlide1', 0.85)
delay(0.15)
print('Whoosh!')
return true
end,
}))
return true
end
}))
end
delay(0.35)
end
end
end,
}
draw = function(self, card, layer) if (layer == 'card' or layer == 'both') and card.sprite_facing == 'front' then card.children.center:draw_shader('funmode_monochrome', nil, card.ARGS.send_to_shader) if card.seal then G.shared_seals[card.seal]:draw_shader('funmode_monochrome', nil, card.ARGS.send_to_shader, nil, card.children.center) end end end,
(This is draw function from shader)
For some reason instead of shader being applied to seal and card, it does this and card just turns white :/
are you online?
because I may have a fix
I think adding G.shared_seals[card.seal].role.draw_major = card fixes shadered seal position but shader is still being drawn under the seal
You should be using SMODS.DrawStep
Thank you!!!! It looks really good
What do you prescribe?
this
calculate = function(self, blind, context)
if blind.disabled or not context.before then return end
if #context.scoring_hand <= 1 then return end
for i = 1, 3 do
G.E_MANAGER:add_event(Event({
delay = 0.15 * i,
func = function()
for j = #context.scoring_hand, 2, -1 do
local k = pseudorandom('bl_lapsems_gale', j)
context.scoring_hand[j], context.scoring_hand[k] =
context.scoring_hand[k], context.scoring_hand[j]
end
play_sound('cardSlide1', 0.85)
return true
end
}))
end
end
calculate = function(self, blind, context)
if blind.disabled or not context.before then return end
if #context.scoring_hand <= 1 then return end
for i = 1, 3 do
G.E_MANAGER:add_event(Event({
delay = 0.15 * i,
func = function()
for j = #context.scoring_hand, 2, -1 do
local k = pseudorandom('bl_lapsems_gale', j)
context.scoring_hand[j], context.scoring_hand[k] =
context.scoring_hand[k], context.scoring_hand[j]
end
play_sound('cardSlide1', 0.85)
return true
end
}))
end
end
not sure if it works though
but you could I guess just manually shuffle the deck
It did nothing.
oof
Y'know, I might be able to pull this off with a patch instead.
I appreciate your care, though.
you're welcome
nice
context.scoring_hand wouldn't exist anymore in the event.
is it possible to make your own text with jimbo from the tutorial?
Trying to find find how tutorial jimbo text is done searching around using tutorial
i think you need to use add_speech_bubble and say_stuff
that's what i used for hot potato anyway
I'm sorta what i've been trying lol
but I didn't know about say stuff gonna try that
Mod Developer Chaos. Contribute to Balatro-Potato-Patch/Hot-Potato development by creating an account on GitHub.
chara is a card character object
right now just a simple text on screen
if not whitelist[user:lower()] then return end
if is_on_cooldown() then return end
if not text_to_show or text_to_show == "" then text_to_show = "Hello!" end
attention_text({
text = text_to_show,
scale = 0.8,
hold = 4,
align = 'cm',
colour = G.C.WHITE,
major = G.play
})
play_sound('voice1', 0.8, 0.5)
end```
is there a way to remove a certain joker from the shop pool?
G.GAME.banned_keys['j_modprefix_key'] = true
no shit
THEYVE ESCAPED
What type of sandwich would you assosiate with the spades suit
grilled cheese
ham and swiss
brisket
i was about to say a club sandwich and then i read what i was typing and realized im a dumbass
we're probably not gonna tackle this yet but on a scale of 1 to 10 how difficult would it be to code a joker effect that copies a blind effect
the blind it's copying being effectively variable
Many thanks everyone 🧡
I have code here for a blind that makes 3 random ranks drawn face-down:
SMODS.Blind {
key = "winds",
dollars = 5,
mult = 2,
pos = { y = 10 },
boss = { min = 1 },
atlas = 'MySingingBlinds',
boss_colour = HEX("e0b06c"),
set_blind = function(self)
self.selected_ranks = (function()
local ranks = {}
while #ranks < 3 do
local rank = math.random(2, 14)
local duplicate = false
for _, v in ipairs(ranks) do
if v == rank then
duplicate = true
break
end
end
if not duplicate then
table.insert(ranks, rank)
end
end
return ranks
end)()
end,
stay_flipped = function(self, area, card)
if self.disabled then return end
if area == G.hand then
local card_id = card:get_id()
for _, rank in ipairs(self.selected_ranks) do
if card_id == rank then
return true
end
end
end
end,
disable = function(self)
for i = 1, #G.hand.cards do
if G.hand.cards[i].facing == 'back' then
G.hand.cards[i]:flip()
end
end
for _, playing_card in pairs(G.playing_cards) do
playing_card.ability.wheel_flipped = nil
end
end
}
There isn't an issue with the blind itself, it works well, but I'm wondering if there's a way for it to include modded ranks, as right now it can only flip vanilla ranks
You think a command where it just spawns something on screen that the streamer can't get rid off would be a fun command for twitch integration
instead of checking the id you can check the key at card.base.value
also don't use math.random, use pseudorandom to respect the seed
you can get a random rank with pseudorandom_element, check the smods.rank docs
ok, thanks, I'll have a look
how can i make the sell ui box appear on my custom card
probably have to modify G.UIDEF.card_focus_ui
Could anyone say why the left statement returns a range of values but the right one doesn't?
ok i may have found it but how do i make the weights get undone when you lose the card
lua isnt fit for generating random numbers with decimals, you should try first making a random big integer number and then dividing it
in this case you could try math.random(25, 125)/100
look at this
that's not weights???
where it says
remove_from_deck = function(self, card, from_debuff)
--stuff
end,
wouldnt you just do the reverse?
2 things affecting the rates
O
no bc i'm not just adding to the weights
which i'm not doing either
i'm gonna normalize the weights between multiple rarities
-# oops sent early
add the rarities' weights together and divide by the amount of rarities
okay
because its a multiplier that always starts at 1
so should i patch instead?
okii
i'm looking at it and idk what i'd do to do what i said
😭
where i'd put it in the func and what vars i need to use
actually wait you could probably do a hook
oh cool 
check if the returned key is that of one of the affected rarities, and if so return a random one of the rarities
well because its normalizing the weights right
yea?
why doesnt this work
so when it wouldve normally rolled any of the rarities its effectively choosing an unweighted random rarity out of the affected ones
so would that have the same effect as all rarities being equally likely?
should be
ok
Is there a way to remove what mod a custom consumable is from
I made a fake soul troll card for the twitch mod
But the scrolling text of what mod it's from is a giveaway
You may be pleased to know that I got it working!
ok i'm struggling on the hook
whatre the issues
you need to do it after because you need the return value
add no_mod_badge = true to the joker
Thanks
also no_collection = true if you dont want to see it in the collection
I tried setting it to being locked
But started a new profile and it was still unlocked
But that works much better
Wish stuff like this was mentioned more on the smod wiki would help a ton
now if only I can figure out how to add the ability to put a jokers name in the create_card using twitch chat
I've almost got it working I just can't get the text to read from chat
i got a joker which draws the first hand face down, and gives xmult when a card played face down is scored
i got the context to flip them down, but i need some pointers as to the context to use for checking which cards in the played hand are face down prior to flipping them and revealing the hand
would this be context.before or context.press_play? something else? unsure if these contexts allow me to search the cardarea and the scoring hand.
how would i make legendary jokers appear in shop
use Detained joker
hook create_card, check if key_append == "sho" and _type == "Joker" and not legendary
and add a chance roll to that
then set legendary to true if it passes
sho?
yeah
o right that's the shop thingy
thunk moment
i saw that when getting the poll_rarity hook working
actually
i would set rarity to 4 instead
since legendary bypasses unlock state if true
local oldgetcurrentpool = get_current_pool
function get_current_pool(_type, _rarity, _legendary, _append)
if _type == 'Joker' and _append == 'sho' then
local poll = pseudorandom('rarity'..G.GAME.round_resets.ante.._append)
if poll < (1/odds) then
_legendary = true
end
end
return oldgetcurrentpool(_type, _rarity, _legendary, _append)
end
oh that seems much safer i think
what's with the 'rarity'..G.GAME.round_resets.ante.._append tho
like that it would be affected by context.mod_probability and context.fix_probability
fyi
does it need to be this seed
not specifically, but adding _append and current ante makes it so the seed will actually be affected by the key_append used
ok
idk why current ante but vanilla does that often so its probably important
Make pools separate between different antes
ah
is there a proper way to check this? breaks because indexing self is nil context.scoring_hand[i].self.facing == 'back'
Yes, remove .self
keep in mind unless some mod messes with it scoring cards are always going to be face up
yeah, currently trying to have contexts access a shared local array for cards that were played face down
the way we checked for if a played card is face-down is we check the moment you hit the play button
ignore the reply i forgot i left that there
i meant to bump that question
i got it working ty
probably easy for modded stuff, for vanilla stuff it might be slightly more complicated due to how theyre hardcoded to check for names
also each blind function needs to be called at the appropriate time
SMODS.blindprint_effect when
SMODS.Blind when 
genius
what might be causing this to not give xmult when scoring face-down-played cards?
config = { extra = { xmult = 2 } },
loc_vars = function(self, info_queue, card)
local targeted_cards = {}
return { vars = { card.ability.extra.xmult } }
end,
calculate = function(self, card, context)
if context.stay_flipped and context.to_area == G.hand and G.GAME.current_round.hands_played == 0 and G.GAME.current_round.discards_used == 0 and not context.blueprint then
return {
stay_flipped = true
}
end
if context.press_play and context.cardarea == G.scoring_hand and not context.blueprint then
for i = 1, #context.cardarea do
if context.cardarea[i].facing == 'back' then
targeted_cards[#targeted_cards + 1] = 1
else
targeted_cards[#targeted_cards + 1] = 0
end
end
end
if context.individual and context.cardarea == G.scoring_hand then
for i = 1, #context.cardarea do
if targeted_cards[i] == 1 then
return {
xmult = card.ability.extra.xmult
}
end
end
end
end,
G.scoring_hand isnt a thing
oh yeah haha it's just context.scoring_hand
also you should store if the card was flipped on the card itself probably
let me try that rq
i don't know how to do that... how can that be done?
set .was_flipped or .ability.was_flipped or whatever on the card
just remember to reset the flag after the hand if you put it in ability
@red flower, speaking of cards and how they're defined when "Play Hand" is pressed, could you tell me why this doesn't work? It shuffles the positions of the cards, but when it's time to score them, they revert to their previous positions.
[[patches]]
[patches.pattern]
target = 'functions/state_events.lua'
match_indent = true
position = 'after'
pattern = '''
G.FUNCS.play_cards_from_highlighted = function(e)
'''
payload = '''
-- This is utilized by The Gale.
if (G.GAME.blind.config.blind.key == 'bl_lapsems_gale') and not G.GAME.blind.disabled and (#G.hand.highlighted > 1) then
G.GAME.blind.triggered = true
G.GAME.blind:wiggle()
local LAPSEMS_selected_cards = {}
for i = 1, #G.hand.cards do
if G.hand.cards[i].highlighted then
LAPSEMS_selected_cards[#LAPSEMS_selected_cards + 1] = i
end
end
for i = 1, 3 do
G.E_MANAGER:add_event(Event({
func = function()
delay(0.15)
for j = #LAPSEMS_selected_cards, 2, -1 do
local k = pseudorandom_element(LAPSEMS_selected_cards, 'bl_lapsems_gale')
G.hand.cards[j], G.hand.cards[k] =
G.hand.cards[k], G.hand.cards[j]
end
play_sound('cardSlide1', 0.85)
print('Whoosh!')
return true
end
}))
end
--delay(0.35)
delay(03.5)
end
'''
why are you patching for this
So I can be sure it happens before anything else in G.FUNCS.play_cards_from_highlighted().
context.press_play already does that
also did you not read this #💻・modding-dev message
I'm not calling upon context.scoring_hand anymore.
well
the point is
you literally dont need to patch
just use the old function but shallow copy the old scoring hand to a local variable
so it still exists in the event
What is the old function?
oh ok i started a new run and
the calculate that you used first
@slim ferry works now except for one bug where the xmult is applied to the first scored card instead of the nth scored card, where n applies to each card that was played face down. current code looks like this:
config = { extra = { xmult = 2 } },
loc_vars = function(self, info_queue, card)
return { vars = { card.ability.extra.xmult } }
end,
calculate = function(self, card, context)
if context.stay_flipped and context.to_area == G.hand and G.GAME.current_round.hands_played == 0 and G.GAME.current_round.discards_used == 0 and not context.blueprint then
return {
stay_flipped = true
}
end
if context.press_play and not context.blueprint then
for i = 1, #G.hand.highlighted do
if G.hand.highlighted[i].facing == 'back' then
G.hand.highlighted[i].ability.was_flipped = true
else
G.hand.highlighted[i].ability.was_flipped = false
end
end
end
if context.individual and context.cardarea == G.play then
for i = 1, #context.scoring_hand do
if context.scoring_hand[i].ability.was_flipped == true then
context.scoring_hand[i].ability.was_flipped = false
return {
xmult = card.ability.extra.xmult
}
end
end
end
end,
does G.hand.highlighted refer to a subset of the played cards?
you should check context.other_card since the current code checks if any card in the hand was flipped
works fine if there's multiple
and only reset was_flipped for the whole hand in context.after
SMODS.Voucher {
key = "mixup",
atlas = "vouchers",
pos = {x=0,y=0},
cost = 10
}
SMODS.Voucher {
key = "breakthrough",
atlas = "vouchers",
pos = {x=1,y=0},
cost = 10,
requires = "v_elle_mixup"
}
local rarity1 = {[1]=true,[2]=true,[3]=true} -- Rarities to check for, formatted for easier checking
local rarity2 = {1,2,3} -- Rarities to pick from
local pr_hook = SMODS.poll_rarity
function SMODS.poll_rarity(_pool_key, _rand_key, ...)
local pr = pr_hook(_pool_key, _rand_key, ...)
return (#SMODS.find_card("v_elle_mixup")>0 and rarity1[pr]) and pseudorandom_element(rarity2, "elle_rarity_mix") or pr
end
local gcp_hook = get_current_pool
function get_current_pool(_type, _rarity, _legendary, _append)
if #SMODS.find_card("v_elle_breakthrough")>0 and _type == 'Joker' and _append == 'sho' and pseudorandom('ellerar'..G.GAME.round_resets.ante.._append, 1, 20)==1 then _legendary = true end
return gcp_hook(_type, _rarity, _legendary, _append)
end```
this is my whole voucher code why is it iterating through a string now
works now, thanks!
requires = "v_elle_mixup"
@red flower and/or @slim ferry: this produces a crash. What now?
calculate = function(self, blind, context)
if not blind.disabled then
if context.before and #context.scoring_hand > 1 then
G.GAME.blind.triggered = true
G.GAME.blind:wiggle()
for i = 1, 3 do
G.E_MANAGER:add_event(Event({
func = function()
delay(0.15)
for j = #context.scoring_hand, 2, -1 do
local k = pseudorandom_element(j, 'bl_lapsems_gale')
context.scoring_hand[j], context.scoring_hand[k] =
context.scoring_hand[k], context.scoring_hand[j]
end
play_sound('cardSlide1', 0.85)
print('Whoosh!')
return true
end
}))
end
delay(0.35)
end
end
end,
it should be requires = {"v_elle_mixup"}
you didnt store context.scoring_hand in a local variable
that was
the thing i linked you
did you know that the actual text of the crash is probably helpful for other people to identify the issue :)
but also what eris said yea
Can I not modify it directly, only through a variable?
correct, you can't modify it directly
because it's in an event, context.scoring_hand ceases to exist by the time the event actually runs
Like this?
local list_of_scoring_cards = context.scoring_hand
it should be SMODS.shallow_copy(context.scoring_hand)
What does SMODS.shallow_copy() do?
i dont think this is close enough to what I was talking about to tag me about it
im playing etrian odyssey im busy
it copies all the values directly within the given table to a new table
then returns that new table
calculate = function(self, blind, context)
if not blind.disabled then
if context.before and #context.scoring_hand > 1 then
local list_of_scoring_cards = SMODS.shallow_copy(context.scoring_hand)
G.GAME.blind.triggered = true
G.GAME.blind:wiggle()
for i = 1, 3 do
G.E_MANAGER:add_event(Event({
func = function()
delay(0.15)
for j = #list_of_scoring_cards, 2, -1 do
local k = pseudorandom_element(j, 'bl_lapsems_gale') -- Now this line produces a crash. What now?
list_of_scoring_cards[j], list_of_scoring_cards[k] =
list_of_scoring_cards[k], list_of_scoring_cards[j]
end
play_sound('cardSlide1', 0.85)
print('Whoosh!')
return true
end
}))
end
delay(0.35)
end
end
end,
because j is a number
you cant pseudorandom_element a number
also btw is there even a reason you cant just do G.play:shuffle()
if you shuffle them the play order doesn't change iirc
Just tried it with G.play:shuffle(), and the play order did not change. What am I to do?!
I've resorted to using a patch so the shuffled order gets set in stone before any other function acts on it, but it still crashes. Now what?
[[patches]]
[patches.pattern]
target = 'functions/state_events.lua'
match_indent = true
position = 'after'
pattern = '''
G.FUNCS.play_cards_from_highlighted = function(e)
'''
payload = '''
-- This is utilized by The Gale.
if (G.GAME.blind.config.blind.key == 'bl_lapsems_gale') and not G.GAME.blind.disabled and (#G.hand.highlighted > 1) then
G.GAME.blind.triggered = true
G.GAME.blind:wiggle()
for i = 1, 3 do
G.E_MANAGER:add_event(Event({
func = function()
delay(0.15)
G.hand.highlighted:shuffle() -- This is the offending line.
play_sound('cardSlide1', 0.85)
print('Whoosh!')
return true
end
}))
end
--delay(0.35)
delay(03.5)
end
'''
did you know that the actual text of the crash is probably helpful for other people to identify the issue :)
It only says "attempt to call method 'shuffle' (a nil value)". But how can shuffle() be nil?!
oh because you can't call shuffle on any table, it's specifically on a whole cardarea
you have to do it on G.hand, not G.hand.highlighted
press windows+shift+s, hold in the top corner of your screen and drag to the opposite bottom corner, press ctrl+v here
top tip advice for sharing your crash
I already know how Lightshot works (I've been using it for years), and I already shared the only relevant information.
I really need to get on that better crash helper
yes but in the future, it's easier on everyone if you just post a screenshot of the crash alongside the code
so we don't have to keep asking what the crash is
because the text of the crash is always relevant
there are also some common crashes that experienced people will instantly recognise
Code adapted from Death, keeping track of each card's .T.x data, but the play order still doesn't change. What do I do?
[[patches]]
[patches.pattern]
target = 'functions/state_events.lua'
match_indent = true
position = 'after'
pattern = '''
G.FUNCS.play_cards_from_highlighted = function(e)
'''
payload = '''
-- This is utilized by The Gale.
if (G.GAME.blind.config.blind.key == 'bl_lapsems_gale') and not G.GAME.blind.disabled and (#G.hand.highlighted > 1) then
G.GAME.blind.triggered = true
G.GAME.blind:wiggle()
local LAPSEMS_selected_cards = {}
for i = 1, #G.hand.cards do
if G.hand.cards[i].highlighted then
LAPSEMS_selected_cards[#LAPSEMS_selected_cards + 1] = i
end
end
for i = 1, 3 do
G.E_MANAGER:add_event(Event({
func = function()
delay(0.15)
for j = #LAPSEMS_selected_cards, 2, -1 do
copied_LAPSEMS_selected_cards = copy_table(LAPSEMS_selected_cards)
local k = table.remove(copied_LAPSEMS_selected_cards, j)
local l = pseudorandom_element(copied_LAPSEMS_selected_cards, 'bl_lapsems_gale')
G.hand.cards[k], G.hand.cards[l],
G.hand.cards[k].T.x, G.hand.cards[l].T.x
=
G.hand.cards[l], G.hand.cards[k],
G.hand.cards[l].T.x, G.hand.cards[k].T.x
end
play_sound('cardSlide1', 0.85)
print('Whoosh!')
return true
end
}))
end
delay(0.35)
end
'''
It's adapted from what the Death Tarot card uses to determine which selected card is the leftmost in hand, if that's any clarification.
what makes certain consumables show up rarer? is it just having a soul_set or having hidden be true?
calculate = function(self, blind, context)
if context.debuff_hand and not context.check then
pseudoshuffle(context.full_hand, "seed")
end
end
does this work for you
soul_set requires hidden
but having both automatically makes it rarer, right?
It worked exactly, and now I feel like a buffoon for trying and failing with far more complex attempts.
How would I set G.GAME variables when a game starts? I don't want it to be reset like Mail and Castle. I might just be overlooking something
the way it's implemented means just thinking about it as making the card rarer is technically wrong
if you set soul_rate to 1, then every card of that consumable type becomes the "hidden" card you're setting up
if you don't want it to be treated like soul/black hole/etc, and just be a regular consumable, consider just making in_pool only return true like 50% of the time or whatever (depending on how rare you want to make it)
that reset function has a start of the game argument you can check
okay, where would i find that function at?
check mail or castle in vremade lol
Ok, I wasn't understanding how it works exactly, but I think I got it now
Thank you!
would it be considered malware if i opened a site
am i required to do math to change the pixel size of a joker?? i cant just like, set it to a different number??
do you think 95/1.2 is not a number
no i mean why is it like
why not use the actual printed pixel size of the joker
why make it a division
is it that hard to say like. 50 or smth
it is a lot more clear when it's the base size modified by another number
it would be better if they weren't magic numbers but i didnt feel like changing that
if it is like that it's easier to change the size by just modifying the second number
this kinda feels less clear because i was under the impression i needed to do this
what about the actual pixel size and then a comment appended to it like "base is 95"
if you don't know the dividion operation returns a number maybe
i know it returns a number, this makes me think it's gonna read wrong if i DONT do it EXACTLY like this
whatever
im sorry this is very basic programming
so h is height and w is width
yes
then dont get mad at me 😭
youre making fun of me!
idk i dont like when people talk about what i did with dismissiveness when they don't know what they're talking about
look im aware how division and basic programming works, my brain is so melted in all these different weird ways that smods and balatro work and referencing everything that it didnt cross my mind i didnt need to do it. im sorry
like given everything it fully would have made sense in my head to have had to manually calculate the pixel size of a joker from base size because of some bullshit with, card back scaling or whatever. im not thinking clearly and im just generally pissed off
how do i hook into a function in card, do i just dont?
Is there anything like update_blind_amounts() that can instead update any changes to a Blind's appearance and boss_colour?
So when making art for the jokers and stuff, are you supposed to draw the 1X version and then scale it up, or draw the 2X version and then scale it down?
I see the Aseprite balatro extension has a tool for 1X -> 2X scaling, so it makes me think you need to draw 1X first
Haha thanks
a function hook is universal, you want to hook the function and then check if you have the card inside the hook
is there any efficient way to get a blueprint_effect to return twice?
this is what we have but, as you can see from the comment it doesnt exactly work
return SMODS.merge_effects{ ret, ret2 }
you want to call blueprint_effect twice even if it is a single card because there might be other effects aside from the return
epic, thank you
im assuming i cant return ret, ret this way? has to be two separate locals?
your past answer helped someone in the future.
absolute hero
(no reply ping, so you might not even see this lol)
Yes, if you want jokers that roll probabilities to roll twice.
if you return ret, ret then something like space joker is rolled once instead of twice and triggers twice if successful
there's an aseprite extension for balatro spriting? 
Seems useful
ty
Is there any function that can be run to update a Boss Blind's appearance and boss_colour? This thing's functionality is already completed, but I want it to turn verdigris-colored if it picks Chips and orange if it picks Mult.
Any takers?
By my own testing, I ran eval G.GAME.blind.config.blind.boss_colour = HEX('FFAA00'), but the color wouldn't update to bright orange until I headed to the main menu then back into the game.
Maybe you could run the blind's draw function again or something like that? Though it might just spawn a second one, not sure
Speaking out of my ass here lol
Draw function? How do I access that?
just Blind:draw() maybe? dunno
[E] < Error: blind.lua:467: attempt to index field 'states' (a nil value)```
Well I have no idea what I'm talking about so fair enough lol
Gee, where?
blind.lua
[I] > eval Blind:change_colour(HEX('A00AA'))
ourple...
Since it's a Showdown Blind I'm working with, changing the background color isn't so necessary, but I'd still like to know how to do it. Any ideas?
uhh i think the booster packs in vanilla remade use the function to change it
[I] > eval ease_background_colour_blind(HEX('FF0000'))
very nice
Nah, I'm back to where I started!
And after this gets sorted out there's still the question of: how do I change the Blind button's appearance, too?
Try ease_background_color{new_colour = G.C.RED}
Ta-daaaaa!
Nice!
Lol I'm impressed with myself for somewhat being able to read Balatro's code now
this one didnt work because A00AA isnt a valid colour
I meant to type AA00AA, sorry.
And now, I can use this as much as I darn well please! ⭐
LAPSEMS.change_blind_color = function(new_color)
Blind:change_colour(new_color) -- Blind box
ease_background_color{new_colour = new_color} -- Background
end
Awesome :)
got this long error trying to load a custom deck
dawg i might have to crossmod just to take this for myself
oh lordy lord the curse of talisman
Crossmod? You can just copy the function code yourself. Just make sure to credit me.
talismans "big numbers" cannot be directly compared with normal numbers
Code?
oh god do some mods just. break with talisman
you need to_big
jokerforge 😔
for every single comparison
of two numbers
or it explodes when it compares a bignum and a normal num
Might this do the trick?
--[[
Cribbed from Minty's Silly Little Mod, apparently for compatibility with Talisman.
--]]
to_big = to_big or function(x)
return x
end
to_number = to_number or function(x)
return x
end
Alternatively use Amulet instead of Talisman, which fixes this
its not about that though
So you don't need to use to_big() on every single number in your code
just adding that does nothing
ok this joker looked worse than i thought
it just makes the required checks not crash if you dont have talisman
THANK. YOU. FOR. THIS.
surprisingly, the balatro font has support for a wide range of symbols/letters
look at the languages section
most of them have support
ooo
ew
You're. Welcome! Also, I've seen your messages in this channel before; may I know the nature of the mod you're making?
ACCIDENTALLY MADE IT SO THAT IT WAS +X1.5 EACH, WOOPS
Lol nice
theres no specific theme, just anything i feel like coding.
moved to working on the mod fulltime because roblox went up in flames.
Mine started out as an ordinary small-in-scope mod, but now it's got more Blinds than some other mods have Jokers.
And more still that're cross-mod Blinds; there're three for Minty's Slly Little Mod.
yeah.
X23.5 on each
im playing a run through my own unfinished mod to find all of the early bugs
Alright here's a funny one
I have a joker that says a variety of funny phrases during various points of your run
And they're all stored in a table in config extra
How do I move this into the localization file without it being completely incomprehensible
Currently I just return like message = card.ability.extra[math.random(1, 10)] to get a random message from a subset of these
put a bunch of entries in misc -> dictionary in your loc file like so:
misc = {
dictionary = {
something_quote_1 = "I'm helping!",
something_quote_2 = "Yum!",
...
}
}
and then return like message = localize("something_quote_" .. math.random(1, 10))
That should work
Could I store a table in misc dictionary though? Then I could do kinda the same thing with just getting a numbered entry from the table
Or does it have to be one string per entry
it has to be one per (of course you can save anything to a table in lua but it won't work with vanilla functions)
yea the localize function won't be able to handle the table properly, which is what you use to get the strings from the localization file
I've looked all throughout blind.lua, but nothing I found looks useful for changing a Blind's appearance from one sprite to another. Anyone have any tips for me?
Yeah this works lol
Here's an unsolicited suggestion: how 'bout you split 'em up into nancy_usefuljoker_scoring_1, nancy_usefuljoker_obtained_1, and so on?
Then I'd have to rewrite the code more and I'm lazy
It already has math.random with the correct numbers, so I won't touch it
But this way, it'd be easy-peasy to add more quips in the future. Minor rewrite now saves you from a bigger headache later on, was my rationale.
That's a fair suggestion
I don't think I'll be adding more to this guy though
He's chatty enough :)
was rerolling a deck for a specific starting legendary joker
there are 2 extra legendaries in this mod (7 total)
i got stanc 3 times in a row
1 in 343 chance
WHAT
WHAT
stanc 4 times in a row and counting
I think he likes you~
the joker that i havent designed a card design for? yeah that checks out, i think my procrastination likes me too
Running eval G.GAME.blind.config.blind.pos.y = 1 doesn't change the Blind's appearance until I head to the main menu and then continue the game. What must I do to have it instantly change appearance?
what's the best way to create a stack of a card in a cardarea vertically?
@lament agate could i ~~steal ~~ borrow your config menu code
go ahead
tyyy nxkoo ur the best
i don't know how feasible that is, considering literally SMODS doesn't handle it in the case of unlocking blinds in the collection from debugplus (they don't update their sprite until you back out of the blinds menu and go back in)
SMODS.create_sprite hooking and shenaniganery
mayhaps
true but that's vaguely evil in nature
indeed
alternatively hook where blind token sprite is made
and assign it to a global
that can be accessed by an update function
with a nil check ofc
if the creation is done inline with the ui it will be annoying though
i'd have to check
you're welcome! ^^
What does that entail, "vaguely evil"?
is it possible to have a ui node inside of a cardarea?
it's quite a lot of effort for something that seems fairly simple from the user standpoint
and it involves working with code deeper in the UI and visuals systems of the game than most modders should deal with on a regular basis
how would i make a poker hand intrinsically do things
where playing the hand does something (not attached to a joker or voucher or whatever, its the hand itself that does a thing)
like some of the highest priestess shit (i tried looking but they seem to have a whole hand library system that uh. i dont really want to just rip that out wholesale that seems like way too much compared to what i actually need)
like fucked up poker hand calculate?
calculate? no i mean do things when it is played
not in terms of what counts as the hand
it was metaphorical referring to the joker calculate
anyway
global mod calculate
it can just check for the hand and do whatever
-# now if this is about cold beans
-# please for the love of god
-# use the function
I just made a whole mod that does that lol, here:
https://github.com/Noah-Bunis/BalatroMahjong/blob/v1.0.1/items/round_eval.lua
everything rn cycles back to this round eval adding tags based on checking the hand
"bm_TwicePureDoubleChi", "bm_OutsideHand", "bm_PureStraight", "bm_HalfFlush", "bm_FullFlush",
"bm_ThirteenOrphans", "bm_Tsuiisou", "bm_LittleFourWinds", "bm_BigFourWinds", "bm_Junchan"}
SMODS.current_mod.calculate = function(self, context)
if context.before then
for i = 1, #yaku do
if next(context.poker_hands[yaku[i]]) then
G.E_MANAGER:add_event(Event({
func = function()
add_tag(Tag(("tag_" .. yaku[i])))
play_sound('generic1', 0.9 + math.random() * 0.1, 0.8)
play_sound('holo1', 1.2 + math.random() * 0.1, 0.4)
return true
end
}))
end
end
end
end```
Setting aside the desire for changing Copper Colossus' image, @frosty rampart, might you instead know how to put tooltips onto Boss Blinds as seen in the collection screen, like with card-enhancing Tarot cards? Going with the classic info_queue method in collection_loc_vars() didn't do it for me.
as far as i'm aware it takes custom ui coding. aikoyori's shenanigans does it but it involves basically just manually recreating how the infoqueue system works so that it can be applied to blinds
Sounds like it'd be more trouble than it'd be worth for me. But it'd be cool if Steamodded did that by default.
You think a booster pack called temu full of bootleg versions of rare jokers would be a fun idea
lmao thats hilarious actually
Had an idea for blueprint where it fails half the time
And likely hood of perishing
But they are dirt cheap
#⚙・modding-support message help requested :<
i think thats a thing in yahi mod maybe
Is it?
yea
yeah i was playing with a few mods and i saw a similar idea
I know the cryptid mod has like a blueprint that has 1/2 chance of working
Is it just blueprint or all rare jokers
I know spaceman isn't a rare but was gonna make it where had a 1/4 chance to upgrade a random hand instead of the played one
ive also seen something like that somewhere
its kinda hard to come up with unique joker ideas
yeah
Broken jokers
youd have to keep them all common rarity. but make them spoofs of rare and legendary jokers
The spaghetti code I made to get this to work tho
Still not sure if this is a good concept for a joker
nah its fun
Because feeding it Michel seems better than hunting for cavidish for extra
eh its intresting and unique
I might look into the temu idea tho
how would i detect if the anti contains a showdown blind? (and possibly see what blind that is, i know how to check the blind config and it's key)
Is there a good way to make or learn shaders for a beginner
use the vanilla shaders as reference
wel I kinda wanna makea shader effect for a custom joker edition
for temu jokers I wanna give off that holo stank from bootleg tcg cards u get off temu and other chinese seller websites
what's the area for spectrals/tarots
how do i get if a card's in the collection area
G.TAROT?
trying to send a link for u but
my pc's clipboard has been acting up recently
here
G.consumeables
How would I get consumable sell cost
was coincidentally looking at it already bc i'm trying to do this and it's not a listed cardarea??
On smods wiki there are linked some books and shader examples with explanations
Card.sell_cost
Doesn't work
weird
yw
local card = create_card('consumables', G.consumeables, nil, nil, nil, nil, 'ttv_thefakesoul')
is this correct or am I missing something
I get a center nil value error
if card.area.config.collection
ty
SMODS.add_card({key = 'c_modprefix_key'})
still getting local center nil value
Code?
if is_on_cooldown() then return end
if G.STAGE == G.STAGES.RUN and G.consumeables then
local card = SMODS.add_card({key = 'ttv_thefakesoul'})
card:add_to_deck()
end
end```
It would be c_ttv_thefakesoul if ttv is your mod prefix and thefakesoul is the key of the consumable.
yup that was it
now if I can figure out how to remove the twitch intergration
it would be perfect
I added no_mod_badge = true,
but didn't seem to work
So I'm guessing add_card is just a shorter create_card?
No, that would be SMODS.create_card, SMODS.add_card also emplaces and adds to deck.
local cu_hook = Card.update
function Card:update(dt, ...)
if self.area and self.area.config.collection and G.GAME.banned_keys[self.config.center_key] then
print("hook!")
self.children.center:draw_shader('debuff', nil, self.ARGS.send_to_shader)
end
cu_hook(self, dt, ...)
end```
why isn't it adding the shader
You should be using SMODS.DrawStep
ah ty
how do i debuff a pool of jokers
-# more specifically on a stake too
I made a test shader to replace the background menu with I see hwo to add the shader but how woudl I got about replacing the background it with
looking for references in the main game but can'e seem to find it
nvm I believe I found it
shader = 'background',
send = {
{name = 'time', ref_table = G.TIMERS, ref_value = 'REAL_SHADER'},
{name = 'spin_time', ref_table = G.TIMERS, ref_value = 'BACKGROUND'},
{name = 'colour_1', ref_table = G.C.BACKGROUND, ref_value = 'C'},
{name = 'colour_2', ref_table = G.C.BACKGROUND, ref_value = 'L'},
{name = 'colour_3', ref_table = G.C.BACKGROUND, ref_value = 'D'},
{name = 'contrast', ref_table = G.C.BACKGROUND, ref_value = 'contrast'},
{name = 'spin_amount', ref_table = G.ARGS.spin, ref_value = 'amount'}
}}})```
trying to use a lovely patch to change the colour values
but I can't seem to get it to work
this is supposed to check if the total amount of hand levels above 1 is greater than the number of highlighted cards, yet it always seems to be off by one and requiring 1 extra level on top. what could cause this?
wait
im stupid
nvm
I tried swaping the colour values around to doesn't seem to change anything either
I know the patch sorta works because if I cahnge the background sharder to the custom one I made it crashes the game
how do you create a tag
add_tag(Tag('key'))
thx
that took me 20 seconds to find through vanillaremade
I entirely forgot about vanillaremade okay
im trying to make a joker unlock condition and from my testing it's not unlocking
here's the bit i wrote last night, using_customable is a custom unlock arg type that i've just got being called anytime a consumable is used in a different file
did you try returning true instead of unlock_card
i tried both
does it enter either if condition
it should but i havent run a full debug
is there a way to tell how many times a given card has been played? i recall hearing that that was still left over from when the magnet vouchers were a thing
nvm im just making my own variable
Anyone know how mods add those little credits for people’s ideas/art on a joker?
you can also just add them as an info queue
i'm reading the SMODS api documentation but i can't seem to find info on method parameters and what they do, nor can i find information on global functions like ease_ante(), are they on that github wiki or do i have to just keep referencing vanillaremade and reverse engineer?
Most of the global functions you are thinking of are vanilla functions that are rarely documented on the smods wiki, most smods functions themselves are either buried somewhere on the wiki/in update posts, or have reasonably informative lsp definitions
anyone know why this is triggering twice
calculate = function(self,card,context)
if context.joker_main then
return {
mult = card.ability.extra.mult
}
end
if context.joker_type_destroyed and not context.blueprint then
print(inspect(context))
card.ability.extra.mult = card.ability.extra.mult - card.ability.extra.smult
local dest = card.ability.extra.mult <= 0
return {
message = dest and "Consumed!" or "Defended!",
func = dest and function() SMODS.destroy_cards(card) end,
no_destroy = dest
}
end
end```
i figure it might still be calculating when it destroys itself? (assuming you mean the joker destruction effect is triggering twice)
the print is running twice