#💻・modding-dev
1 messages · Page 613 of 1
don't judge me i do not know lua 😭
i'd honestly recommend learning it
ok but where do i start
just get a hold on very basic things
How come this doesn't work:
[patches.pattern]
target = "cardarea.lua"
pattern = '''if self.ARGS.invisible_area_types[self.config.type] or
(self.config.type == 'hand' and ({[G.STATES.SHOP]=1, [G.STATES.TAROT_PACK]=1, [G.STATES.SPECTRAL_PACK]=1, [G.STATES.STANDARD_PACK]=1,[G.STATES.BUFFOON_PACK]=1,[G.STATES.PLANET_PACK]=1, [G.STATES.ROUND_EVAL]=1, [G.STATES.BLIND_SELECT]=1})[state]) or
(self.config.type == 'hand' and state == G.STATES.SMODS_BOOSTER_OPENED) or
(self.config.type == 'deck' and self ~= G.deck) or
(self.config.type == 'shop' and self ~= G.shop_vouchers) then'''
position = "at"
payload = ''' if self:can_draw() then'''
overwrite = true
match_indent = true```
So what context should I use to retrigger Jokers. I was using context.before, but that didnt work for specifically Jokers. Do I need to do it again for specifically context.joker_main?
What I mean is what context should I put the retrigger = true?
context.retrigger_joker_check
Okay, sure, I'll try that
is there a universal context check? like one that always checks
context.before? It checks before anything happens with your whatever
SMODS.current_mod.calculate?
is there any context for after discarding
what are you trying to do
welll its a little complicated
but i want a joker that turns your gamespeed to 8
and most of it already works
and just keep it that way?
yes
you would set it in update repeatedly
if G.GAME.normalgamespeed then
G.SETTINGS.GAMESPEED = 8
G.GAME.normalgamespeed = nil
end
if not G.GAME.normalgamespeed then
G.GAME.normalgamespeed = G.SETTINGS.GAMESPEED
end
G.SETTINGS.GAMESPEED = 8
if context.remove_from_deck then
G.GAME.normalgamespeed = 4
end
yo gang
i have it like this currently
No, remove_from_deck is a function not a context.
and the only thing that doesnt work is the remove from deck
i want to make flushes playable with one off suit card
but smeared joker is hardcoded
do i need to patch
is that not just four fingers
ahh i see
hmmm
just hook SMODS.four_fingers and return 4 if the hand is a flush
yeah it would be but question still stands
ive not used hooks b4
thats why im asking
is there any good documentation on how they function
to lock it you can repeatedly set the game speed in update on the joker
update = function(self, card, dt)
if G.GAME.normalgamespeed then
G.SETTINGS.GAMESPEED = 8
G.GAME.normalgamespeed = nil
end
if not G.GAME.normalgamespeed then
G.GAME.normalgamespeed = G.SETTINGS.GAMESPEED
end
G.SETTINGS.GAMESPEED = 8
end
so like this?
just do G.SETTINGS.GAMESPEED = 8 and keep the old game speed saving in add_to_deck
wait wdym?
why would i keep the old game speed in add_to_deck?
well because update runs every frame
and you dont need to save the old game speed every frame
yeah i get that
but why would i save the old game speed in add to deck
update = function(self, card, dt)
G.GAME.normalgamespeed = 8
remove_from_deck = function(self, card, from_debuff)
G.GAME.normalgamespeed = 4
end
wouldnt this work?
the issue i have with this currentl
is that when i put the gamespeed down
it just
goes down
wdym
well if i go into my settings
and set gamespeed to 4
it stays at 4
previously it would go back to 8 (unless you were playing a hand)
update should prevent that though
but it doesnt
im running this right now
well when i obtain the joker the gamespeed does go up (nvm it doesnt me when i lie)
calculate = function(self, card, context)
update = function(self, card, dt)
G.SETTINGS.GAMESPEED = 8
remove_from_deck = function(self, card, from_debuff)
G.SETTINGS.GAMESPEED = 4
end
if context.end_of_round and G.GAME.current_round.hands_played == 1 and context.main_eval then
card.ability.extra.Xmult = card.ability.extra.Xmult + card.ability.extra.Xmult_mod
return {
message = 'Vroom',
sound = 'YA_calcium'
}
end
if context.end_of_round and G.GAME.current_round.hands_played >= 1 and context.main_eval then
card.ability.extra.Xmult = 1
end
if context.joker_main then
return {
card = card,
Xmult = card.ability.extra.Xmult,
colour = G.C.MULT
}
end
end
end
this is what the full joker looks like right now (ignore the other stuff its for a different function)
all seperate functions should go outside of calculate
I've been trying to get this to retrigger Jokers that are eternal(I removed the eternal condition for testing), but it has never seemed to actually retrigger Jokers.
i have a joker that is supposed to unlock if you win a run without having any consumables, but i'm not sure the best way to do it.
i have something like:
check_for_unlock = function(self, args)
if args.type == 'win' and G.GAME.modname.never_held_consumable then
return true
end
end,
update = function(self, card, dt)
if G.consumeables then
if #G.consumeables.cards > 0 then
G.GAME.modname.never_held_consumable = false
end
end
end,
but it's not triggering, probably cuz update only happens when you have the joker spawned in. how do i do a global update function when you get a consumable?
hook Card:add_to_deck to check when a consumable is added
or use SMODS.current_mod.calculate and check for a consumable being added in context.card_added
something else i just realized
i wanna make a joker that changes the langauge
that should probably also go in update shouldnt it?
probably
but for where you reload localization after the change do check if the current language isnt already the language youre changing to
since idk if its a good idea to reload localization every frame unconditionally
maybe maybe
first i need to figure out how to actually change the language
ive been doing alot of digging and reading but i cannot find a single thing about how to do it outside of the main way
is there a good guide on doing hooks cuz i'm not sure the best way to format it
soo HOW do i fix it if i can
so like this?
also the syntax with : only works when creating a function as function x(...) rather than x = function(...)
the arguments have to be the same as the original function, have a look at the vanillaremade example https://github.com/nh6574/VanillaRemade/wiki#whats-a-hook (happens to be for the same function but rules apply for all functions)
i've formatted it like the example, but vsc is still yelling at me
yeah the syntax with : only works if you do function Card:add_to_deck(...) and not if you do Card:add_to_deck = function(...)
ah okay, that's what i missed
local card_add_to_deck_ref = Card.add_to_deck
function Card:add_to_deck(self)
local ret = card_add_to_deck_ref(self)
if self.ability.set == 'Consumable' then
G.GAME.modname.never_held_consumable = false
end
return ret
end
what did i mess up this time
this happens when i buy a consumable from the shop
oh wait, it also happens when i buy jokers too
the : syntax is for skipping the self argument in the function
ah, okay
I'd recommend just doing Card.add_to_deck = function(self, e) if it's confusing with :
No, it's from_debuff not e
🤷 just took it from their screenshot
It doesn’t matter what it’s called
we know, but I'd suggest naming it the same as the original function to be consistent if for no other reason
does anyone know how to bypass the character limit on a joker? or just in general?
As far as I'm aware there is no character limit
You can just make new lines by doing [x] = "This is a description", where x is the line you want
replace the string with whatever you want
inside of your loc_txt
i have this as the name for a joker i wanna do
you want the name to be multiple lines of text?
\n is your friend
i formatted it that way thinking that would work
Yeah, use \n to make a new line
it won't, but I think \n does work, do name = "text in first line\ntext in second line"
try name = "Joker That's Been Crumpled Up, Torn Slightly, Soaked In The Lagoon And Kissed With Coral Blue\n#2 Semi Gloss Lipstick"
so like this
i wouldnt put the space before the \n
itll move the first line left a bit instead of centering it
imma load it now
This is good code, right
No, it's G.P_CENTERS.j_credit_card
thanks
are non-scoring card checkscontext.cardarea == unscored
or context.cardarea.unscored
context.cardarea == 'unscored'
ok gamers uh
ive decided to code a joker semi-manually for the first time
in the sense that i make a blank joker in jokerforge with no functions, nothing
and i do everything else manually in vscode
so far its working well, i just need help with a scoring issue
key = "wheelbarrow",
config = { extra = { mult = 8} },
loc_vars = function(self, info_queue, card)
local numerator, denominator = SMODS.get_probability_vars(card, 1, card.ability.extra.odds,
'vremade_wheelbarrow' .. G.GAME.round_resets.ante)
return { vars = { numerator, denominator }, card.ability.extra.mult }
end,
loc_txt = {
['name'] = 'Wheelbarrow',
['text'] = {
[1] = '{C:green}1 in 2{} cards get drawn face down',
[2] = 'All {C:attention}facedown{} cards give {C:red}+8{} Mult when scored'
},
['unlock'] = {
[1] = ''
}
},
pos = {
x = 6,
y = 3
},
display_size = {
w = 71 * 1,
h = 95 * 1
},
cost = 4,
rarity = 2,
blueprint_compat = true,
eternal_compat = true,
perishable_compat = true,
unlocked = true,
discovered = false,
atlas = 'CustomJokers',
pools = { ["hatchet_hatchet_jokers"] = true },
calculate = function(self, blind, context)
if context.stay_flipped and context.to_area == G.hand and
SMODS.pseudorandom_probability(blind, 'vremade_wheelbarrow', 1, 2) then
return {
stay_flipped = true
}
end
if context.individual and context.cardarea == G.play and
context.stay_flipped then
return {
mult = card.ability.extra.s_mult
}
end
end,
}
the idea is that cards that are flipped give +8 when scored
Is it possible for a suit to naturally count as two other suits? I wanna make a suit that acts like a smeared joker card (without smeared joker, of course)
how so?#
Hook Card:is_suit
however, its not doing that
its not giving da extra mult 😔
at least it runs without any crashes LMAO
context.stay_flipped is only used when checking if a card should be drawn face down, so that doesnt run alongside context.individual
i see, so how do i make it so that when a card is flipped, it sends out some sort of variable that the joker can recognise and provide +8 mult ? if that makes sense
also i just realised loc_vars literally means "local variables" LMAOOOOO
What do you mean “card is flipped”
you should set a flag on all the cards that were face down in context.press_play (since the cards get flipped up before scoring), check if the card has that flag in context.individual, and then reset the flags in context.after
its called "wheelbarrow" bc its meant to be sorta like the wheel but as a joker kind of
okay, ill try that
uhh
i dont know how to set a flag,,
arent flags the g.game thing
not specifically
oh
A flag here is jargon for a boolean or binary variable
also i cant find context.pressplay
press_play
See the wiki
boolean is anumber thing right
oke
oh wait no
its the opposite
it can only hold true or false values
yeah
Yes
so you would loop over G.play.cards, check for each card if their facing value is "back", and set a flag on the card if true
Put the flag in each relevant card’s ability table, and name the key something like PREFIX_NAME
okay hm
Can I per chance attach a custom effect for an edition other than the normal ones, as if it was calculate, since I can only infer about on_apply, on_remove and on_load
you can put a calculate on an edition
For a minute I believed that was not possible via the smods wiki
didn't fucking work
Names can be tables I think.
explain?
name = {
"Joker That's Been Crumpled Up, Torn Slightly, Soaked In The Lagoon And Kissed With Coral Blue",
"2 Semi Gloss Lipstick"
}
ok chat im gonna admit
I dont know what im doing
like at all
i dont know how to make this
SOBS
im trying to lock in and i just cant
What have you tried so far
i think its just having no idea how lua works
Have you been able to identify the face down cards
IDK HOW ANY OF THIS WORKSSSSSS
loc variables are fine and all but flags are like
so confusing
I think it's that you don't know how Balatro is coded
Take a look at the wiki page for calculation
Not all contexts exist at the same time
The way it works is that sometimes the game processes calculation, which passes some contexts to some objects
You can think of these as timings when abilities can activate
First, you want an ability that flags face down cards during a context where the press_play flag is true
if context.press_play
--INSERT FOR LOOP OVER PLAYED CARDS
end
Something like this is what you want
I fixed it
Flag is just programmer lingo
Context is Balatro lingo
i see,,
Again sometimes the (modded) game will call calculate_context with a table as argument
a joker's calculate function is called many times over the course of a single hand, and even outside of when hands are played. each time, it's called with a different set of values in context. some of them are flags, like context.press_play. some of them store more information than just true or false, like context.full_hand contains the full played hand when it's relevant to the current context that is being calculated.
This table is nicknamed context and has variables players can access
Typically one of these variables is something like key = true, which is like the name of the context
For example, press_play = true only in the "press_play" context
a loop is a programming structure that repeats itself multiple times so that you don't have to rewrite a bunch of code to do the same task on a number of things, e.g. going over the full hand being played and marking which ones are face down
oh right okay
yeah, i remember covering that in javascript ages ago
thats,,, confusing
it's a very important concept to grasp
ofc, im not disagreeing
im just trying to break it down in my head
so calculate is what a joker does
im guessing
like lusty joker calculates if a suit flag is heart then returns with extra mult
and hand_size is a flag that isnt a boolean but rather carries a specific value
The Balatro system isn't the best but it's good enough. Here, you can think of each Joker knowing what they can do and when, so a worker has to visit each Joker individually with whatever raw materials they have and ask the Joker to do their thing. Most of the time the Jokers do nothing
you're too hung up on what a "flag" is
i see
YEAH BC IT STILL DEOSNT MAKE MUCH SENSE TO ME 😭
it's just a variable
Typically you'll call these variables or properties or something else
if that helps
global or local?!?!?!
yeah i use variable often
^ used scratch as a kid
It depends
A flag is just a variable that can be accessed by any other Joker, but it is only true or false
Yes
they cant go beyond true or false
Nope
hmm
again
a "flag" is not a strictly defined thing
it's literally just a special name some people use for a boolean variable
it's very willy nilly in lua because lua variables don't do any strict sort of type checking, so you can have a variable equal to true and then you can immediately just set it to 5.3 or "Hello world!" or whatever you want
Have you played visual novels or history games
not history
games with a story
multiple-choice stories makes more sense
testg
Sorry my internet went ballistic
I want to say they make a joke about flags but I forget
Anyways, in DDLC depending on the poems you write you have scenes with different girls
In programming and visual novel player slang this is called setting a flag
Because you took a decision or made an action that set you along a specific path in the game
There’s a specific variation of this slang, “death flag”, from when you end in a route where a character dies
Maybe the character says something like “I sure love being alive and not being dead” and that’s like the game yelling at you this character is gonna die; players will call this a “death flag” I think
I don't know how DDLC is programmed but it's a didactic example in the sense that you could also imagine that instead of a boolean variable, the game has a variable with the name of a girl (or a number), and it would work essentially the same
flag = type of variable known by other jokers that can only be true/false
in ddlc the characters are more analogous to tables i think
in that characters are whole files that (ostensibly) contain various information about each characters
(this is obviously more accurately about classes in a more traditional object-oriented language, but lua is silly and quirky like that)
you've got a vague idea of where you're headed
Are you talking about the characters-as-characters or the actual code
well both tbh
that's why i said ostensibly, the actual chr files in the code just contain various spooky images/sounds/messages
but the existence or absence of the files can be considered "flags" in that the removal of the chr file denotes monika killing the relevant character
true, perhaps i went too fast
Unless you imagine a more complicated structure behind the game
my understanding is that the chr files are meant to be interpreted by the average layman as containing actual data about the characters
For example, instead of directly setting you on a path, your actions change the characters' happiness, and then the game decides your path based on which character is happiest
but we're way off topic now lol
i think the issue is that i cant find context.press_play on the wiki
so its confusing me even more
i dont even know what it does
im guessing its used for defining when a round starts
Yeah I guess it's only listed on an old commit
no
whats happening here, teaching someone what's programming is?
yeah, im very new to it
oh yea calculation documentation is. limited
but context.press_play is for calculation during the instant that the player presses the button to play a hand
this is the goal @primal robin
like when context.press_play if cards_flipped = true return ability.extra.mult
you're looking for if
you're just looking for if context.press_play
Meta explained what it is. Blind.press_play is a vanilla method (in Blind objects of course) which SMODS turned into a calculation context for modders to use
when the play hand button is pressed, a calculation is run with context.press_play set to true
It's handled by the calculate functions
by flipped you mean face down
yeas
Do you want to remove it or do you just want to make it unavailable?
For example, Cavendish isn't removed, it's just unavailable
https://www.youtube.com/watch?v=Zp-4U5TlbxY Best tutorial to get started making Jokers
STEAMODDED 1.0.0
A tutorial on how to make a modded Joker.
https://github.com/art-muncher/Example-Mod -- EXAMPLE MOD
https://github.com/Steamopollys/Steamodded -- STEAMODDED
https://github.com/WilsontheWolf/DebugPlus -- DEBUGPLUS
-----------------------------------------------------...
well i have a joker that when purchased gives one of three jokers
and i want the three jokers to not be in the normal pool
only available through that one joker
isnt this tutorial out of date
just a quick comment , some of this stuff is really outdated
some of it is still accurate
if you created these jokers, you can add an in_pool function to them that just returns false
but when i started couple months ago some of it was not up to date
So Cavendish
okay thanks
kinda but cavendish can still be in the pool
i want these to not be in the pool at all
local flipped_count = 0
for _, card in pairs(G.play.cards) do
if card.facing == "back" then
flipped_count = flipped_count + 1
end
end
if flipped_count > 0 then
return {
mult = flipped_count * card.ability.extra.mult_per_flipped
}
end
Not before Grös michel expires
Probably this?
true but mr srockw told me what i needed to know
That's where I was gonna get at
I just wanted to know if you wanted to make something like Cavendish, which this does
kinda its a little complicated tho
but for this specific question it doesnt really matter
hanging chad is j_chad right
oo, yes that could help
what does in pairs do
what is for _ 😭
its a way to make loops
_ is a name given to variables you're not gonna use
in pairs find how many are in
Cavendish is always in the Joker pool it's just there as you can see there's an in_pool function that can flag it as unavailable. You can think of Jokers like Stone Joker as functioning similarly.
Showman involves something similar in the sense it's another part of the check to see if a Joker is available, but they're always in the pool before being processed
hmm
and then for_ is the loop
You better learn basics of Lua first rather then guessing things
Do you know what a table is
true,, i normally just use jokerforge for stuffs
the knowledge i have of programming is still quite new
I see, someone provide video about what is lua and how it works
iam making a "pull request", the intial pull request works like gros michel than you get a pullrequest??? which behaves like a cavendish would and you get either merged,declined, or request changes, i got everything else working already i just wanted to know how to get merged declind and request changes out of every pool
what I told you should be enough to get those 3 jokers out of the pool completely, you can still spawn them with SMODS.add_card in the joker that's meant to create them
how do i shorten this patch, it'd be easy to make it just recognize the first line of the pattern but how would i add the two ends
yeah im pretty sure i got everything else working
oh now that i think about it
is there a universal key for food jokers?
or something i can use to identify all of them
do you need to shorten it
Not yet
@wintry solar was working on it
not really but i don't really wanna do long patches because they lead to compatibility issues
also it doesn't work with cryptid at all
you could use goto instead of wrapping everything in a condition
oh no...
goto?

-- before the code
if condition then goto skip_voucher end
-- after the code
::skip_voucher::
i mean you can make a food pool
and a lot of mods use a food pool
so it should be usable
That's scary......
doesn't this require the same amount of patching as adding the ifs and the ends separately
just steal another mod's code for it
it makes the pattern to match shorter
or rather it's less patches because you don't need to match to add the ends
but you need to match to add the goto locations, no?
yeah
the original code is left untouched but it would be an issue if another mod patched the same location in a non-goto way which is an improvement
so it'd be 4 matches in total still
goto meh
it might look as cleaner code in the dump i guess
wait you can shorten context to ctx?
yeah the argument doesn't have to be called context, so you can name it ctx if you want
oh its no big issue im just looking through food jokers because i need them for smth and i find that typo
This is how I do it (Code partially from other mods, obviously):
j_gros_michel = true,
j_ice_cream = true,
j_cavendish = true,
j_turtle_bean = true,
j_diet_cola = true,
j_popcorn = true,
j_ramen = true,
j_selzer = true,
j_egg = true,
}
-- Initialize pool of food jokers if it doesn't exist already, which may be created by other mods.
-- Any joker can add itself to this pool by adding pools = { Food = true } to its code
-- Credits to Cryptid for the idea and Paperback for this code
if not SMODS.ObjectTypes.Food then
SMODS.ObjectType {
key = 'Food',
default = 'j_joker',
cards = {},
inject = function(self)
SMODS.ObjectType.inject(self)
-- Insert base game food jokers
for k, _ in pairs(Cracker.vanilla_food) do
self:inject_card(G.P_CENTERS[k])
end
end
}
end```
btw the inject function in that code is no longer needed, you can just do cards = copy_table(Cracker.vanilla_food)
the = true part is completely unneccessary
that was cus of an old bug in steamodded
what kind of bug would make tables not be made properly if you dont do that
and then the = true part becomes necessary without the inject function cus that's the format of the cards table in object types
ah
the bug was that the cards table wasn't being loaded iirc
so like this:
j_gros_michel = true,
j_ice_cream = true,
j_cavendish = true,
j_turtle_bean = true,
j_diet_cola = true,
j_popcorn = true,
j_ramen = true,
j_selzer = true,
j_egg = true,
}
-- Initialize pool of food jokers if it doesn't exist already, which may be created by other mods.
-- Any joker can add itself to this pool by adding pools = { Food = true } to its code
-- Credits to Cryptid for the idea and Paperback for this code
if not SMODS.ObjectTypes.Food then
SMODS.ObjectType {
key = 'Food',
default = 'j_joker',
cards = copy_table(Cracker.vanilla_food)
}
end```
Blue Joker uses G.deck.cards to keep track of all cards remaining in deck -- which includes cards in hand. Is there a G.<???> thing that returns all cards except those held in hand, or must I first loop through G.deck.cards and then prune all the cards in G.hand.cards?
yep
blue joker doesnt include cards in hand though
My bad.
yea, G.deck is just your deck, there is no trickery in what cards it contains
does anyone know if there is a context specifically for leveling up a hand type/poker hand
do you want to level up a hand or know when a hand is leveled up?
i have an issue with creating Jokers, if i create a joker using a pool besides Joker (Like object type Food), it doesn't respect challenges that do "All Jokers are [Sticker]"
well actually both lol but I was looking to see if there was context that would return true if a hand was leveled up
you would need to add them manually afaik
still nothing
i dont think so, you would need to hook the level_up_hand function
i think i had a context like that patched at one point but it stopped patching correctly and it wasn't super necessary so i just removed it
what smods version are you using?
the latest
the actual version is more helpful when someone asks
1.0.0~BETA~1016c
then your code is wrong
have you tried smart_level_up_hand ? looks like level_up_hand may be legacy
elaborate please, because if that is the case, jabon might have to update the code
the smart one calls the vanilla one so you want to hook the vanilla one because it covers all cases
for leveling up a hand you can use the smods one
well I don't know what your specific code looks like, but what you were told to do is correct
...do you want to look at the code yourself?
not what im asking about
the localization area in smods wiki is right there, too.
i was looking for something in particular but i found it just looking there
ok
now i just need to know how prefixes are appended
Is add_tag(Tag('tag_' + string.lower(context.card.edition))) the most elegant way to create an edition tag according to context.card's edition or is there a better way?
its .. for concatention
also .edition is a table
and it won't work for modded editions
you probably want context.card.edition.key:gsub("e_", "tag_") instead too
i assume thats what youre going for
uhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
lmao
what
i coded a joker to crash the game when bought LOL
Oops ok
Thanks :)
and probably also check if it exists first
Like check if it has an edition?
I did that in a separate condition
check if the tag exists i mean
Can I just use Tag(context.card.edition.key:gsub("e_", "tag_")) as a condition?
wtf is there more than one jimbo? is it from pools? no. cuz there wasnt any before i added a pool i rthink
yes if a pool runs out it uses the default, which is jimbo for vanilla jokers
your pool might also use jimbo
for some reason my seal localizations don't have locvars???
i'm trying to change gold seals into Filipino Seals (inside joke, long story)
and this code works:
Other={
gold_seal = {
name = "Filipino Seal",
text = {
"Earn {C:money}$3{} when this",
"card is played",
"and scores",
},
},
},
but this doesn't, as it indexes an empty var:
Other={
gold_seal = {
name = "Filipino Seal",
text = {
"Earn {C:money}$#1#{} when this",
"card is played",
"and scores",
},
},
},
i thought seals had variables??
are you adding the loc_vars yourself?
no
ohhhhhhh
say for example if a mod changes that number is there a way to make some sort of internal if/else that gives the hardcoded value if no loc_var is present and the loc_var otherwise
it's easier in that case to just give it a loc_vars but the problem is that if another mod changes the value it will also probably change the localization
i personally wouldn't worry about it
ah ok then
Reroll cost is staying the same, did I do something wrong?
Nvm, I just set reroll_discount to -2 instead
localize({type = 'name_text', key = 'j_modprefix_key', set = 'Joker'})
thank you
why did my if statement stop if statementing
it thinks if is a context when it just isnt
unicode shenanigans my beloved
Oh hello Hyper
remove the last == true
hii
i think if you want debug help you should probably. get rid of the unicode bit for a second
hard to see
Yeah this
formatting 
me when i type random code in random places
indent yo code
it worked before so idk what happened
also what is a
a
i dont see it defined anywhere
if the goal is to crash the game then you're doing good
should be card.ability.extra.a
keep it up
now that i think about it yeah
it is
if you want to force the game to crash just do a for i = 1, math.huge or a local function x() x() end; x()
Instant stack overflow
G = nil
Or do {} > 0
basically what im tryna do since this is supposed to be a joker that makes it seem like it shouldnt exist is to make the price go haywire
blame it on talisman
anybody know why my scoring calculation crashes if i use a planet card?
show us the code
huh???
again??/
third time's the charm
they hate me
third time was not, in fact, the charm
okay i fixed the majority of the things suggested anyways what tf is happening with my if statement???
show the code above
that calculate function doesnt have a end statement
i needa change the for i loop rq
show both in the same screenshot
wait no the indents are fucked mb
you ended the calculate too early
Your message could not be delivered. This is usually because you don't share a server with the recipient or the recipient is only accepting direct messages from friends. You cant see the full list of reasons here
remove the fourth end
💥
Your message could be delivered. This is usually because you share a server with the recipient or the recipient is accepting direct messages from anyone. You can't see the full list of reasons here
They stop when discord works
okay that fixed it ty
anyhow anybody know why?
i have a color right there
am i required to define hand level ups for my parameter?
i have a very unique bug
card.ability.extra.h_size = card.ability.extra.h_size + 1
G.hand:change_size(card.ability.extra.h_size)
This joker has a way of increasing the hand_size, i want it to go up by ` everytime this happens (asin it happens twice handize goes up by 2 total) however what it does is go +1 everytime the methoc is called (so if i were to do the method twice it would go to 3 total handsize for a third time would but the total handsize at 6 etc) how do i fix this
wdym change by 1?
oh yeah also idk if this is smth i can fix or not but the game just doesnt process the unicode text properly like at all
fair
And its fucky unicode shenanigans
so i assume no it cant be fixed
okay yeah that works but how do i display it in my loc_txt?
card.ability.extra.h_size,
{C:attention}#3#{}
i previously had this display it (accurately despite the value itself being inaccurate) how do i change that?
Well you can just return card.ability.extra.h_size right
Since it increases hand size by the same amount as the actual joker config value increases by now
wdym?
this is what i did
but i dont use extra.h_size anymore
what happens when it's removed from deck
you should still scale that value for display reasons
adding a custom rank and having a card similar to baron with it. the ids for jack and 10 are 11 and 10 and I wanna sandwich this rank's id in between, how can this be done?
its telling me it cant index this line here, do i need all of this to make it not do that
surprisingly there wasnt documentation for this so i was staring at it for like, 30 minutes and now i think i understand what it does
then again i dont know anything about lua
take ownership and change it yourself
i assume thats how you do it
wdym SMODS.ability
is that meant to be accessing something on the card
if so use card.ability
oh right
I think he means like how can the code read the modded card like what would he have to place
and then is that an integer?
change everything over one
and put it as 11 or wht ever
if so you want for i=1, card.ability.extra.repeatThisManyTimes do
so i assume i have to do that for all of these too right
i did it anyways
It seems like Leon just needs it to identify the rank, changing it to a string even would work like ‘prefix_rank’
SMODS.Rank:take_ownership("[rank]",
nominal = [the right nominal]
)
you could also do this with tables
local ranks = {
[1] = {key='king', nominal=new nominal}
}
for _,v in pairs(ranks) do
SMODS.Rank:take_ownership(v.key,
nominal = v.nominal
)
end
whoops forgot to reply
^^^
i see
cut down 2 lines per rank is pretty nice
it mightnt work thats just what I think would work
Kw We’ll figure it out but will try that just in case (he and I co-develop lmao)
uh can someone just help me quick, it's smth easy and i cant be bothered looking for it
how do i get the seal thats on the card? like key
nvm found it
i tried reworking the entire list randomization and bro this has to be the most overcomplicated list ever conceived by human hands
i mean i think it makes some kinda sense
in the while loop from top to bottom
selects a number from given pool (1, 9999)
sets a (an empty list) to the generated number
tags setA (a variable to detect whether or not to display the text) to true
resets randomlist
resets a
Mods/lovely/log
card.seal = nil
can I do this from the seal
self references the card in the seal calculate function iirc
ight
Never made seals myself so I'm not 100% sure
show your code
🐴
oh
nvm
still in limbo
calculate = function(self, card, context)
if context.repetition then
return {
repetitions = card.ability.seal.extra.retriggers,
message = "Melted!",
func = function()
G.E_MANAGER:add_event(Event({
trigger = "after",
delay = 1,
func = function()
card.seal = nil
end
}))
end
}
end
end,
i tried it in different contexts
they didnt work before
but ig i can try them
oh wow wheres the documentation for
context.playing_card_end_of_round
🙏
this is what i got
key = "wheelbarrow",
config = {
extra = {
mult = 8, flippy = 0
}
},
loc_vars = function(self, info_queue, card)
local numerator, denominator = SMODS.get_probability_vars(card, 1, card.ability.extra.odds,
'vremade_wheelbarrow' .. G.GAME.round_resets.ante)
return { vars = { numerator, denominator }, card.ability.extra.mult }
end,
loc_txt = {
['name'] = 'Wheelbarrow',
['text'] = {
[1] = '{C:green}1 in 2{} cards get drawn face down',
[2] = 'All {C:attention}facedown{} cards give {C:red}+8{} Mult when scored'
},
['unlock'] = {
[1] = ''
}
},
pos = {
x = 6,
y = 3
},
display_size = {
w = 71 * 1,
h = 95 * 1
},
cost = 4,
rarity = 2,
blueprint_compat = true,
eternal_compat = true,
perishable_compat = true,
unlocked = true,
discovered = false,
atlas = 'CustomJokers',
pools = { ["hatchet_hatchet_jokers"] = true },
calculate = function(self, blind, context)
if context.stay_flipped and context.to_area == G.hand and
SMODS.pseudorandom_probability(blind, 'vremade_wheelbarrow', 1, 2) then
card.ability.extra.flippy = (card.ability.extra.flippy) + 1
return {
stay_flipped = true
}
end
if context.individual and context.cardarea == G.play then
if (card.ability.extra.flippy or 0) >= 1 then
return {
mult = card.ability.extra.mult
}
end
end
end
}```
for wheelbarrow
index global nil value error
@maiden phoenix its still happening 😭
stuck in limbo
Yea idk sorry
prob
SMODS.pseudorandom_probability(blind, 'vremade_wheelbarrow', 1, 2) then
with blind??
@viscid talon
i think
in your calculate definition replace blind with card, so it ends up like calculate = function(self, card, context)
and you have to change where you used pseudorandom_probability to use card instead of blind
Quick question, whats the context.other_card that detects the rank of the card? I want to make a joker gain chips based on the cards rank
When do you want your joker to gain chips
on trigger of the card
I have that as the overarching if statement but what would i put in place of chips_gain if I want the joker to gain based off of the cards rank?
if context.other_card:is_suit("Clubs") then card:juice_up(1,0.5) card:juice_up(1,0.5) card.ability.extra.chips = card.ability.extra.chips + card.ability.extra.chips_gain return { message = "+1", colour = G.C.CHIPS, card = card } end
I think I did the lua thing wrong
ill try that tmrw
Hmm, I'd do
if not SMODS.has_no_rank(context.other_card) then
card.ability.extra.chips = card.ability.extra.chips + context.other_card.base.nominal
end
That worked a treat thank you
I guess follow up question, how do you make a message include a variable? or I guess in this instance just a integer. I know how in other forms of code with f'{variable}' but here I'm confused
return { message = "+context.other_card.base.nominal", colour = G.C.CHIPS, card = card }
simplest way would be message = "+" .. context.other_card.base.nominal
Also just so I understand for future reference, what is .. ? and also if I were to put something after the variable would it be "+" .. context.other_card.base.nominal .. "+"?
.. is concatenation
so "a" .. "b" becomes "ab"
and "a" .. "b" .. "7" becomes "ab7"
ah gotcha I understand it now thank you
That works, a more elegant solution would perhaps be message = localize { type = 'variable', key = 'a_chips', vars = { context.other_card.base.nominal } }
Which basically gets this key from the localization table and inserts your variable
Yeah long term you always wanna use localized stuff
But if you're just testing it's fine for now
Btw is there a way to make a joker create a message when a card is scored or can it only produce a message from itself (I.E. how do I write card = card to make the message originate from the joker instead)
message_card = card inside the return table
you can change the message to appear on any card like that
It seems like when I try that the message appears on the card when it is scored but I was curious if there was a way to make the joker itself create the message when the card is scored?
it should just be that tho, what is your current code?
oh my god
I'm a moron
Thank you I had just changed the message of something that wasn't trigger so I didn't see the difference
Has anyone made answerable trivia in Balatro?
chat i know this is a rreally silly question but
i played modded ONCE and now i cant turn my achivemnts back on..,. how do i do it
OOPS
WRONG CHAT
AAAA
i havent gone thru the process of uninstallation but i presume u would need to reset the profile
that gets rid of all my progress doesnt it...
on that profile yes
swearing is fine here
as long as its not hate speech lmao
FUCK!!!!!
mood
man wtf am im gonna do
what mod were u playing lol
Hey so I want a separate pop up to indicate when the played hand is set on fire (Like what was done with the black sticker)
How do I do this for things that aren't related to things like stickers?
I have no clue im really new to modding i just wanted to say the art is super cute
Sigh I was playing mayhem
A friend made it lol
They are very talented
How do you mark them as set on fire
do u have a localization file set up?
Yup
Played hand is set on fire if it’s score exceeds the target score
I get that but are you just putting a flag on the card
Or am I misunderstanding
I just use info_queue[info_queue + 1] = blah blah blah
Oh I did misunderstand
in your localization file add a new entry in descriptions.Other.whatever_name
just like a joker whatever_name = { name = "something", text = { "line1", "line2" } }
and in your joker's loc_vars do info_queue[#info_queue + 1] = { set = "Other", key = "whatever_name" }
I managed to get the pop up showing but it's blank with the title being ERROR
g_onfire = {
name = "Hand On Fire",
text = {
"Occurs when played hand",
"scores greater than Blind",
"score"
},
},
},```
This is in the localisation under descriptions
Oh wiat
I just realised it isn't in descriptions lmfao
Ay thx!
:D
Holy shit im doing it (this probably doesn't look impressive without code)
I'm a fucking genius
To explain: this credits tab is being generated programmatically, rather than manually
Given some basic information, my loaded items have built a table of credit sections, "Concept", "Artists", and "Programmers", and based on whether or not there are tagged information on items, it sets out the columns as necessary. If I only have artist listed, it's one column, since only the Artists section is valid. With two tags, two columns. With three tags, three columns
Now that I have the sectioning and the lists of contributors working, all that remains is adding rows of names with some reasonable scaling based on the number provided
we're witnessing the ascension of a new ui wizard
Let me see if I can get my custom provided data tables working too
is there a context.other_card for enhancements? In my instance I'm looking for a way to detect if the card is a wild card
I found a work around nvm
That artists logic seems wrong, or is it supposed to automatically fill a dimension if you give it 0?
It still fills the dimension if you give it nothing. It's establishing the sections/categories to use for the credit, to which loaded items will add to the contributors table
The provided contributors here are for things not easily associated with a single item
So you can add an entry directly for a slight bit of manual control for more abstract things (at least I think it would be weirder to create my "direction" table based on putting "direction" tags on some items. Like duh I directed it, I'm the co-creator of the mod)
Not 100% certain why this second column is weirdly small
oh god ui
Not just UI. Procedural UI
I've made well enough progress today and hopefully I can finish this tomorrow!!!
All this was basically because I was sick of doing UI trees for the credits of my mods, so this automates the process
I need to do some procedural UI too (help)
do you perchance know what function(s) change the children's position/size?
like in general?
yup
(I'm trying to make a pannable container)
(so a container that doesn't align it's children but moves them when panning)
(like a map or somethin)
At a node level, it'd just be the Moveable:move_xy function I'd think
mhm mhm taking notes
also wth is up with UIBox and UIElement?! a UIBox creates a self.UIRoot which is a UIElement right? why? what for? To what end?
Idk if it serves you but there’s offset variables
Wow
might may possibly help thx
Do you want an example
sure!
Guy basically invented web's display: grid, not bad
Take a look at my Blinds with tooltips on them; I remember adjusting the horizontal offset so the tooltip wouldn’t cover the Blind selection column
aight, thx!
@latent perch here’s something to look for
👍🦐
How do you get the description of a joker
I tried card.config.center.text but it didnt work
localize{ type = "name_text", key = card.config.center.key, set = card.ability.set}
oh wait description
uhhhhh
just try that but without the type = "name_text" ig
No, it would be type = 'raw_descriptions'
What are you trying to do
+1 mult for every vowel in the description
Ewwww
Anyway, you need to use string methods on it instead
anyone know how to check if another modded joker is owned?
(i want to make a joker so that you get 10x if another specific joker is owned)
next(SMODS.find_card('j_modprefix_key'))
thanks!
@wintry solar maybe make sense for SMODS.process_loc_text return value it sets?
Like yk I can manually select it, but why not just add 1 line of code to make life a bit easier?
Like because of this missing return I need to do this
And if any changes will happen in future for this function, I'll be sad!
im tryna give x5 mult when chips and mult are (exactly) equal, this just does nothing?
calculate = function(self, card, context)
if context.joker_main then
if G.GAME.current_round.current_hand.chips == G.GAME.current_round.current_hand.mult then
return { xmult = 5 }
end
end
end,
if mult == hand_chips
that exactly or with G.GAME.current_round.current_hand prefixed?
It would be exactly that.
Ah ok
how do i make a joker retrigger itself?
if context.retrigger_joker_check and context.other_card == card then return {repetitions = 1} end
card.ability.extra.repetitions = card.ability.extra.repetitions + 1
this joker can increase the amount of times it retrigger itself, is this compatible with that?
Yes, just replace 1 with card.ability.extra.repetitions
alr thank youi\
still didn't work, should it not be in an if context.joker_main then?
calculate = function(self, card, context)
if context.joker_main then
if mult == hand_chips then
return { xmult = 5 }
end
end
end,
or is it the way I'm testing?
im using the plasma deck and then just playing a hand, but after the 'balanced' message it doesn't do anything
Are you 100% sure they are equal
^ @wintry solar
Then its the way you are testing, the balance from plasma happens after joker main
oh, then how would I test it.
or actually, can I just use context.afterinstead?
Play a level 1 High Card with a 4 and 2 Jokers.
wdym by 2 jokers?
The joker called Joker
oh
calculate = function(self, card, context)
if context.setting_blind and not context.blueprint then
G.E_MANAGER:add_event(Event{func = function()
(context.blueprint_card or card):juice_up(0.8, 0.8)
for _, j in ipairs(G.jokers.cards) do
if j ~= card and not j.getting_sliced then
local key = j.config and j.config.center and j.config.center.key
if key then
elseif key:find("selzer") then
card.ability.extra.repetitions = card.ability.extra.repetitions + 1
j.getting_sliced = true
j:start_dissolve({G.C.RED}, nil, 1.6)
end
end
end
end
return true
end})
return {
message = "His hunger grows...",
}
elseif context.joker_main then
return {
mult = card.ability.extra.mult,
chips = card.ability.extra.chips,
Xmult = card.ability.extra.Xmult,
}
else if context.retrigger_joker_check and context.other_card == card then return {repetitions = card.ability.extra.repetitions} end
end
i currently have this and idk why it isnt working (the full method has every food joker but its too long for a discord message lol)
Do you have retriggers enabled?
config = {extra = {mult = 0, chips = 0, dollars = 0, Xmult = 1, h_size = 0, price = 2, repetitions = 0 }},
return {vars = {card.ability.extra.mult, card.ability.extra.chips, card.ability.extra.h_size, card.ability.extra.dollars, card.ability.extra.Xmult, card.ability.extra.repetitions}}
this is currently all it has lol
i know it says zero but destroying the selzer does make the number go up in my loc_txt
do i need to enable this?
SMODS.current_mod.optional_features = {
retrigger_joker = true,
post_trigger = true,
quantum_enhancements = true,
cardareas = {
discard = true,
deck = true
}
}
or well
well only retrigger_joker
oh yeah @slim ferry
update = function(self, card, dt)
G.SETTINGS.GAMESPEED = 8
end,
remove_from_deck = function(self, card, from_debuff)
G.SETTINGS.GAMESPEED = 4
end
this works
but sometimes even when i dont have the joke the gamepseed just goes up
uh
try adding if card.area ~= G.shop_jokers and card.area ~= G.pack_cards to the update
so it doesnt trigger when its in the shop or in a booster
how do you add an ifstatement to something outside of calculate?
or do i do it inside of update?
inside of update got it
it still happend when i hover over it in the collection 😭\
eyah
oh
uhh
actually
you should check if card:can_calculate()
that probably works better
update = function(self, card, dt)
if card:can_calculate() then
G.SETTINGS.GAMESPEED = 8
end
so like this right?
lol
if it doesnt like that just make it G.SETTINGS.GAMESPEED ~= 8 and card:can_calculate()
that didnt work
it still does the game speed up when i hover over it sadly
well this was close
does that even exist?
yeah
also its not even over hovering just seeing it in collection
couldnt i also technically swap out remove from deck to not in deck?
update = function(self, card, dt)
if card.area ~= G.shop_jokers and card.area ~= G.pack_cards then
G.SETTINGS.GAMESPEED = 8
end
remove_from_deck = function(self, card, from_debuff)
G.SETTINGS.GAMESPEED = 4
end
end
```because this is what the full thing looks like
but couldnt i added a check on if its on in deck?
actually thats a good idea
just set like
card.ability.extra.active in add_to_deck or smth
and then check that in update
no like
keep update
just set some value on the joker in add_to_deck
and check if that value is set in update
so it only does something if the card is in your deck
ohhh so like
in add to deck i add local test = true
and then remove from deck local test = false
and then in update if local test = true then gamespeed up
well you would have to store it in card.ability since local variables dont exist outside of the function where you create them
wait wdym store it in card.ability?
do like
like this
and then check that value in update
add_to_deck = function(self, card, from_debuff)
card.ability.extra.active = true
end
```so like this?
and then set update to if card.ability.extra.active = true then game speed up?
yeah
G.GAME.selected_back
thanks
.effect.center.key
that too?
also how would you detect the first joker trigger
hi guys , i was wondering why the message didn't show , is it because "add_card" erase it ?
you shouldnt return SMODS.add_card regardless
also is the joker even triggering at all
yup is it triggering , else i wouldn't be here
nvm , found the problem
is there a way to check what number you scored??
ok so i need a way to identify the current deck in use
i mean to get the score of your hand you can just multiply hand_chips by mult
Scroll up a little
No, it's SMODS.calculate_round_score()
oh right
how does card.facing work
anyone have any idea
do you have "only show commands" turned on in the debugplus settings
okay but it doesnt seem to be set by flip()?
it should be
oh hmm it is but its not being read properly
Has anyone had any experience adding/removing keys from a joker.config.extra table dynamically during gameplay? I know config doesn't play well with tables sometimes
joker config tables should work just fine with tables in them
all that doesnt work is storing functions and gameobjects in them
ok, g2k, ty
hold on
is there a way to identify when a run has been won?
ok thanks
usually happens when you're stuck in an infinite loop, what is the code?
uh one sec
card.ability.ijhpool = {}
local random_seed = (G.GAME and G.GAME.pseudorandom.seed or "")..G.hypr.ijhpsr
for i=1,4 do
local a = 'dgfhkasdgfashf'
local fl = true
while fl or where(card.ability.ijhpool,a) do
fl = false
random_seed = random_seed..pseudoseed(random_seed)
a=pseudorandom_element(G.hypr.ijhjokers,pseudoseed(random_seed)).key
end
card.ability.ijhpool[i]=a
end
where() is defined dw
where(v,t) is a function that returns where v is in a table t, or nil if it's not in there
What is the goal?
actually wait
hold on
function where(t, thing)
if not t then return end
for k, v in ipairs(t) do
if v == thing then
return k
end
end
end
i misremembered how my own function works
or wait
Are you trying to pick 4 different jokers from a list of jokers
no that should work
kinda yea
that's what card.ability.ijhpool is
it's the keys not the joker prototypes themselves but that should work
actually lemme not clog chat
what parameters would i need for the function
none
Can you add another "friends of Jimbo" like skin to the cards if you have the textures for one made?
oh shit thanks
honestly I'm not sure, sorry
its fine
if I had to guess the problem is with the ijhmanage function
nnnope
func = function()
if not G.hypr.ijhpsr then G.hypr.ijhpsr = 0 end
G.hypr.ijhpsr = G.hypr.ijhpsr + (G.GAME and pseudoseed(G.GAME.pseudorandom.seed) or math.random())
local random_seed = (G.GAME and G.GAME.pseudorandom.seed or "")..G.hypr.ijhpsr
ijhmanage(card,pseudorandom_element(card.ability.ijhpool))
play_sound('tarot2')
card:flip()
assert(false,'Breakpoint Reached!')
return true
end
this reaches the breakpoint
how would you destroy a specific card in hand via a joker if context.individual and context.cardarea == G.play function?
sorry for all the surface level questions, im quite new to lua 😅
also is there a way to make it so that sounds don't increase in pitch with each card played?
I made a custom rank, how do i make this card identify it? (its supposed to be like a baron clone)
is there a "register all" function for assets like there is for sounds?
is there a way to quick refresh a mod in smodded?
(dont want to have to reboot every time imakea small change)
I believe someone put up a soft reset PR but it's not merged yet
👍
You wouldn't, you would use context.destroy_card
thank you
nvm i got it
thank you :)
Is there some type of method or function that can be used to influence a rarities weight in the shop including Legendaries? (Basically, I want a very low chance for legendaries to always be in the shop) I've been trying to find it on my own but can't find any documentation or messages here that helps me.
Did you do context.other_card:get_id() == SMODS.Ranks['modprefix_key'].id?
Yes, if you have other mods installed that number could be higher.
Hey! Is there some beginner documentation or templates to help with learning to mod Balatro?
Thank you!
yo would
if card.ability.extra.lines[card.ability.extra.tries][i] ~= (11 or 12 or 13 or 14) then
do what i think it would
No.
alright then ill do it the big way then
You could do if not ({11=1,12=1,13=1,14=1})[card.ability.extra.lines[card.ability.extra.tries][i]]
could you explain what thats doing please
It's checking if there isn't an index of card.ability.extra.lines[card.ability.extra.tries][i] in {11=1,12=1,13=1,14=1}
why do they all =1
how would i destroy a random card from the played hand?
It can be any truthy value but 1 is the shortest I think.
nvm i got it working like this
SMODS.destroy_cards(full_hand[math.floor(pseudorandom('sqarefrom128')*(#full_hand-0+1))+0])```
No, use pseudorandom_element
if context.destroy_card and context.cardarea == G.play and not context.blueprint then
if context.scoring_hand[pseudorandom('seed',1,#contex.scoring_hand)]
return {
remove = true
}
end
end```
No, that would destroy every played and scoring card also it's context not contex.
would it
Yes.
minor spelling mistake
oh, i didnt catch that, thanks :)
is SMODS.destroy_cards(pseudorandom_element(full_hand, pseudoseed('sqarefrom128'))) correct?