#💻・modding-dev
1 messages · Page 388 of 1
TLDR:
functions are variables and editable
oldfunctionthing = functionthing
functionthing = function(args)
do your hook thing
return oldfunctionthing(args)
believe its xmult and not Xmult
that wasnt the error
it's Xmult
Did you define is_Ace?
It's both.
the is_Ace was pure guessing tbh
Maybe a mockup can help?
local cf = Card.func -- Save the existing function in a variable
function Card:func(x, y, z) -- Override the existing function
--do stuff before the function
cf(self, x, y, z) -- Call the original function from the save you made
--do stuff after the function
end
i dont even know that exists
There is only is_face, nothing else.
card:get_id() == 14
Can you show your full code?
why are you using . first but : the second time between card and func
: is for referencing self, but when copying a function you don't need it so you use .
so then what's my error
Remove the ,
e
ok and if i want to check for both jokers and playing cards do i need to do 2 different hooks?
Does anyone know why this doesn't show the flavour text?
id = "c_gaff_tapered",
key = "tapered",
set = "Tarot",
pos = {
x = 0, y = 0
},
loc_txt = {
name = "Tapered",
text = {
"Enhances {C:attention}#1#{} selected",
"card into a",
"{C:attention}#2#",
}
},```
For jokers there's a function called SMODS.find_card
I'm not sure if it works on playing cards
https://github.com/Steamodded/smods/wiki/Text-Styling#named-colours-dictionary-gargsloc_colours i can just tell you this
Remove the break and move the end after the returned table
When you return something it stops the function entierly so break is useless
im using the vanilla remade implementation for blueprint-style jokers and this crashes my game in the collection, which checks specifically should i use to prevent this
another thing, how do i do so it checks the entire played hand, not only the scored hand
Check for context.full_hand
ok
Careful tho it counts debuffed cards too
nah i just want it to check if there's any ace
Oh ok
really no idea if I understood it, i want a joker to gain more chips whenever anything does juice_up
Oh If I were you I'd avoid doing hooks inside a SMODS object
Do it outside the joker object
How do I add the explainer box on the left?
In your loc_vars function you can add into info_queue
For example
(don't add the "elseif if _c.name == blabla, just the info_queue part)
but then card isn't defined
or i dont need card
It's on any juice_up tho no?
yeah
Hold on I'm gonna type my idea out
You put this outside your joker object
local cju = Card.juice_up
function Card:juice_up(scale, rot_amount)
SMODS.calculate_context({modprefix_juice_up = true})
return cju(self, scale, rot_amount)
end
Then in your joker's calculate function you add
if context.modprefix_juice_up then...
Not sure if it's better to put the calculate_context before of after the original function call, it's up to you to experiment
name = "Tapered",
text = {
"Enhances {C:attention}#1#{} selected",
"card into a",
"{C:attention}#1#{} tapered card"
info_queue[#info_queue + 1] = G.P_CENTERS[card.ability.mod_conv]
}```
So, where do I add in info_queue? I want to explain what the tapered does to a card.
Not in your loc_txt, in your loc_vars function (if you got one, other make one)
Try adding return nil, true at the end of your new context?
What does key and set do within info_queue?
if anyone can find the solution to this problem then i would appreciate it alot
What do you want to reference, it might be different depending of what tooltip you wanna add
why doesn't my achievement text show up? (its just ERROR)
part of the localization file:
misc = {
achievement_descriptions = {para_deathbypineapple = 'Snack on some pineapple slices.'},
achievement_names = {para_deathbypineapple = 'Best idea you\'ve ever had!'},
Try replacing self.config.extra by card.ability.extra?
it's ach_modprefix_achievementkey
I want to reference what the enhancement does
I already tried that unfortunately
Is it a modded one or not? Which one if it's vanilla?
It's a modded one
I'm planning to make another card modifier at some point. But, for now, I just want to add it into the enhancement section
Try info_queue[#1116390750314307698_queue+1] = G.P_CENTERS.m_modprefix_enhancementkey
trying to make a new consumable type for my mod. how do i change the name of the set
same error
Does your mod have a localization file?
no
Send your thing's full code and the override
local cju = Card.juice_up
function Card:juice_up(scale, rot_amount)
SMODS.calculate_context({pvz_juice_up = true})
return cju(self, scale, rot_amount)
end
SMODS.Joker {
key = 'spring_bean',
rarity = 2,
cost = 5,
atlas = "Jokers",
pos = {x=3,y=1},
config = { extra = { chips = 0, chips_gain = 10 } },
unlocked = true,
discovered = true,
calculate = function (self, card, context)
local bean = card.ability.extra.chips
local gain = card.ability.extra.chips_gain
if context.pvz_juice_up then
bean = bean + gain
return nil, true
end
end,
on_plant_food_use = function(self,card)
end,
can_use_plantfood = function (self, card, context)
return false
end,
}
ignore the on_plant_food_use and can_use_plantfood
In your SMODS.ConsumableType thing add
loc_txt = {
name = 'Thing',
collection = 'Thing Cards',
undiscovered = {
name = 'Not Discovered',
text = {
"Purchase or use",
"this card in an",
"unseeded run to",
"learn what it does"
},
},
},
Put your local bean and gain uder context.pvz_juice_up?
that worked ty
still same error
This is fine, but I want a box on the left explaining what tapered does as an enhancement.
Oh if it still doesn't work try if context.cardarea == G.jokers and context.pvz_juice_up then
Does it not show up? Can you show Tapered's code and your enhancement code?
is there a list of all the "card.ability.extra" vars you can have?
still the same...
why isn't my achievement granting?
where it should be granting:
check_for_unlock({type = 'ach_para_deathbypineapple'})
I'm assuming I need to create an enhancement code?
Show your calculate code again?
Cause I haven't done that yet
Does your enhancement not exist?
Oh
Then yea ig
achievement code:
SMODS.Achievement{
key = 'deathbypineapple',
hidden_name = false,
hidden_text = false,
unlock_condition = function(self, args)
return true
end
}
The check_for_unlock doesn't need the "ach-modprefix-" (- are _)
Godamnit discord
Try disabling your mod optional features just to test this out?
wdym by optional features?
Does your mod have optional features for retriggers or allowing new card area?
pretty sure it doesn't
does this mean that if the 1 in 2 chance hits its 50/50 between 2.75 and 0.75 or 1 in 2 chance to hit 2.75 otherwise 0.75
if its the latter reword it
okay
I'm gonna experiment with your joker on my own
how can i make so cards are considered wild cards (they dont transform into wild cards)
sell your pc
too slow
wdym
Hook SMODS.has_enhancement
if you mean a steam achievement its not possible without breaking TOS iirc
yeah, but i want every card to be considered a wild card, even though they arent
no in balatro itself
its a modded achievement
make a new profile and do it there lol
this is the desc
Yes, I'm aware if you want things to think that a card is wild you need to hook SMODS.has_enhancement
gl
that doesn't work
@slow brook Try replacing the juice_up hook by this
local cju = Card.juice_up
function Card:juice_up(scale, rot_amount)
if G.jokers and G.jokers.cards then
SMODS.calculate_context({pvz_juice_up = true})
end
cju(self, scale, rot_amount)
end
ok no idea 😭 how do i do it?
is this better?
lol i love the image
Try adding unlocked = false to it?
yeah thats better
1 in 3 (as they're 3 slots)
do a coinflip, heads = you buff it even more, tails = you nerf it
Made something that may be helpful to some people 
these are like minecraft's extended tooltips
if anyone has anything theyd like for it, lemme know
(please im terrible with ideas)
that doesnt sound as fun
im gonna try the joker with blueprint + mime
You could hook is_suit and then do next(SMODS.find_card('j_yourjoker`) and return true or something
Tho some jokers do trigger on wild card enhancement..
how do i hook 😭
i think
im gonna
just give it a diff use
can i give myself vouchers with debug+?
what use do i give to a crayon card
This is how you hook
(this card)
I mean it doesn't crash, but also doesn't add anything in calculate
yes but you need to buy them in a shop
remove the context.cardarea check
i love this idea tbh
how
how do i do so when i select a blind the joker deletes the leftmost consumable?
do /eval dp.hovered:redeem()
do Xchips exist in the base game or do i have to custom code that
SMODS adds it
nice
still doesn't, at end of scoring it gives +0
@daring fern use your words
No?
Ooh I get it
worked for me
You're modifying the local value, not the card value
thats extra, just be in the shop and spawn the voucher the same way you do a joker
Try card.ability.extra.chips = card.ability.extra.chips + card.ability.extra.chip_gain
there's no way i forgor that
how do i do so when i select a blind the joker deletes the leftmost consumable?
the / is to open the menu
if you are in shop and spawn a voucher the same way you do a joker it puts it in the shop for you
then just give yourself the 10 bucks to buy it
how do i use that exactly
its not the same as just typing chips instead of mult like i thought itd be
if context.setting_blind then
if G.consumeables.cards and G.consumeables.cards[1] then
local first_cons = G.consumeables.cards[1]
end
end
xchips, not Xchips
holy shit, i found the best joker naturally
x_chips and xchips work but Xchips doesn't
Actually all of those work
read it again
This is so stupid Xmult works fine why didn't they add this case 😭
pretty sure anything with _mod doesnt throw up the vanilla message right?
dunno lol
You don't need the _mod with SMODS
k ty
cause it wasnt before i removed _mod
Yea avoid using _mod values
as it turns out, juice up is everywhere...
Eyup
how can I add a for loop for each seal or card with seal randomize the seal value?
wont work :(
xchips aint working
can i somehow only count juice ups with e.g 0.4 or higher scale?
loc_vars = function(self,info_queue,card)
return {vars = {card.ability.extra.Xchips, card.ability.extra.chips}}
end,
calculate = function(self,card,context)
if context.joker_main then
return {
card = card,
chips = card.ability.extra.chips,
Xchips = card.ability.extra.Xchips,
}
end
end
}
why aint the xchip
did i forget to change it
im going insane
i changed it in the wrong place
shouldn't it be Xchips_mod = card.ability.extra.Xchips
multiple things work
You could add params in your SMODS.calc_context to get those and do if context.rot_amount then
Isn't enhancement in preview hand already possible?
yeah i pr'd that
o
i mean the styling
so it doesnt say {C:attention}text
That's cool
don't think I understood a single word here
how can i make a scaling card?
what is the hard part
you dont know what a moon is
Example with Spare Trousers https://github.com/nh6574/VanillaRemade/blob/301c21c024837870f603852538edceecbffd189d/src/jokers.lua#L2879
Moons aren't real!!!!!!!!!!!!!!!!!!!!!!!!!
more like zebra grass with moon and hanafuda and chrysanthemum and that touhou girl on the card
Can't believe you had to actually do that
btw your code didn't eat the consumable, can you please fix it? 🥺
That was just to give you the first consumable
the hell is a zebra grass
Grass with zebra colors
does :destroy() exist?
no
dunno if i misunderstood it but it crashes now
Check how ceremonial dagger does it https://github.com/nh6574/VanillaRemade/blob/301c21c024837870f603852538edceecbffd189d/src/jokers.lua#L459
What's the crash
um didnt understand much
Check if context.scale exists before comparing it
Not every juice_up has set param iirc
Just do first_consus:start_dissolve({ HEX("57ecab") }, nil, 1.6)
ok
Does anyone have a font for the legendary jokers?
how do i make it give the chips it got right now? cuz now it gets it's chips increased but adds +0 and only after the hand it has e.g. +100
Show your calculate code again
tried to change it from joker_main to final_scoring_step but it didn't change anything
Maybe remove the return nil, true
funny u'd ask, I just asked myself a little while ago in fan-art, hehehe
#🎨・fan-art message
still not
I think the chips of your joker is fetched before the juice_ups
So yea not much you can do
yeah probably (whatever fetched means)
The addition of chips*
how do i make a consumable have a message where it is and not on the corner of the screen
the shader applies, but the "shine" present on edition cards (and the cryptid edition decks) doesn't
is cryptid using a different rendering on the edition decks? they sway and tilt when you hover over them, which isn't something that backs normally do
You need to apply that aswell.
how would i go about that?
There is no G.GAME for mult
It's just mult
where can i find a documentation about attention_text for consumables
That's the current scored chips of the blind.
is the chips just chips
What am I doing wrong here that it doesn't destroy cards?
calculate = function(self, card, context)
if context.before then
for k, v in ipairs(context.scoring_hand) do
if v.seal or v.edition or next(SMODS.get_enhancements(v)) then
G.playing_card = (G.playing_card and G.playing_card + 1) or 1
local copy_card = copy_card(v, nil, nil, G.playing_card)
copy_card:add_to_deck()
G.deck.config.card_limit = G.deck.config.card_limit + 1
table.insert(G.playing_cards, copy_card)
G.hand:emplace(copy_card)
copy_card.states.visible = nil
G.E_MANAGER:add_event(Event({
func = function()
copy_card:start_materialize()
return true
end
}))
if context.destroy_card and context.cardarea == G.play then
return {
message = localize('k_copied_ex'),
colour = G.C.CHIPS,
func = function()
G.E_MANAGER:add_event(Event({
func = function()
SMODS.calculate_context({ playing_card_added = true, cards = { copy_card } })
return true
end
}))
end,
remove = true
}
end
end
end
end
end
whats the var for the chips i need then
hand_chips?
what in the non conforming variable naming in this
Do the same thing but apply negative_shine
so we have G.GAME.chips, hand_chips, mult
two of which are the same thing
and are differently named
how do i put an attention_text in the middle of the card that's generating it
No?
i get the differentiation
You didn't have to say that twice.
but making the thing for hand chips and mult the same wouldve made way more sense
I copied what wheel of fortune does but ive got idea what to change so it works
change used_tarot for card probably
it now displays it on the consumable slots
no idea tbh
consumeable makes sense if you get confused, but card should be area there
but yeah put consumeable or whatever you have in the second argument in the place of used_tarot
works now :D
what does this mean
uninstall talisman
i keep getting this after i changed a - to a +
whats the code
is it bugged or what
no that's what talisman does
you need to handle comparisons and stuff properly
no thats in the game's code
common_events line 1094
in your lovely/dump
but im not asking for that anyway, i want to see your code
loc_vars = function(self,info_queue,card)
return {vars = {card.ability.extra.Xmult, card.ability.extra.mult}}
end,
calculate = function(self,card,context)
if context.joker_main then
local change = card.ability.extra.mult
if to_big(mult+change) <= to_big(0) then
change = 1-mult
if to_big(change) > to_big(0) then
change = 0
end
end
return {
card = card,
mult = change,
Xmult = card.ability.extra.Xmult,
}
end
end
}
to_big(mult+change)
thought it was on about a main.lua
what condition would i use for my achievement such that it only triggers when you lose due to a specific joker? unlock_condition always being true grants it on startup
did that crash without the to_big?
i dont think its necessary
it didnt crash without the plus sign
thats not what i asked
negative + mult
-5 mult to be specific
and i dont want the total score going negative
so i make it go to 1 if its anywhere from 0 to 5
how would i get this achievement to trigger only when losing to the pineapple joker?
didnt think id see "death by pineapple" today
or ever
talisman probably doesnt like negative big mult
talisman handles all the compatibility minus comparisons tho right?
so mult+change would be fine
I don't think talisman ever patched the code that handles the calculation so returning a bignum will crash
anyone know the best way to change tarot values during runtime? Aka something like a joker that increases Hermit's max money
take ownership of hermit and check for the joker on creation
on creation of the joker loop through all consumables and modify the values of any hermits
negative big mult is weird i can confirm
values below -e308 just becomes -naneinf
but theres other strange things that happen
does anybody know how to trigger my achievement only at one specific time?
SMODS.Joker{ -- Pineapple implementation
key = 'pineapple',
config = { extra = {
xmult = 3
}
},
pools = { ["Food"] = true },
rarity = 1,
cost = 2,
blueprint_compat = true,
eternal_compat = false,
perishable_compat = false,
rental_compat = false,
loc_vars = function(self,info_queue,card)
return {vars = {card.ability.extra.xmult}}
end,
calculate = function(self, card, context)
if context.joker_main then
return {
xmult = card.ability.extra.xmult
}
elseif context.end_of_round then
G.STATE = G.STATES.GAME_OVER
G.STATE_COMPLETE = false
check_for_unlock({type = 'deathbypineapple'}) -- should trigger here and only here
end
end
}
-- Technically in different files. Doesn't really matter
SMODS.Achievement{
key = 'deathbypineapple',
hidden_name = false,
hidden_text = true,
bypass_all_unlocked = false,
earned = false,
unlocked = false,
reset_on_startup = true,
unlock_condition = function(self, args)
return true
end
}
alsoo im pretty sure you can return big stuff
depends what specifically youre providing a bignum too but for things like Xmult im pretty sure it works
i dont have anything that should natively return a bignum without modifications so idk how true this actually is but ive done a lot of stuff with value manipulation for things that definitely return mult and it worked fine
check_for_unlock should work here you need to test for the type in unlock_condition though
would it be possible to create a button (like the buy/use button) using a DrawStep?
args.type specifically
whats the reference to the table of jokers you have?
im gonna hope that its a G. something
G.jokers.cards?
but i havent found the docs for G. yet
ty
its being worked on https://github.com/Steamodded/Wiki/pull/30
I was thinking lines like this, but I'm not sure if ~= is handled with metatable stuff or not
for some reason it doesn't display the achievement popup (but does give the sound)
im making a Yin Yang card, and it can only spawn if you have both
i dont remember off the top of my head but im like fairly certain you can just do this comparison normally?? (metatable stuff wont kick in without luajit2 installed though) idk im bad at lua
should i make the Yin & Yang card destroy the actual cards of Yin and Yang when bought
you can atleast in lua 5.4 since i tried it just now
but idk how well that holds up
in 5.1
it will probably be janky if the big value is to_big(1) but like idk if it will crash
when do i do stuff on a joker being bought?
is it just done or is it a calculate and a context?
if context.buying_card and context.card.ability.set == "Joker"?
like the joker itself, not just any joker
add_to_deck
we are deving
is context.destroy_card for doing stuff when a card is destroyed or to destroy a card?
Bump
why doesn't my achievement pop up when it triggers?
SMODS.Joker{ -- Pineapple implementation
key = 'pineapple',
config = { extra = {
xmult = 3
}
},
pools = { ["Food"] = true },
rarity = 1,
cost = 2,
blueprint_compat = true,
eternal_compat = false,
perishable_compat = false,
rental_compat = false,
loc_vars = function(self,info_queue,card)
return {vars = {card.ability.extra.xmult}}
end,
calculate = function(self, card, context)
if context.joker_main then
return {
xmult = card.ability.extra.xmult
}
elseif context.end_of_round then
G.STATE = G.STATES.GAME_OVER
G.STATE_COMPLETE = false
check_for_unlock({type = 'deathbypineapple'}) -- should trigger here and only here
end
end
}
-- Technically in different files. Doesn't really matter
SMODS.Achievement{
key = 'deathbypineapple',
hidden_name = false,
hidden_text = true,
bypass_all_unlocked = false,
earned = false,
unlocked = false,
reset_on_startup = true,
unlock_condition = function(self, args)
return args.type == 'deathbypineapple'
end
}
you're nesting your context checks
What does this mean
which part
Something sake with the moon
Da heck are those
Damn you could hold a whole suit in your hand and fan it out with ease
bump
for i,v in G.jokers.cards do
if v.config.center.key == "Yin" then
if context.destroy_card then
return true
end
end
if v.config.center.key == "Yang" then
end
end
i got no clue here on what the syntax for destroying a card is
does anyone know where I could get all the letters/font for the legendary jokers?
They aren't all the same.
that's not it, but also you don't destroy jokers with context.destroy_card, that's for playing cards
just do v:start_dissolve()
and loops need to be written like this for i,v in ipairs(G.jokers.cards) do
...hence why they said "all the" instead of "the"
just ignoring the R there?
you could copy it pixel by pixel ig
probably not the fastest way but i dunno if theres another
it's one pixel
and its different aint it
Look at the Es in perkeo
bump
add_to_deck = function(self, card, from_debuff)
if from_debuff == false then
local hasDestroyedYin = false
local hasDestroyedYang = false
for i,v in ipairs(G.jokers.cards) do
if v.config.center.key == "j_CGN_Yin" and not hasDestroyedYin then
v:start_dissolve()
end
if v.config.center.key == "j_CGN_Yang" and not hasDestroyedYang then
v:start_dissolve()
end
end
end
end,
is this right for destroying Yin and Yang jokers when I get a joker?
does spawning it with DebugPlus not activate add_to_deck or what?
it should
from_debuff is true when it just got undebuffed, but i dont want it to blast Yin and Yang again
bump
what i mean is that i dont know if from_debuff is false when called or just nil
try if not from_debuff instead
falsy
false-y
oh
yeah i was about to test that
bump
its nil
multiboxes? i gotta use that somewhere
theyre cool i use them for my jokers
they have colour support too
is X1.5 Chips (or Mult) for a $6 uncommon fair?
unconditionally?
yea
i'd say so
and then if you find Yin & Yang, you get X2 Chips & Mult
but you need to be holding Yin and Yang in your jokers
feels a little weak for needing two other jokers
yea
what do yin and yang do individually?
X1.5
and is the x2 on top (so x3) or replaced
replaced
and its X2 Chips AND X2 Mult
so X4
unless youre using ^ jokers from other mods
x2 chips on one and x2 mult on the other or x2 chips and x2 mult on both
Yin has 1.5X chips, Yang has 1.5X mult, Yin & Yang has 2X chips & 2X mult
yes
should i make it so you also have to find Yin&Yang
or make it so you get it if you have both
definitely the latter
unconditional X4 mult becomes ass once you have to find 3 seperate jokers for it
2? its fine because thats the condition
unconditional* x3 mult is in vanilla with 2 commons anyways and a bit of probability
how do i make a joker impossible to find naturally, just inpool always returning false?
sadly it doesn't seem to show up properly without that line break there
looks cool tho
in_pool = function(self, args)
return false
end
why doesn't my achievement show up when i get it? (i still hear the sound though)
SMODS.Joker{ -- Pineapple implementation
key = 'pineapple',
config = { extra = {
xmult = 3
}
},
pools = { ["Food"] = true },
rarity = 1,
cost = 2,
blueprint_compat = true,
eternal_compat = false,
perishable_compat = false,
rental_compat = false,
loc_vars = function(self,info_queue,card)
return {vars = {card.ability.extra.xmult}}
end,
calculate = function(self, card, context)
if context.joker_main then
return {
xmult = card.ability.extra.xmult
}
elseif context.end_of_round then
G.STATE = G.STATES.GAME_OVER
G.STATE_COMPLETE = false
check_for_unlock({type = 'deathbypineapple'}) -- should trigger here and only here
end
end
}
-- Technically in different files. Doesn't really matter
SMODS.Achievement{
key = 'deathbypineapple',
hidden_name = false,
hidden_text = true,
bypass_all_unlocked = false,
earned = false,
unlocked = false,
reset_on_startup = true,
unlock_condition = function(self, args)
return args.type == 'deathbypineapple'
end
}
i do kinda hate spamming this channel with questions
but the SMODS docs arent done and are difficult to find anything in
(if it even HAS docs)
the whole point of the channel is to ask questions anyways
jokers
check SMODS.add_card in the docs :3
add_card takes the same parameters as create_card btw
should i make Yin&Yang have no edition or let it do that
inherit higher-ranked edition from yin/yang respectively
ooh thats a good idea
idk how you check which one's higher ranked though
bump
eh ill just make it random
idea for card enhancement:
Waxed Lightly Weather Cut Copper Card
1 in 2 chance to add a random enhancement to an adjacent card. If not, destroy the card
do you think you could give me an example here
cause idk what the t means
is that supposed to be a tuple or a table or what?
t is a table of values
example:
SMODS.create_card({set = "Food", area = G.pack_cards, skip_materialize = true, key_append = "does rng seeding matter that much?", stickers = {'para_negativesticker'}})
creates a random food joker with the negative sticker (note i added the negative sticker)
vanillaremade uses add_card if you need an example
add_card is prob better
is this unbalanced?
what is key_append here?
it feels unfitting to be an enhancement
rng seeding
but how do i do that
put in a string so it won't generate the same cards as other sources
eg. judgement does this so its not the same as the shop
just use any string?
the specific string doesn't matter, i could put the bee movie script if i wanted
and also it allows you to check for it in in_pool
bump
does your achievement have anything to do with ghosts
no
your achievement is clearly a ghost
why does:start_dissolve()not destroy the joker running the code for it
and how do i make it do that
wait
its not even running it
it makes a card, then when that card gets made, it should destroy the card that made the card
use SMODS.destroy_cards(card)
its a joker btw
and it worked before it was making the card
so i think it has to do with it still needing to run code
Galvanized Steel Card
+$20 while held in hand, BUT X0.9 chips
(even tho its just a bunch of ends)
use SMODS.destroy_cards(card)
this is a fun idea
maybe nerf the money a little bit
How would I make this copy the cards twice?
calculate = function(self, card, context)
if context.before then
for k, v in ipairs(context.scoring_hand) do
if v.seal or v.edition or next(SMODS.get_enhancements(v)) then
card.ability.trigger = true
G.playing_card = (G.playing_card and G.playing_card + 1) or 1
local copy_card = copy_card(v, nil, nil, G.playing_card)
copy_card:add_to_deck()
G.deck.config.card_limit = G.deck.config.card_limit + 1
table.insert(G.playing_cards, copy_card)
G.hand:emplace(copy_card)
copy_card.states.visible = nil
G.E_MANAGER:add_event(Event({
func = function()
copy_card:start_materialize()
return true
end
}))
end
end
end
if card.ability.trigger == true and context.destroy_card and context.cardarea == G.play and
(context.destroy_card.seal or context.destroy_card.edition or next(SMODS.get_enhancements(context.destroy_card))) then
return {
message = localize('k_copied_ex'),
colour = G.C.CHIPS,
func = function()
G.E_MANAGER:add_event(Event({
func = function()
SMODS.calculate_context({ playing_card_added = true, cards = { copy_card } })
return true
end
}))
end,
remove = true
}
end
end
that literally doesnt exist
or has no doc
definitely this
but it should be on the utilities page
latest release is like 3 weeks old
and its not
documentation is... lacking
it should be on a page that DOES exist
very
Latest "release" is 0509c, whilst SMODS.destroy_cards was added by 0518a.
you should update steamodded NOW
nahh
i fixed it without your silly new steamodded
just like windows, i will never update it
you dont have multiboxes in that one
bump
just run it twice
How?
bump
anyways im trying to either run a calculate function on a button/ui element press OR smods.calculate_effect (either work, I just want to display a message on a specific card (not the card with the button))
how would I go about doing that?
Cache the cards that need to be calculated and run it next frame or something?
Does anyone have mods that I can check out that have not just consumables, but their enhancements?
cause nothing happens when i run it
cryptid?
Whatever you do, don't look at cryptid for a reference.
cryptid is confusing lol
it doesn't use smods anyways
what
im so close bro i need help
put a comma on line 25 after the }
honestly id love to have an animation of the joker flying into the card used
that'd work too
(it's a harpy, and it eats playing cards for +mult)
any that is custom? So, not based on tarots or existing stuff
you mean custom consumable type?
thanks
vanillaremade has an example of how to apply enhancements with use
it has a custom consumable type but none of those custom consumables apply enhancements
this is technically a custom consumable even if it's based on the vanilla tarot
https://github.com/nh6574/VanillaRemade/blob/301c21c024837870f603852538edceecbffd189d/src/tarots.lua#L511
instead of turning them into stone cards im thinking of just debuffing them for like, 5 hands
bump
guys i came here for help, if i need to get a keypress but only once, to set a keybind, what can i use for that? i can't use keypressed because it would override the game's keypressed for escape to menu
do i add a comma at line 26 or smth
legitimately though, how do I make two copies?
you closed the quotes early
i think it's just that mult is outside the string and not a keyword
Can we see up to line 28?
i think you should provide better images
but the message implies you maybe forgot to close the config braces
ok
Comma after the position as well.
remember everything in the same level will need a comma unless it's the last element
also please install the lua extension
...why does self.ability not exist in this context? 
idk but i like your screenshots they look nice
Because you’re passing the center not the card
i see
so in this instance, it should be self.config? 
and then do card.ability?
And then add self in the function call
so i pass self into the card arg and do card.ability? 
Yes
bump
Just loop the code that does the copying?
Hey, I'm trying to attempt to mod in something that plays "invisible" by Duran Duran whenever I get the invisible joker, and that it stops when it's not in my joker pile. I'm using the following code as an example:
SMODS.Sound({
vol = 0.6,
pitch = 1,
key = "music_flush_five",
path = "aoc.ogg",
select_music_track = function()
return (G.GAME and G.GAME.blind and (G.GAME.blind.config.blind.boss and G.GAME.blind.config.blind.boss.showdown)) and 2 or false
end,
})
yes, enclose your card copying code in a loop that runs twice - then to take that into account for your card added calculate call, instead make a table that populates with those card copies as you create them in the loop and pass that as your card created table 
Is there a list of values somewhere I can get from the game?
Like the Get function
Damn, all my basic coding knowledge just leaves me when I make balatro mods, thanks!

can i ask a stupid question
Yep
is there any way i can get a sound to stop playing after the blind is finished
Can I ask a question about coding here?
Yes
SMODS.Sound({
pitch = 1,
key = "music_Duran_Duran",
path = "music_Invisible.ogg",
sync = false,
select_music_track = function()
return next(find_joker("j_invisible"))
end,
})
Would j_invisible be correct for the invisible joker?
does recalc_debuff() disable jokers or is there another function for it?
yes
but it's recommended to use next(SMODS.find_card("j_invisible")) instead
Ah thank you!
Does that just iteratively check that it's there constantly?
i think so yes
I'm not sure how the sound stuff works, but I think so
Okay, thanks!
You might want to return a number for music priority too, but dunno how that works exactly
Currently, if I have two of these jokers, only one applies eternal to the card on its right, how can I fix it?
calculate = function(self, card, context)
if G.jokers and G.jokers.cards then
local other_joker = nil
local eternal_joker = nil
for i = 1, #G.jokers.cards do
if G.jokers.cards[i] == card then
eternal_joker = G.jokers.cards[i+1]
if eternal_joker then
eternal_joker:set_eternal(true)
end
end
if G.jokers.cards[i] ~= eternal_joker then
other_joker = G.jokers.cards[i]
other_joker:set_eternal(nil)
end
end
end
end
For a custom seal, what do i need to check in the calculation function to have the effect only apply once the card scores? I'm in context.main_scoring at the moment but the effect is triggering on all cards with the seal immidately upon play
calculate runs all calculations before scoring, if you need it at animation timing then use an event or return want you need
or self, card, false
what do you want to do?
debuff a joker from another joker
where is that in the wiki?
utility functions
bump
perfect, that did it. last thing. what field am i missing to fill in that "ERROR" for the seal. theres name = Green Seal and label = Green Seal in the localization. And doesn't seem like it has an issue getting the text field
does calculate() run every frame?
as in, putting something there will assure it gets updated
Using the update function might be better for that
dt i assume is frames_to_wait?
Never used it before, Axy doesn't usually run things every frame
What are you trying to do, anyways?
how do i get hands and discards?
dt is delta time
well, update a joker's effect every frame (who could've guessed)
specifically, when moving a joker from its position
amount of frames passed since the function or game (cant remember which) booted up
Ah, so each frame you'd check if the card's position changed, then do things
That makes sense
does anyone know this
Hm... Thinking about how Axy would approach it. Maybe check the card's VT or T tables, forgot which one in a Movable object gives the desired values. It's probably described somewhere in the movable Lua.
didn't find anything conclusive xdd
sorry but i didn't understand a thing you said 😅
What do you mean? The hands left, the hands played, adding more hands, or something else?
there's a function in CardArea for moving cards between slots
but if it's moving to anywhere in the game field then good luck
do you guys like this?
Uhhh... The former table is the visual transform, the values the card takes if it's smoothly moving from one spot to another. The latter table is the actual transform, where it actually is in the code, while the visual card is smoothly moving to the desired position.
hands left
no, i meant as in moving between slots
Ouh
this is what i want to do:
the joker disables all jokers to the left of it, so i want to know where is it, when and what to disable. disabling is already kinda sorted out.
Try G.GAME.current_round.hands_left, not sure if that works tho
(for anyone searching this)
how do i find hands left G.GAME.current_round.hands_left
how do i find discards left G.GAME.current_round.discards_left
Hrm... When in the appropriate context, you could do a for loop over G.jokers.cards, then find the index of where the card is equal to your own card. Then do another loop and everything whose index is below that index can be disabled using your method.
Did it work though?
Good, now future searchers would know that too
Axy raises you one higher. https://hackage.haskell.org/package/bifunctors-5.1/docs/Data-Bifunctor-Joker.html

what
that is the idea, but like what is the context where i'll use it?!?!?!
that's why i'm thunking doing it every frame
Dunno, depends on when you want the joker to do that
After main scoring so the other cards can play once before they're debuffed, or maybe before and add a juice up to surprise users, or during main joker scoring so it could be optionally disabled by another joker
Or maybe just when added to deck, so it doesn't try to check jokers every frame
Or maybe check whenever that card changes position, and find that CardArea function someone else mentioned
ideally, whenever its joker position index changes
yeah
Then you'll want to find that function in the cardarea Lua, and hook that
Dunno what it is though, because am on phone and don't have a lovely dump downloaded
how do i check if the player is in a blind
wonderful, didn't find anything. will leave this here if somebody else knows somethiing i don't :<
if G.GAME.blind and G.GAME.blind.in_blind then
infinite handsize with juggler
Anyone know why this plays the sound once for each card? I'd like it to play only once.
calculate = function(self, card, context)
if context.joker_main then
local toDestroy = 0
for i = 1, #context.scoring_hand do
if context.scoring_hand[i]:get_id() < 9 then
toDestroy = toDestroy + 1
end
end
if toDestroy > 0 and not context.blueprint then
card.ability.extra.chips = card.ability.extra.chips + (toDestroy * card.ability.extra.chip_gain)
end
return {
chips = card.ability.extra.chips
}
end
if context.destroy_card and context.cardarea == G.play and not context.blueprint then
if context.destroy_card:get_id() < 9 then
card.ability.extra.message = true
return {
remove = true
}
end
end
if not context.after and card.ability.extra.message == true then
return {
G.E_MANAGER:add_event(Event({
func = function()
card:juice_up(0.8, 0.8)
play_sound('slice1', 0.96 + math.random() * 0.08)
card.ability.extra.message = false
return true
end
}))
}
end
end
if i remember correctly, there's a joker in Jen's Almanac that does something similar and only works on context.before for updating, so maybe what i want to do doesn't work
uhh.... yeah
i assume that might be why jen's almanac does it on context.before
sadge
although probably "draw your entire deck" is like bottom 20% of jokers in that mod. haven't played it so idk
what if the formula has no real number solutions
If both of them were imaginary, multiplying the two imaginaries might still work
Just remove the imaginary term
what is the pointer to a card's edition?
oh yea you right
oh hey you're that one friend of alb
long time no see
and what are the internal names
you were in calldontwork for a while
use -a instead of a ig
Whaaaa, you know Jeff too
Ahhh
Things went badly there due to private reasons, so uh
Does anyone have any tips on how to make all suits count as the same, i tried looking at smeared joker works but it seems to run a function dedicated towoards how smeared joker works
thing is idk what smeared_check does
all i know is that might be how the game will make clubs and spades for example be the same thing
idk what documentation to look at
within SMODS
Is there a way to check if G.jokers.cards is a specific joker?
You can look in your lovely dump and search for that function, then read what it does
probably G.jokers.cards.config.center.key = "internal id"
will take a look now
if ((card.base.suit == 'Hearts' or card.base.suit == 'Diamonds') and (suit == 'Hearts' or suit == 'Diamonds')) then
return true
elseif (card.base.suit == 'Spades' or card.base.suit == 'Clubs') and (suit == 'Spades' or suit == 'Clubs') then
return true
end
return false
end```
could I be able to put this function on a joker but have all of the suits be equal to each other within one consolidated if statement?
probably yeah
maybe change the name of the function so that it doesn't override
at that point if it makes all suits equal it doesnt even need to check, it can just return true
so like
function allsuits
return true
end
nevermind, suitless cards are a thing
you still need to check if the card has a suit
wll you'd be checking if the suit is one of the four suits, and then if the other suit is one of the four suits, and unless another mod is interfering, thats always gonna be true, so really it just turns into a stone check
i did something like this
idk if making custom functions work like this
that is at the start of my mod code
should i remove the smods part
yeah that's most likely good
yeah
i'd remove the smods but yeah that would work
At that point you can just use the SMODS util file, there's a function that checks if a card has no suit or rank, or something like that
How does this work with custom suits?
that just wouldn't tbh
Time to workshop it some more then, whee
if you want it to fully work with custom i assume
if ((card.base.suit) and (suit)) then
might work lol
just checks if there is a suit at all since you're making all of them equal
local card_is_suit_ref = Card.is_suit
function Card:is_suit(suit, bypass_debuff, flush_calc)
local ret = card_is_suit_ref(self, suit, bypass_debuff, flush_calc)
if not ret and not SMODS.has_no_suit(self) and next(SMODS.find_card("j_modprefix_key")) then
return true
end
return ret
end
actually yeah that bypasses the whole function fair enough
how do i get all currently visible hands
loop through G.GAME.hands and check which one is visible
they have a G.GAME.hands[name].visible property
why does the game crash when checking a base card's edition?!?!
how do i prevent it?
whats the crash message
and whats the code
attempt to index 'edition' (nil value)
if the joker doesnt have an edition then .edition is nil
apparently base edition cards have 'nil' edition
yeah
how do i prevent that?
add it to the check
do an if check beforehand
if joker.edition ?
if not G.jokers.cards[1].edition or not G.jokers.cards[1].edition.negative then
doesn't that return false if the card is base?
no
i want to return true
it returns true
if there is no edition or if the edition is not negative then
i'm confused wait
what do you want the condition to be?
if G.jokers.cards[1].edition and not G.jokers.cards[1].edition.negative then would be the opposite
if thats what you want
Maybe learning Karnaugh maps would help
i have never done a karnaugh map outside school
anyone worked with create_text_input() before? ive been looking at this for like 2 days and at this point i feel like i have to have overlooked something simple
True, but it helps for parsing if statements like these
so in the case of a base edition, it would be
if not nil and not false
and nil is a falsy value? is this correct
what's that
try asking @manic rune
can someone check this?:
whats the issue?
yo im makeing a mod for the first time and ive been following this vid https://www.youtube.com/watch?v=Zp-4U5TlbxY
im at the part where they show how to get the joker art to appear but its just not appearing for me, could anyone tell me why
key = 'Jokers',
path = 'Jokers.png',
px = 71,
py = 95
}
SMODS.Joker{
key = 'gamexplain',
loc_txt = {
name = 'GAMEXPLAIN',
text = {
'When a pair of Kings or jacks is in a scored hand,',
'gain a {X:mult,C:white}X#1#{} Mult'
}
},
Atlas = 'Jokers',
pos = {x = 0, y = 0}
}
-# i just got up from bed :3
bump
trying to use it as basically config modification, code is this:
palette_mod = SMODS.current_mod
function create_UIBox_palette_main_menu_settings()
local t = create_UIBox_generic_options ({ back_func = 'palette', contents = {
{n = G.UIT.C, config = { align = 'cm', id = 'palette_main_menu_settings_id' }, nodes = {
create_text_input({
w = 3, max_length = 6, prompt_text = 'Enter Hex Code', ref_table = palette_mod.config, ref_value = 'test', id = 'palette_main_menu_input',
callback = function()
sendInfoMessage("Ran")
end
})
}}
}})
return t
end```
i feel like i have to have overlooked something overly simple atp
whats the issue
thats neither of the ones I wrote lol
also the second condition throws an error so it's not really false, it just that lua shortcuts the first condition in an and so false and whatever is always false
like, is there anything wrong?
It's a tool taught in introductory logic courses, that lists out all possibilities for a set of variables, then finds the simplest way to express it using Boolean algebra (if statements). It's not actually a good idea in actual code, but it helps to learn how to read Boolean algebra in general.
atlas lowercase
its changing the value temporarily, but on restart it just resets, not sure how to get it to actually save in the smods config since usually i dont use create_text_input
so the first condition is really just try-catch
basically
i'll look into it
the second one?
it also uses text input to save configs
yes
ok thx lemme see if this works
i assume you mean this one?
https://github.com/Steamodded/examples/tree/master/Mods/KeyboardController
mhm
ill take a look now, thanks for the help :)
hi bepis
good morning
Good luck xD
good luck indeed
well it crashed again
also everyone play joyousspring i just added koi koi
Yay, joi koi
attempt to index edition (nil)
What does your code look like
^
it's just an if statement
if not G.jokers.cards[i].edition and not G.jokers.cards[i].edition.negative then
this is what N gave me
it shouldnt crash there
thats not what i gave you
i'm 15/10 confused i'm sorry
nvm
ok hold it for a second
god let me wake up first, i think my brain is half loading rn
Remove the first not in your code
do you want it to count base cards or not
i want to pass for every card, except for negative cards. what is the correct solution
sorry for being kinda slow :(
this one then #💻・modding-dev message
can someone help me in dm with my code?
thank you so much, that actually worked really well (i had been overcomplicating it a lot)
how do i get a pseudorandom value?
and is it possible to use the run seed?
it uses the run seed by default, that's the point of pseudorandom yes
is "seed" the run seed or do i leave it blank to use the run seed?
but you give it an individual seed to have different rng sources
no you need to also give it a seed of your own
it uses both
does the game not juice up debuffed cards?
btw what do you use to check if a card is a certain suit?
it should
its just like :isSuit() right?
:is_suit("Diamonds")
doesn't seem like it does
sob
to make my own probability local var (for text), would i do
update = function(self,card,dt)
card.ability.extra.baseProb = G.GAME.probabilities.normal
end
you dont need update
just return G.GAME.probabilities.normal or 1 in loc_vars
-# the or 1 is important because it can be nil
yes that will change
that oops can affect it
Hm... Still wondering what part of the Card object stores the atlas for the card itself, like the visuals for 2 of Hearts and all that. Axy wants to adjust the visuals for playing cards when scored, but not their actual values or any enchancements or similar.
wouldnt making it 1 make oops ineffective
Posted this in the modding chat, need dev thoughts: is 50/50 chance of spectral and tarots good enough?
no, its checking if G.GAME.probabilities.normal exists, if its not then it will be set as 1
actually, you might want some more nil checks
config = { extra = {
baseProb = G.GAME.probabilities.normal or 1,
overallChance = 4,
diamonds = 2,
spades = 50,
clubs = 7,
heartsChance = 2,
heartsMult = 1.5,
}
},
loc_vars = function(self,info_queue,card)
return {vars = {
card.ability.extra.baseProb,
card.ability.extra.overallChance,
card.ability.extra.diamonds,
card.ability.extra.spades,
card.ability.extra.clubs,
card.ability.extra.heartsChance,
card.ability.extra.heartsMult,
}}
end,
is this right
(G.GAME and G.GAME.probabilities and G.GAME.probabilities.normal) or 1
yes, return that in loc_vars vars
Oh, because it's in loc vars, so those objects may not exist
Am curious at which point the first two might not exist
outside of a run, checking collections there, i think
Ah
how does making custom blinds work? are there any resources (similar to this video that are easy to follow)?
i don't think the raw documentation is very easy to follow, imo
i guess i'll work with what i have
it is, you will have to get used to it :p
how do you even summon a blind for testing??
debug plus
i have it
press 3 on the blind
ok
why is my info_queue for a modded enhancement crashing the game 🥀
Why are you passing in a table
...wait, can you display a card inside a card description
yes
Omg
Bunco mod does it
use main_end
that's a way of passing an info_queue
okay using G.P_CENTERS.m_fmod_raffle_card works
Never thought of sending more than just styled text in there
the table is for specific stuff i realize, while the G.P_CENTERS method puts the description and everything it inherits
Ok, weird question. Im working on a texture pack, and while working on the consumables ive been editing Tarots.png right? I can change the Tarot and Spectral cards just fine, but for some reason it isnt changing the planet cards?
Is there some kind of lua that I have to edit SPECIFICALLY just for the planets somehow?
Because as far as I can tell, the only place the textures exist in the files is Tarot.png
I'm not too versed on the subject of texture packs but I'd recommend looking at another texture pack mod and seeing if they have to do anything different to get planets to load
I mean I'll check, but I cant imagine there is, no other texture has needed multiple commands to divy up sections of a single file?
yo me again so i understand to get the game to check what rank the card is but how do i get it to check hat hand it is
i need it to check for a pair of jacks or kings
i want you to understand what i mean. how am i supposed to know what each of these mean? i already know self, card because i've worked with them, but what is area and how do i use it?
Ohhh, texture packs might help with Axy's idea, wonderful
Not sure if that specific function is there, but you can check the lsp_def folder in the Steamodded mod for annotations on functions. It might give a short description of each parameter, if your IDE doesn't show that already while editing.
i think self refers to the object itself
while card refers to the instance the code is running on specifically?
how broken do you think that all gems combined (Onyx Agate, Bloodstone, Rough Gem, and Arrowhead) but 1/4 chance to proc at all is?
cause it seems even right
only bloodstone and rough gem really matter
yes but +chips and +mult dont matter as much
if you have enough hand levels then eh
(which i made it do)
it needs an order to trigger in
