#💻・modding-dev
1 messages · Page 170 of 1
smods has example jokers that you can look at
Oh neat
....am i blind? wheres like, all the example stuff on the github 
I don't know ;-;
Thank you!

I should double check that jokers file for new calc stuff
the examples there use mult_mod 
at the very least it needs to be adjusted for new calc best practices
yeah I'll comb through it now
such as getting rid of manual card_eval_status_text and xyz_mod+message
how does the boss blind trigger its discards after a hand is sent? I used G.FUNCS.discard_cards_from_highlighted() in context.before and it just queued the discard to happen after the whole scoring process, after which the game itself bugged out and drew twice as many cards as the hand size
my code for reference
yeah context.before is far too late for that
i think there's been thoughts of providing calculation interfaces for blind functions
aw, so there's no workaround for now?
as of now you'd have to hook/patch Blind:press_play()


What do I do
Syntax error: game.lua:2723: duplicate label 'continue'
Additional Context:
Balatro Version: 1.0.1n-FULL (best guess)
Modded Version: 1.0.0~ALPHA-1304a-STEAMODDED
LÖVE Version: 11.5.0
Lovely Version: 0.7.1
Platform: Windows
Stack Traceback
===============
(3) C function 'function: 0x1cb0ce58'
(4) global C function 'require'
(5) main chunk of file 'main.lua' at line 1728
(6) global C function 'require'
(7) LÖVE function at file 'boot.lua:323' (best guess)
Local variables:
c = table: 0x1cb0d938 {identity:false, version:11.5, accelerometerjoystick:true, modules:table: 0x1cb0cd30 (more...)}
openedconsole = boolean: false
confok = boolean: true
conferr = nil
(8) global C function 'xpcall'
(9) LÖVE function at file 'boot.lua:362' (best guess)
Local variables:
result = boolean: true
(10) global C function 'xpcall'
(11) LÖVE function at file 'boot.lua:377' (best guess)
Local variables:
func = Lua function '(LÖVE Function)' (defined at line 355 of chunk [love "boot.lua"])
inerror = boolean: true
deferErrhand = Lua function '(LÖVE Function)' (defined at line 348 of chunk [love "boot.lua"])
earlyinit = Lua function '(LÖVE Function)' (defined at line 355 of chunk [love "boot.lua"])
@paper zealot
i'm not actually going to make EVERY word in the toki pona lexicon a joker
i'm just putting them here so i can remove the ones i don't think will work and leave only the ones i think will work
Oh Wow
Does anybody know how I'd code a joker to give +1 Chip?
theres an example joker in here that gives +4 Mult, I think you can easily change it to give +1 Chip https://github.com/Steamodded/examples/
Interesting
i've set my eyes on esun, lawa, lili, and suli so far
The files with the actual code don't seem to open for me
lili and suwi will have different sized cards kinda like wee joker
lili will be small and suli will be big
(because that's what they mean)
Ok I've managed to make it act like a DNA joker but for Every round, now just need to make it duplicate the card twice and make it only for face cards
if context.before then
G.playing_card = (G.playing_card and G.playing_card + 1) or 1
local _card = copy_card(context.full_hand[1], nil, nil, G.playing_card)
_card:add_to_deck()
G.deck.config.card_limit = G.deck.config.card_limit + 1
table.insert(G.playing_cards, _card)
G.hand:emplace(_card)
_card.states.visible = nil
G.E_MANAGER:add_event(Event({
func = function()
_card:start_materialize()
return true
end
}))
return {
message = localize('k_copied_ex'),
colour = G.C.CHIPS,
playing_cards_created = {true},
}
end
end```
yay!
Now I just gotta find out how to make it give a singular chip
if context.joker_main then return { chips = 1 } end
the current planned list of toki pona jokers are
pu (the one at the very beginning), esun, jaki, jan, kala, kijetesantakalu, kiwen, kon, kule, kulupu, lanpan, lawa, lili, linluwi, luka, ma, mani, meso, moli, mun, musi, namako, nanpa, nasa, pakala, pilin, seme, soweli, suli, tenpo, wawa, and weka
if you have any other ideas please let me know
i WILL accept toki pona words beyond pu and ku
It keeps crashing because of Context :(
what's your code
how do i change the player's money?
im trying to make a joker that either doubles it or loses it all
ease_dollars* I think?
ease_dollars
`SMODS.Atlas{
key = 'Jokers',
path = 'jokers.png',
px = 1207,
py = 1615
}
SMODS.Joker{
key = 'Timbo',
loc_txt ={
name = 'Timbo the Test Joker',
text = {
'{C:chips}+#1#{} Chip'
}
},
atlas = 'Jokers',
pos = {x = 0, y = 0},
rarity = 1,
config = {
extra = {
Chip = 1
}
},
calculate = function(self, card, context) return
if context.joker_main then return {chips = 1}
end
}`
I know it's not the best, this is because I'm incredibly bad at Lua
I read (most of) the docs
you can just return dollars in calculation
For context, it broke after the code to give the chip was added
you have an extra return
I see
It still broke because of an unexpected symbol near } on line 38 :(
And line 38 is the last line... with nothing near it ;-;
what are you using to edit your code?
Notepad++
It's still coded in Lua though
get a lua extension or something
it'll show you syntax errors while you write code instead of finding them when you try to run it
Well that's cool
anyways your calculate function is missing an end
you need a loc_vars function
Ah
my game keeps giving me this error when i try to load my mod yet i have an lua file that's named correctly can someone help me?
looks like you did something wrong when creating an atlas
this is what my atlas looks like
do you have a "GoldFinger.png" file in both assets/1x and assets/2x
I'm planning on making a card-copying Joker effect, can I get a bit of a rundown on what each piece of this is doing so I have a better understanding of how and what I'll want to use? (Ping when replying, I might not be looking here)
you're using notepad to write code?
Flash bang warning next time please
Yes I have both the png's in the right places the smaller one in 1x and the larger one in 2x
🔦 ‼️
It has a loc_vars now, it still says +nil :(
Yes yes everyone keeps telling me to find a code editor, I'm working on it, VisStudio doesn't like my machine though
you have nested folders
make sure your mod is at Mods/mod name/<entry file>.lua
sublime text is very simple and worlds better than notepad
visual studio or visual stuido code?
at least use something like notepad++ so you don't have it stuck in light mode
Nah I'm just a dumb ass i named my files GoldFinger.png so it would read as GoldFinger.png.png
pfft-
you still have nested folders
Is there a list of all the color options available any where (i.e. {C:inactive})?
Ok ill check that out thanks
yes, definitely make sure you are downloading VSCode and not Visual Studio. Completely different
Note to self, Notepad++ does have a dark mode, my eyes are saved
doesnt work, probably just doing something wrong
ease_dollars(0)
ah lol
although that doesn't do anything lol
if you want to set money to zero probably do ease_dollars(-G.GAME.dollars)
And you can always check what that one boss blind does that sets your money to zero on playing your most played hand
that worked
now i just need to find out how to multiply it
If you want to double it, just do ease_dollars(G.GAME.dollars). Triple it, just do ease_dollars(2 * G.GAME.dollars), etc...
perfect
waiiit knowing this makes life easier.
Okay hold on...
only thing i need now is figuring out how to make the probability in the card description update with opps all sixes
so that its accurate like all the other base game ones
and how do i set it to a specific starting value?
You multiply that value by whatever you want your starting value to be
so 2 would be 2 * G.GAME.probabilities.normal
if I want to add an image to a singular card, do I still need a card map or just a singular picture of the card (for 1x and 2x)
okay so there's no way in hell that stuffing literally just DNA's code into a different context will just work, right? I do need to modify some of this, right?
Not a fix but I can't figure out in the docs, what do I put for the key? Does it matter?
because my game doesn't crash and no errors but my image isn't in the game for my tarot card
doesnt seem to work. Ive tried all combos of quotations and parenthises and brackets and apostraphes i can think of, and it always either has it in plain text or shows nothing
im sure im just being an idiot lol
Can i see the code
did you add the files in both 1x and 2x
yes 100%
I am once again asking how to make my joker give +1 chip (it keeps displaying as +nil & doesn't do anything)
this is how i have it right now, but ive tried otehr variations too
I do in fact need to do that
You need a loc_vars function. You can't just put it in the description like that
That's a literal string
ah lol
whats the crash error
one is named THD.png, the other TarotsHD.png
I need a hanged man emote rn
Game works but noting in the collection
thats some progress!
whats the best way to go about setting up that function?

wrong one 
I think I messed up on my atlas guys, bad
There is some good information on the Steamodded Wiki page on the repo, and in the example mods
probably the x and y position
thinned down the Literally DNA, but the error doesn't really give me any information as to what needs to be adjusted since it's calling outside of my code
i know how to make the function, just not how to declare the probability
as in you dont see the black seal?
or the respective spectral card
yes
both
oh right I need to import
Is this part of my code even doing anything?
config = { extra = { Chip = 1 } },
(It then goes to the loc_vars & calculate things)
ok i think i have the loc_vars function, how do i call to it in the description?
You defined a variable accessible at card.ability.extra.Chip, with a value of 1
You can use it however you like
SMODS.Atlas{
key = 'sigma',
path = 'Tarot.png',
px = 0,
py = 0
}
local tarotCard = SMODS.Consumable({
key = "tarot_card_joker_effect",
set = 'Tarot',
atlas = 'sigma', pos = { x = 0, y = 0 },
cost = 0,
loc_txt = {
name = 'Balance',
text = { '50% chance to turn every joker polychrome', '50% chance every joker is destroyed', '(Not affected by dice)'} --Would also appreciate help on colors, couldn't find it on docs
},
unlocked = true,
discovered = true
})```
pic is my tarot (just for reference)
Interesting
why
px = 0,
py = 0
?
Does that do anything at all...? I just want +1 Chip
I was just trying to follow the docs 😅
I only have one card so I assumed that would work
is this correct?
that defines the width and height of the card, if its 0,0 it means it has no height and no width
In your description, where you want the value to be displayed, you do this:
"#x#", x = the position of the value in the loc_vars return statement vars
So if it was the first value returned, you would put #1#. If it was the third, you would put #3#
might as well try and see
ohhhh I see, thank you
game crashed when launched!
so I need to find the pixel length and height?
:D
yes sadly I havent done consumables so idk their width and height
71x95
I guessed wrong lol
thx
the same as jokers?
yeah
I thought they would have less width
Nope. But they do have more transparent pixels on the sides, so that's probably what you mean
does this mean I messed up on my card?
yeahhh probably
whats the crash error
You have to have I think 4px of transparency on either side, and one on the top and bottom
So the card is centered between transparency, if that makes sense
it works, but it doubles the second number, meaning the probability goes down instead of up
so the pic needs to be 75x99, centered?
if i put the 8x first it would be an 8 in whatever chance
plus one for double res?
No, pix is 71x95 total. But some of that space is transparent
are you sure you have a seals folder with a lua file called black_seal in it
You can reference how the base game's spritesheet is organized to get a visual
wait, why black_seal?
wait i think i figured it out
he just blanket copied the structure I linked him without taking a moment to try and udnerstand it
So like this? Plus one with doubled res for 2x?
idk why it looks fuzzy, or if its supposed to
the game launches now! But it crashes when I hover over the seal (again x3)
I think so. But it looks awfully blurry
it should look pixely, but photoshop auto-blurred and I have 0 idea on how to fix that
its probably something with loc vars, whats the error again
I know that GIMP automatically applies some anti-aliasing that you have to disable, but I'm not sure with photoshop
Im gonna re-do it in gimp and its also eaiser for pixel art
should I just remove loc vars?
no, can you paste your localization file too
Balck Seal?
No problemo
do you know of an easy template for the tarot I can find, or how would I get it?
the whole thing if possible
Tbh I'm just waiting for the other issues to be dealt with so I can ask about mine
You can extract the Balatro.exe and find it in the assets folder
It gives a card map
Isn't that what you are looking for?
other should be inside descriptions
yeahh, but I only need one card so do I crop, edit just one and delete the rest, i'm really not sure about this part
YOOO no way
it works now
holy moly
finally
That's probably how you're gonna have to do it, since it's the only way they are stored in the base game
Now, how do I import spectral card?
which one of the ones I listed? Edit one and delete the rest?
You'd probably be fine either way, but personally editing and just deleting the rest sounds safer so the lineup is preserved
alright
can anyone help me here?
im doing a bunch of random checks separately
but for some reason they dont ever return more than on positive
only one check at most succeds every time
a function can only return once
typo in consumables in your load_file
should i have every check check a variable and then return everything at once?
you could accumulate effects
instead of returning on each check
modify a local variable that is returned at the end
thank uu
Where can I find info on that?
I just assumed
it's in the vanilla localization file
Ive got this error now:
Can someone explain where I should pay my attention to understand what causes error while reading this report?
this is correct, right?
Howdy, new here! Just was wanting to ask if anyone has good resources to look at as far as adding a new booster pack. I can add consumable types easy but the part I haven't figured out yet is adding the new packs haha
Also very happy to go over any docs, rn just crawling through source code to piece things together one at a time
If you haven't checked the SMODS wiki, it provides a lot of the information that you would need
it's on the repo
is there a function or something that lets me manually trigger/score a specific card?
My Joker (Uncommon, $6)
This Joker gains +? Mult every 7 [7] cards played and scored
(Currently +0 Mult)
I'm designing this Joker, do you guys think it should be +1 or +2 Mult per 7 scored cards? It's Uncommon so I don't want it to be too OP
ty!
this is perfect
i'm reading through the documentation for sound effects on the SMODS repo, but i don't quite get it — i have a sound called fling.ogg in assets/sounds, how would i play it?
play_sound('prefix_key', pitch, volume)
Can you elaborate on how you'd want to implement this? I have ideas but it definitely depends on the use case, like if you're triggering/scoring something in hand vs. scored or whatever
I am realizing that was a little vague, yeah, basically I want to be able to make a certain card in your hand score (alongside its enhancement), even if it wasn't played
have you given the atlas a key?
but why my seal uses the name of the file as atlas then?
(and it works)
actual key for atlas here is 'enhancer'
that's odd? it shouldn't, I don't think
you've tested it in game and it appears correctly?
it appears as nebula deck
but it no longer crashes
but this one cuases a crash
Oh nvm!
that fixed it
thanks
what does this error mean?
i know there's a way to check if a hand was played the current round, but is there a way to check if a hand was played before in the current ante?
it means it can't find one or both scales of the image
or that they're different aspect ratios
oh. ohhhhhh thanks, my 2X was still called Phanta =w=
I guess it just depends on the conditions then, you definitely can get info on a card in hand to score it, reminds me of things like Baron that have held in hand abilities and scan through your hand after scoring happens
Actually I was just messing around with some mod that has a similar joker to this haha I can dig through the code and see how that one works
okay got a new one!
that's not built in not you could make it happen with a couple hooks
are you prefixes all correct where you're using the atlas?
can i see the code rq
suresure! i'm not sure i ever used the prefix...?
oh well there was one use in the sound name
you didn't update the atlas key in the joker
teh atlas should be the key in your smods.atlas
oh. whoops. =w=
for atlas =
us when copy paste:
more silly mistakes with GhostSalt :P
i suspect this error's happening because i haven't registered my sound yet, how do i go about doing that?
anyone that can help me figure this out? I wanna make a joker that triggers when the played hand is played for the first time that ante
What should I add to vars for this part of code?
Anyone know how lovely works? Like how it patches the actual game?
https://github.com/ethangreen-dev/lovely-injector?tab=readme-ov-file#patches here's the documentation
(bump)
thanks
not in vanilla I think
I know this is a bit of an odd thing to do in the first place, but i'm having issues with this joker effect? do I need to do more to correctly upgrade a poker hand?
because currently, this code does this
doesn't display hand names when upgrading them, and sometimes shows negative numbers? the outcome is correct but the display is completely messed up
you need to manually change the text
So in my attempts to use modified DNA code (completely unsuccessful atm), my current iteration:
if context.playing_card_added then
G.playing_card = (G.playing_card and G.playing_card + 1) or 1
local _card = copy_card(card, nil, nil, G.playing_card)
_card:add_to_deck()
G.deck.config.card_limit = G.deck.config.card_limit + 1
table.insert(G.playing_cards, _card)
G.deck:emplace(_card)
_card.states.visible = nil
return {
message = localize('k_copied_ex'),
colour = G.C.CHIPS,
card = self,
playing_cards_created = {true}
}
end
end```
produces a stack overflow, and I've determined I need to do something with `copy_card(*card*`, because changing that changes the error.
But what should I change it to?
You're creating a card whenever you create a card
yes
That's your problem
riiiight, it needs to have some sort of stop on it
Is it possible to edit the config field of a deck during a game? Specifically, I'd like to have a deck that gains a joker slot after defeating each boss blind, but I can't find a mod doing something like that
okay, now there's a new one
How do people get into modding, is there any documentation?
the problem is the card = self in the return
self is not a card
You can read the source code and also the Steamodded wiki and other mods’ source code
https://github.com/Steamodded/smods/wiki is a good starting point
Thanks
I mean Negative Jokers do it, right?
removing that made the Copied pop-up, pop-up, didn't make the copy action actually happen though
It does in a way yeah, but what I'm making is more of an art showcase than a playable mod, so I'd rather not deal with the negative visual if that makes sense
yeah that was not going to fix your previous code not working, just the crash
right
I could always just set the deck to have a ton of slots to begin with, but if there's a way to increase the joker slots that would be best
I found plenty of mods with stuff happening after boss blind defeated
it's local _card = copy_card(*card*, nil, nil, G.playing_card) for sure at this point I just need to figure out what I'm putting in that slot
if you're not planning to make it playable you should use debugplus and you can execute lua code mid game
you're copying the joker being calculated
and trying to make it into a playing card
I figured
ah okay that was a bad explanation, it's gonna be presented as a video of it being played, so I more meant that it didn't need to be balanced or anything like that
you can alwyas change the amount of slots by increasing G.jokers.config.card_limit
works for any card area
I didn’t say to use Negative Editions, just the effect
I'm struggling to figure out how to change it to be the card that is being added per the context.playing_card_added activation
Also Antimatter Voucher does it too
oh... this might be perfect
they're in context.card apparently
so, should be saying context.card instead of just card?
apparently not, that's, something I think
it does return something different
well yes, context.cards is a list of cards and you're only taking the first card if you did this
and that is likely entirely my fault
loc_vars = function(self, info_queue, card)
return { vars = { card.ability.extra.copied } }
end,
calculate = function(self, card, context)
if context.playing_card_added and card.ability.extra.copied == false then
G.playing_card = (G.playing_card and G.playing_card + 1) or 1
local _card = copy_card(context.cards[1], nil, nil, G.playing_card)
_card:add_to_deck()
G.deck.config.card_limit = G.deck.config.card_limit + 1
table.insert(G.playing_cards, _card)
G.deck:emplace(_card)
_card.states.visible = nil
card.ability.extra.copied = true
return {
message = localize('k_copied_ex'),
colour = G.C.CHIPS,
--card = self,
playing_cards_created = {true}
}
elseif context.post_trigger then
card.ability.extra.copied = false
end
end```
I thought the post_trigger would be sufficient to reset it but apparently not
presumably context.playing_card_added happens only once, and you get all the cards added in context.cards
okay so I just shouldn't need it, gotcha
well that's, not the error I was expecting
what's your code now
loc_vars = function(self, info_queue, card)
return { vars = { card.ability.extra.copied } }
end,
calculate = function(self, card, context)
if context.playing_card_added then
G.playing_card = (G.playing_card and G.playing_card + 1) or 1
local _card = copy_card(context.cards[1], nil, nil, G.playing_card)
_card:add_to_deck()
G.deck.config.card_limit = G.deck.config.card_limit + 1
table.insert(G.playing_cards, _card)
G.deck:emplace(_card)
_card.states.visible = nil
card.ability.extra.copied = true
return {
message = localize('k_copied_ex'),
colour = G.C.CHIPS,
--card = self,
playing_cards_created = {true}
}
end
end```
Sorry if this is a basic quesiton but I'm a complete novice
I'm making a mod which adds a deck, I am trying to get it to randomly pick half the cards in the deck and apply a seal to them
any help would be appreciated
remove this from your return playing_cards_created = {true}
what code do you have so far
A-
did you change anything or did it just happen
For extra context the deck actually applies silver seals to the entire deck, I am trying to implement the Card Sleeves mod and there's a different deck that forces all cards to have a pink seal, so I'm trying to get this new Card Sleeve to apply silver seals to only half the deck
CardSleeves.Sleeve {
name = "reverencesleeve",
key = "reverencesleeve",
atlas = "sleeves",
pos = { x = 0, y = 0 },
config = {},
unlocked = true,
apply = function(self)
local key, vars
if self.get_current_deck_key() ~= "b_reve_reverence" then
key = self.key
if self.get_current_deck_key() == "b_poke_obituarydeck" then
XXXXXXXXXXXXXX
G.E_MANAGER:add_event(Event({func = function()
G.consumeables.config.card_limit = G.consumeables.config.card_limit + 5
return true
end }))
else
G.GAME.modifiers.poke_force_seal = "poke_silver"
end
else
G.E_MANAGER:add_event(Event({func = function()
G.consumeables.config.card_limit = G.consumeables.config.card_limit + 2
return true end }))
end
end,
}
end
the XXXXXXX is where I want the whole "half the deck gets seals" thing to apply
I started a new run to test it after I'd checked it worked with Standard Packs, put Certificate in too, and as soon as I pressed the button to start the Blind, crash
ok i dont know how to format code blocks lmao sorry
loc_vars = function(self, info_queue, card)
return { vars = { card.ability.extra.copied } }
end,
calculate = function(self, card, context)
if context.playing_card_added then
G.playing_card = (G.playing_card and G.playing_card + 1) or 1
local _card = copy_card(context.cards[1], nil, nil, G.playing_card)
_card:add_to_deck()
G.deck.config.card_limit = G.deck.config.card_limit + 1
table.insert(G.playing_cards, _card)
G.deck:emplace(_card)
return {
message = localize('k_copied_ex'),
colour = G.C.CHIPS,
}
end
end```
I am not familiar with how cardsleeves works, so I can't really help you
after checking, it would appear that this also happens with DNA's card adding
no worries
it only works with Standard Packs
I think this context is just wrong
as in, wrong in steamodded
add that additional check then
and context.cards and context.cards[1]
i guess this isn't a steamodded context then
if context.playing_card_added and context.cards and context.cards[1] then yeah?
yes
ech
if context.playing_card_added and context.cards and context.cards[1] then
G.playing_card = (G.playing_card and G.playing_card + 1) or 1
local _card = copy_card(context.cards[1], nil, nil, G.playing_card)
_card:add_to_deck()
G.deck.config.card_limit = G.deck.config.card_limit + 1
table.insert(G.playing_cards, _card)
G.deck:emplace(_card)
return {
message = localize('k_copied_ex'),
colour = G.C.CHIPS,
}
end
end```
copy the hologram's code return too maybe
return { your stuff like it is here }, true
actually that probably does nothing, but doesn't hurt to try
how much of the stuff, what all should be in it
just add , true after your closing }
yeah
otherwise, I guess you're just not getting the cards that were added through your context
if context.playing_card_added and context.cards and context.cards[1] then
G.playing_card = (G.playing_card and G.playing_card + 1) or 1
local _card = copy_card(context.cards[1], nil, nil, G.playing_card)
_card:add_to_deck()
G.deck.config.card_limit = G.deck.config.card_limit + 1
table.insert(G.playing_cards, _card)
G.deck:emplace(_card)
return {
message = localize('k_copied_ex'),
colour = G.C.CHIPS,
}, true
end
end```
you're just getting sent how many were added and the exception is standard packs
lemme actually check the Spectral cards too, hadn't checked those yet
yeah okay they also error
cryptid should work, looking at the code
well that one is on your code
yeah only copies one of the copies
anyway you're dealing with localthunk's code here
and it seems like there isn't a consistent way for you to get the playing cards added in every situation
figures, what'd be the thing to do for fixing that? my mind goes to like a for loop if that's even a thing you can do in lua
yes you'd loop through context.cards
certificate, marble joker and DNA are the ones that don't seem to send what cards they added to the context
how does riff-raff generate common jokers only? i see it has the key 'rif' when generating but i don't see how that accomplishes anything
it passes a rarity to create_card
0 in this case
with SMODS.create_card you can pass a string instead of a rarity in case custom rarities mess with it
yes you can do something like SMODS.add_card { set = 'Joker', rarity = 'Common' }
incredibly inconvenient!
if context.playing_card_added and context.cards then
for i = 1, #context.cards, 1
do
G.playing_card = (G.playing_card and G.playing_card + 1) or 1
local _card = copy_card(context.cards[1], nil, nil, G.playing_card)
_card:add_to_deck()
G.deck.config.card_limit = G.deck.config.card_limit + 1
table.insert(G.playing_cards, _card)
G.deck:emplace(_card)
return {
message = localize('k_copied_ex'),
colour = G.C.CHIPS,
}, true
end
end
end```
Still only added 1 but I'm 90% I probably just wrote it wrong
also familiar, grim and incantation which I missed
I found the Antimatter deck here #💻・modding-dev message does the effect I want, turns out it was quite easy
needs to be context.cards[i] oops
thanks for your help Victin, much appreciated 🙂
okay well that didn't work
Wdym it didn't work
Looks fine, you can skip the , 1 after the loop, pretty sure the default is 1
still only copied once instead of each time
yeah, two Cryptid usages, 2 Hearts in deck instead of the desired 4
is there a function like find_card but it returns every joker corresponding to that key instead of just ones that are currently owned?
the code looks fine to me, did you make sure to save and restart game
like jokers in the shop? or in a booster pack?
you can do get_current_pool('Joker') and that will be a list of all the jokers in the pool currently
yeah just did to see, but nope
it will have the keys of the joker, so 'j_joker' for example
maybe it's cus you're missing _card:start_materialize() somewhere
but I wouldn't know for sure
that's the only difference you have from vanilla code
Weeee go play it !!! https://github.com/survovoaneend/Tattered-Decks
(barely functional)
I'll fix the button placement later btw
I know it's shit
and damn, that one it makes doesn't even activate Hologram
might just
have to make this one do something else
it's a crash hazard right now and doesn't even fully function in the places where it works
if you want it to activate hologam you have to add this playing_cards_created = {true} again to your return
in that list you're supposed to pass the list of cards your joker created
so you should store them in a list as you create them and then pass that to the return
yeah... you will either need to make patches to modify the game code, or add a check of the kind if type(context.cards[i]) == "table" then
but then it'll just ignore the cards from the types that currently crash the game
if context.playing_card_added and context.cards then
for i = 1, #context.cards
do
if type(context.cards[i]) == "table" then
G.playing_card = (G.playing_card and G.playing_card + 1) or 1
local _card = copy_card(context.cards[i], nil, nil, G.playing_card)
_card:add_to_deck()
G.deck.config.card_limit = G.deck.config.card_limit + 1
table.insert(G.playing_cards, _card)
G.deck:emplace(_card)
G.E_MANAGER:add_event(Event({
func = function()
_card:start_materialize()
return true
end
}))
return {
message = localize('k_copied_ex'),
colour = G.C.CHIPS,
playing_cards_created = {_card}
}, true
end
end
end
end```
In trying to implement that, definitely did it wrong, it instantly fully closed the game
your return statement should be outside the for loop and after it
oop nope
or else you will always return in the first iteration of the loop
just changing {_card} to {true} fixed the crash, yeah definitely not a smart move, running on low though
what was the crash
no crash message, just game closure
also you can remove the , true that was just to test
moving the return to outside of the for loop also does that apparently
can you resend what your current code looks like
if context.playing_card_added and context.cards then
for i = 1, #context.cards
do
if type(context.cards[i]) == "table" then
G.playing_card = (G.playing_card and G.playing_card + 1) or 1
local _card = copy_card(context.cards[i], nil, nil, G.playing_card)
_card:add_to_deck()
G.deck.config.card_limit = G.deck.config.card_limit + 1
table.insert(G.playing_cards, _card)
G.deck:emplace(_card)
G.E_MANAGER:add_event(Event({
func = function()
_card:start_materialize()
return true
end
}))
end
end
return {
message = localize('k_copied_ex'),
colour = G.C.CHIPS,
playing_cards_created = {true}
}
end
end```
i assume that doesn't crash
it does when a pack card is added
about to test other methods
Cryptid yes
and DNA yeah
everything causes total game closure
moving the return back into the for loop eliminates the crashes
I fail to see why that'd be happening, especially with no crash logs
I suspect like an infinite for loop is happening or something
ah yes, you're right, your joker is recursively triggering itself on every card added
what is the specific effect of your joker
the description
"Creates an additional copy of each card added to your hand or deck"
you'll just have to find a way to prevent it from copying the cards it is adding
save a list of the cards you need to copy, then copy the ones in that list, so it doesnt keep adding the newly made ones to the list
maybe mark the cards with some flag that you can look for before trying to copy
what is the text colour used by dna?
C:attention
ty
maybe I'll come back to it eventually but I don't got it in me right now
it does also work with Magic Trick so that's something at least
how do i make a joker play a song? kinda like jimball. Im trying to look at the cryptid code but its a mess
i found and adapted the part to declare where the song is in files but dont know how to call it
SMODS.Sound({
key = "music_ksi",
path = "music_ksi.ogg",
sync = false,
pitch = 1,
select_music_track = function()
return next(find_joker("j_gcbm_ksi"))
end,
})
this could very well be wrong, just my best guess
also dont ask why im making a ksi joker
well if you're going to draw attention to it, why are you making a ksi joker 👀
it should be called based on what you return from select_music_track
my friend made the art for it and now i feel obligated lmao
dont quite understand what you mean
ok i got it to work, just need to know how to make it loop
better idea
im just gonna loop the song for 10 hours lmao
I'm trying to make a joker that triggers when the played hand is played for the first time in hte round. Can anyone help? I have no idea what I'm doing at all lmao
i'm copying from card sharp rn and it just does nothing witht his code
I think your calculate function needs to be calculate = function(self, card, context)
how do i make a joker do something after the hand is finished playing?
that's just context.joker_main i think
How can I change a color of text in a description of a consumable?
i fixed that, didn't do anything tho
that's normal calculation. i said after the hand has played
context.after
oh my bad i didn't understand
ty

does if context.after and context.first_hand_drawn then work?
hey howdy!! brand new to modding in general and lua. trying to write a joker that scales its mult based on how many copies of itself you have. how can i make that happen?
taking a peek at the source code is not revealing much. I'm seeing a (find-joker('jokerName')) type deal but not 100% sure what to do with that
please @ me, i'm in a lot of servers and i don't mind :)
is there anyone that can help?
I would first suggest reading the docs if you haven't, it helps a lot. And if you still don't know then please don't as me as I am also very new to lua and modding
how do i check how many cards are being played?
#G.play.cards
I'm wanting to get into making modded cards, is there somewhere that the lua code for the base game jokers is that I can look at
I don't remember off the top of my head, but you can look at the code for the hanged man or madness, for example
where do i find the code for the vanilla cards?
an easy way is to do card:start_dissolve()
If you extract the Balatro.exe, you can find the entire source code
but that wont count for card destroyed effects i thinnk
Yeah, there's more to it than just that for full compatibility
i've done that but i can't figure out which file has the joker effects
all of that stuff is under card.lua
and most function calls that aren't in that file will be under misc_functions or related files
common_events.lua for example
ok
i'm looking but it isn't helping me understand,, , i'm trying to destroy a card in the played hand
does anyone know how to stop Gimp from doing this? I want it to just be a hard pixel line, no gradient or anything
Use the pencil tool, not the paintbrush
step 1: stop using gimp for pixel art
if you want something free, try libresprite
i'm trying to make a card that gains sell value like egg but it does this rn 😭 can anyone help me?
calling it in the wrong context
This looks like an anti-aliasing issue. Check and see if GIMP has an option for that. AFAIK you don't need to change environments for this.
If you'd like to, Krita is another great FOSS option.
what context do i use then?
It's because the paintbrush doesn't work with a single pixel. The pencil tool is the tool for the job there
if context.end_of_round and context.cardarea == G.jokers then
I don't work with GIMP; my bad.
Remove context.individual
i had context.individual removed before and it didn't work
this worked. thank you!
nice! no problem! if you ever need somewhere to look to find the right contexts: https://github.com/Steamodded/smods/wiki/calculate_functions
The SMODS wiki docs should probably be pinned in this channel lol
It's mentioned about 80 times a day
yeah, lol
_ _
People who don't look for wikis also don't look at pins
is there anyone that can help? it's still not doing anything
I just made something like that for my mod, this destroys every scored card
if context.destroy_card and context.cardarea == G.play then
for _, playing_card in ipairs(context.scoring_hand) do
if playing_card == context.destroy_card then
return { remove = true }
end
end
end
how do i make it only destroy 1 card?
You want to check if context.destroy_card is the card you want to destroy
hey, does anyone know if it's possible to activate a joker only when another joker activates?
if context.other_joker then
{
full_hand = G.play.cards,
scoring_hand = scoring_hand,
scoring_name = text,
poker_hands = poker_hands,
other_joker = card, --changes to other_consumeable as it iterates over consumeables
}```
check to make sure context.other_joker is the specific joker you are looking to trigger off of, then put anything it needs to do as normal
what's a better way to test my joker than repeatedly starting runs and hoping to get it from the first store?
DebugPlus is the way to go
there's a debug plugin that lets you spawn jokers
I just made a deck, and then have it add the joker to my deck
and item remover to remove items from the pool
so this does trigger whenever another joker is checked, but is there a way to detect whether that joker actually triggered? like checking if it added chips/mult/money or if it rerolled
that gets a bit tricky, but you could try to take ownership of the joker, then give them a new ability variable that only gets set to true when it triggered, then have your new joker check that old jokers variable to see if its true, then set the other jokers triggered variable back to false
I have not done this before, but that would be my approach, and is prob not the best way either
so something like card.ability.extra.triggered
then have the new joker you make check card.ability.extra.triggered in the context i mentioned and only trigger that new joker if its true
How do I check if a joker is a food joker other than adding valid food jokers to a list one-by-one?
That's the neat part - you don't
could take ownership of the existing ones and give them a variabvle like i mentioned above, but that wont work the best for other mods that may add food jokers
how can I make that text grey?
C:inactive
what am i doing wrong?
calculate = function(self, card, context)
if context.destroy_card and context.first_hand_drawn and not context.blueprint and #G.play.cards == 1 then
card.ability.extra.Xmult = card.ability.extra.Xmult + card.ability.extra.Xmult_mod
return { true }
end
if context.joker_main then
return {
Xmult = card.ability.extra.Xmult
}
end
end```
I feel very dumb...
But where would I put that?
text = { '50% chance to turn every joker polychrome', '50% chance every joker is destroyed', (this text ->)'(Not affected by dice)'}
Hey guys, I don't know why but when I put context.full_hand:is_face() it keeps crashing if context.before and #context.full_hand == 1 and context.full_hand:is_face() then
{C:inactive}your text here{}
text = { '50% chance to turn every joker polychrome', '50% chance every joker is destroyed', (this text ->)'{C:inactive}(Not affected by dice)'}
You don't technically have to close it there, but it's best practice
full_hand is not a card even if the length is 1
do you know where in the docs this is for future reference?
if context.before and #context.full_hand == 1 and context.full_hand[1]:is_face() then
scoring_card then?
you would do context.full_hand[1]:is_face()
^
It's in misc_functions.lua. search for G.ARGS.LOC_COLOURS and there's a whole list there
It's not in the docs, but the balatro source code
(I guess it could be in the docs. I haven't checked)
does there exist a video on how someone created a balatro mod? i tend to work realy well with videos where i can see how ppl navigate the directories of the game (i get so lot all the time in directories LMFAO), so i'd love to watch
Any UI geniuses know what's preventing juice_up on my UIBox?
function SystemClock.update_config_panel()
local panelContents = G.OVERLAY_MENU:get_UIE_by_ID('sysclock_config_panel')
if not panelContents then return end
panelContents.config.object:remove()
panelContents.config.object = UIBox{
config = {offset = {x = 0, y = 0}, parent = panelContents, juice = true},
definition = SystemClock.config_panel()
}
panelContents.UIBox:recalculate()
panelContents.UIBox:juice_up(0.5, 0.5) --does nothing
panelContents.config.object:juice_up(0.5, 0.5) --does nothing
Moveable.juice_up(panelContents.config.object, 0.5, 0.5) --does nothing
end
function SystemClock.config_panel()
return {
n = G.UIT.ROOT,
config = { align = 'cm', minw = 11, r = 0.1, emboss = 0.1, colour = G.C.GREY },
nodes = {
---Contains a bunch of child nodes, option_cycles and sliders
}
}
end
That should be good, but if you intended the hand to only contain a single card then you should keep that other check in there as well
Ahh I see. Thanks! Also uhhh how do I trigger something twice?
after looking I am still kinda confused.
text = { '{G.C.GOLD}50% {G.C.DARK_EDITION} test' }
That doesn't work, how would I do something like that?
just C doesnt work either
You use the variable on the left. so C:x where x is the variable on the left of the color you want to use
ah, thx
been messing around with it for a while, still not working
try a couple print statements, what does context.scoring_name show?
there's a bit of info on this on the smods examples https://github.com/Steamodded/examples/blob/master/Mods/ExampleJokersMod/ModdedVanilla.lua
wait, where do print statements show up?
in the console that should open with the modded client
should have the game and a console window when it opens
nothing is printed
can you post the code for the entire joker?
puit the print statement before that if statement
it seems like the second if statement isnt p[passing the check
anyone have thoughts on this
I can't seem to figure out how to actually get the cards generated by a booster pack
still isnt. printing anything
G.pack_cards.cards? maybe
does it make empty lines in the conole? or just nothing happens in the console
Why is my json file broken? What am I doing wrong? what is happening? where am I? I am in the swirly void
nothing happens
Also I changed main file from main.lua to blank, and nothing changed. It's literally just not recognizing the file.
gives this
though, let me take a look, I might be doing it wrong
That's not how you write dependencies I'm pretty sure. The part above that in the wiki shows how
WHO CHANGED THE DEPENDECY METADATA WHEN I WASN'T LOOKING
uuuuuuuughhhhhhhhhh
that's how it USED To be written me and my friend have been BASHING our heads against the wall for 48 HOURS WONDERING "why does the thing not thing" why is it because the dependency format changed. dammit
sorry, i am angry
doofenshmirtz used his Dependency Metadata Change-inator
I think context.individual never has context.cardarea == G.jokers, do you want it to trigger on every playing card?
Seriously tho, what was wrong with the old dependency metadata?
i want it to work like card sharp but the other way around
so you dont need individual
I think it should be on context.joker_main
G.playing_card = (G.playing_card and G.playing_card + 1) or 1
local _card = copy_card(context.full_hand[1], nil, nil, G.playing_card)
_card:add_to_deck()
G.deck.config.card_limit = G.deck.config.card_limit + 1
table.insert(G.playing_cards, _card)
G.hand:emplace(_card)
_card.states.visible = nil
G.E_MANAGER:add_event(Event({
func = function()
_card:start_materialize()
return true
end
}))
return {
message = localize('k_copied_ex'),
colour = G.C.CHIPS,
playing_cards_created = {true},
}
end
end```
How....do I make this copy the card twice?
just do the copy section 2 times 😛
_card:add_to_deck()
G.deck.config.card_limit = G.deck.config.card_limit + 1
table.insert(G.playing_cards, _card)
G.hand:emplace(_card)
_card.states.visible = nil```
thaat works?
anyone know where in the source code the way the wheel works is shown?
I'm making something similar to it but want to get a reference.
it should
For anyone keeping score at home, the issue with juice_up on UIBox was the object role type.
UI child elements use role_type = 'Minor' which causes them to inherit the motion of the Major, so they won't be juiced.
The solution is to replace the role_type with Major like so:
panelContents.config.object:set_role{
role_type = 'Major',
major = nil
}
could make it look nicer and do a loop, but honestly dont need to if you only wanna do it 2 times
is there a context for choosing a card from a booster pack? I want to have a joker do something specifically when you do that
actually I can probably just check for context.playing_card_added or context.using_consumeable and context.open_booster
Ok this kinda works? but it just kinda leaves this hole in the middle that's supposed to be the copied card?
it shows up in the full deck, but you can't see it or pick it up
copuld be, try removing: _card.states.visible = nil
can anyone at least help me with the turning jokers poly 
it works! enough!
okay no this isn't correct
these contexts likely dont overlap
yeah, I figured
does it count as buying a card when you pick it from a booster pack
I have no clue
card:set_edition({polychrome= true}) i think
basically what I'm trying to do is give the player a negative copy of any card they take from a booster pack
I had to lovely patch into G.FUNCS.use_card to do something when picking from boosters
maybe you can add your own context there
function tarotCard:use(self, card, area, copier)
for _, c in ipairs(player.inventory) do
if c.key == 'joker' then
c:remove_from_deck(self, card, from_debuff)
end
end
end
this is just a test, but I am SO confused on the layout of things.
The docs tell me what to use but I don't know how to use them
what file is use_card in again?
button_callbacks
try this
[[patches]]
[patches.regex]
target = "functions/button_callbacks.lua"
pattern = '''elseif card.ability.set == 'Joker' then'''
position = 'after'
match_indent = true
payload = '''
SMODS.calculate_context({picking_from_booster = true, card = card})
'''
oh, thanks!
greetings fellow balatro enthusiasts, can anyone tell me why it insists I should close my brace here when uh... no I don't think I should?
thanks
(I know this code shouldn't particularly do anything currently other than essentially add a dummy gold stake, I'm just trying to get it to load in the first place before I start tinkering with actually having it do things.)
i think you're missing a couple commas
how do I check if the player has any jokers?
double checked, you're totally right, completely missed at least one at the color line, thanks
for my tarot card "can_use"
check what the code for Stencil is like
...hmm
this might just be an issue with my smods.add_card syntax because I've never used the function before
@void pecan actually no dont do this
look into the code for Hex
huh? The spectral card?
G.jokers.cards is the variable you want
if so, I have zero idea where to look
if you mean in terms of joker count
I just want to make sure they at least have 1 joker
if #G.jokers.cards != 0 then
or, if you wanna be more secure, then
if #G.jokers.cards > 0 then
I think it's context.card.config.center.key
ah right, that'd be it
had a bunch of these same problems today so I'm glad to reshare the knowledge lol
Is all of the "G.(whatever" in the docs? I also want to turn all jokers polychrome (50%) or destroy them all (50%), but i'm not sure where to start
G. is part of the actual Balatro code, so you'll need to scan that to figure out how it works
trying to make a joker that upgrades when an enhanced heart card is scored, would context.check_enhancement work for finding if the card has an enhancement?

What about turning a joker polychrome? I know I needcard:set_edition({polychrome= true}), but how do I fetch the jokers to make it polychrome?
okay it's working correctly now, but only for buffoon packs, using consumables or pulling playing cards from a booster doesn't activate this
If you want all jokers do a loop on G.jokers.cards
I think if you change the pattern for elseif card.ability.set == 'Enhanced' or card.ability.set == 'Default' then it should work on playing cards
For consumables I'm not sure but it calls context.using_consumeable. I don't know if it differentiates between using it in a booster or not
this is that part of the code
hmm, just inserting the same picking_from_booster context after the playing card check gives me some scary featureless playing cards in my joker slot
it doesn't work with playing cards I'm pretty sure
ah
so you should do add_cards for jokers and consumables and I think it's create_playing_card (no SMODS) for playing cards
am I checking for enhancements correctly? it's not doing anything rn
shouldn't card.ability.set also be context.other_card.ability.set?
i'll try that
so create_playing_card is the only way to create a playing card? I have no idea how this works and it isn't documented anywhere
for key, c in pairs(G.jokers.cards) do
--how do I destroy the jokers? c:remove_from_deck()?
end
this is from my Tribute spectral card (destroy all jokers +1 joker slot)
c:start_dissolve()
okay, I have this, but I have no clue how i'd make it copy the card, currently it's just random
maybe copy_card is what you actually want but I have never used either so I have no idea
Death uses copy_card
oh, that works perfectly
you’ve just given me a funny as shit idea
scary featureless joker
is this the wrong way to set the card's edition?
Blank Joker
Does nothing?
keep it until ante 8 for a suprise
would be really funny if it rarely triggered during scoring to keep you confused on what it does
yesssss…
How do I make the tarot say something when used?
like the “nope!” when you fail wheel?
yeah
i’m not really well versed in coding but you could ask someone else
So I'm gonna work on this more tomorrow, but I thought I might as well ask if anyone has suggestions:
I'm basically a shader noob, but I've followed some basic tutorials before such as when I was using ShaderGraph in Unity. I want to enable a bloom/glow shader on cards contextually. The only shader related stuff I've managed to do so far is add a patch for Card:draw() to use the negative shader for something else when I set a property on a card, but I seem to constantly be running into issues trying to get a new, fresh shader to actually render on something with SMODS
The example I found for SMODS is for editions. Am I able to just set a "shader" property on jokers and have it draw that shader the same way, or are editions special in that regard?
this is how i've been drawing shaders on non-editions
for custom shaders, you should define a shader and give it a key, like so:
SMODS.Shader({ key = 'silver_seal', path = 'silver_seal.fs' })
when referring to the key it should have your mod prefix
Okay yeah I did the defining it but, guh, I forgot to use the prefix
And when defining that draw function, is that just in the joker definition?
yep
Oh, neat. I didn't know it was that easy, though obv I was handicapping myself accidentally
I attempted something similar before but kept getting nil for draw_shader, but I don't think I was calling it from children.center
I havent tried it on jokers yet but it should work exactly the same since it's just a base function
how do I make my tarot say something like wheel of fortune 
Anyone know
Okay this is a decent start, I'll see if I can try this again tomorrow. Thank you!!
Hold on lemme check
So the code for this in the vanilla game is basically this:
trigger = 'after',
delay = 0.4,
func = function()
attention_text({
text = localize([put localization string here]),
scale = 1.3,
hold = 1.4,
major = card,
backdrop_colour = G.C.SECONDARY_SET.Tarot,
align = (G.STATE == G.STATES.TAROT_PACK or G.STATE == G.STATES.SPECTRAL_PACK) and 'tm' or 'cm',
offset = {x = 0, y = (G.STATE == G.STATES.TAROT_PACK or G.STATE == G.STATES.SPECTRAL_PACK) and -0.2 or 0},
silent = true
})
G.E_MANAGER:add_event(Event({
trigger = 'after',
delay = 0.06 * G.SETTINGS.GAMESPEED,
blockable = false,
blocking = false,
func = function()
play_sound('tarot2', 0.76, 0.4);
return true end}))
play_sound('tarot2', 1, 0.4)
card:juice_up(0.3, 0.5)
return true end }))```
Basically it just uses the attention_text() function with a bunch of values, with align and offset differing based on whether or not it's being used from the pack or directly from its current position, and then it nests another function for the sound in it for some reason
So
- attention_text() with your localization string
- play_sound('tarot2')
- card:juice_up()
tf does juice_up() do?
It's what causes cards to shake when you do things with them
i.e. when Invisible Joker is ready to sell, or when DNA is ready to copy
or Trading Card is ready to destroy
so I would do
function tarotCard:use(card)
chance = math.random(1,2)
if chance == 1 then
for key, c in pairs(G.jokers.cards) do
c:set_edition({polychrome = true})
end
else
for key, c in pairs(G.jokers.cards) do
attention_text(text = localize([not sure what you mean here, like any string?]), scale = 1.3
c:start_dissolve()
end
end
end
I forgot the juice up
the key for your text in your localization file (usually localization/en-us.lua)
localize([ ]) is for is you have stuff in localization files
to just use a string replace all of that with ''
So like I'm not developing in multiple languages or anything, but yeah I have all my stuff stored in en-us.lua, and most of the card effect strings are k_[something]
(text = 'text here')
I.E. k_nope_ex is WoF's
test to make sure that you can replace that with a normal pattern patch. regex patches are slower and have more footguns.
it looks like a normal pattern patch will do just fine
I did notice that, but was afraid to touch it
will check
just replace regex with pattern?
ya
[patch.pattern]
that patch has pattern fields anyways, it shouldn't be a regex
I am actually having one more issue with it that I'm unsure how to fix
the patch works perfectly for jokers and playing cards, when injecting that line here and here
doing this successfully adds contexts for getting jokers and playing cards from booster packs
what did i do 
but doing the same for consumables (under if card.ability.consumeable then) causes it to trigger when any consumable is used while you're in a booster pack menu (and it seems to do it twice??) even if the consumable is in a consumable slot
attention_text takes a table as its parameter, not individual parameters
Add braces around the two values you passed in
attention_text({text = "hello", scale = 1.3, hold = 1.4}) like that?
Yeah
same error
try running it. I think your editor is just drunk
It was 😭
THE SECOND I saved it went away
I am way in over my head trying to figure this out
I'm not entirely sure why the consumables act differently but I guess it's just because they're consumable
Lo and behold, it is doing... something
It's drawing it a second time for the shader effect at the very least, which is progress
Thank you Wheat!
the only other shader related thing I've managed was screwing around with using the default dissolve shader to make this, but actually applying a unique shader rather than leveraging existing ones is much harder
Work for tomorrow
ooh that's neat
how can I give myself my tarot card? Is it possible? Using DebugPlus
go into the collection and press 3 while hovering over it
thats cool actually
actually I think you might need to enable the base game's debug menu (which debugplus also has a bunch of additions to) in order for those binds to work?
function tarotCard:use(card)
chance = math.random(1,2)
if chance == 1 then
for key, c in pairs(G.jokers.cards) do
attention_text({text = "Accepted", scale = 1.3, hold = 1.4})
play_sound('tarot2')
c:juice_up()
c:set_edition({polychrome = true})
end
else
for key, c in pairs(G.jokers.cards) do
attention_text({text = "Rejected", scale = 1.3, hold = 1.4})
play_sound('tarot2')
c:juice_up()
c:start_dissolve()
end
end
end
My tarot card doesn't say anything, but no errors.
It kind just skips all of that somehow and immediately either destroys or turns all cards poly
does anything point to this function?
It works well for what it is! Now I'm just trying to get a simple bloom shader up and running so I can make some jokers glow because somebody requested it. I hate shaders I hate shaders I hate shaders
wdym?
the way to calculate stuff when using a tarot card is
(code here)
Well it works, it just my tarot card doesn't "say anything", like wheel of fortune
attention_text({text = "Rejected", scale = 1.3, hold = 1.4})
play_sound('tarot2')
c:juice_up()
c:start_dissolve() - just does this, skips above
so it sets polychrome sometimes?
yeah, everything BUT the card speaking works
it will still be a 50/50 of destroy and poly, card just doesn't speak
I would still try restructuring it as ```lua
SMODS.Consumable {
---everything else here---
use = function(self, card, area, copier)
chance = math.random(1,2)
if chance == 1 then
for key, c in pairs(G.jokers.cards) do
attention_text({text = "Accepted", scale = 1.3, hold = 1.4})
play_sound('tarot2')
c:juice_up()
c:set_edition({polychrome = true})
end
else
for key, c in pairs(G.jokers.cards) do
attention_text({text = "Rejected", scale = 1.3, hold = 1.4})
play_sound('tarot2')
c:juice_up()
c:start_dissolve()
end
end
end
}
havent used attention_text yet but seeing wheel's code you could be missing 'major'?
I hate optimal code
probably
that could be it too
your play sound and juice up functions are missing parameters too, I think that just means they'll be nil, unsure if that's a big deal or not
local tarotCard = SMODS.Consumable({
key = "tarot_card_joker_effect",
set = 'Tarot',
atlas = 'sigma', pos = { x = 0, y = 0 },
cost = 0,
loc_txt = {
name = 'Balance',
text = { '{C:green}50% {}chance to turn every {C:gold}Joker{} {C:dark_edition}polychrome', '{C:green}50% {}chance every {C:gold}Joker{} is {C:red}destroyed', '{C:inactive}(Not affected by dice)'} --Would also appreciate help on colors, couldn't find it on docs
},
unlocked = true,
discovered = true,
can_use = function(self, card)
if #G.jokers.cards > 0 then
return true
else
return false
end
use = function(self, card, area, copier)
chance = math.random(1,2)
if chance == 1 then
for key, c in pairs(G.jokers.cards) do
attention_text({text = "Accepted", scale = 1.3, hold = 1.4})
play_sound('tarot2')
c:juice_up()
c:set_edition({polychrome = true})
end
else
for key, c in pairs(G.jokers.cards) do
attention_text({text = "Rejected", scale = 1.3, hold = 1.4})
play_sound('tarot2')
c:juice_up()
c:start_dissolve()
end
end
end
})
wrefgougf3w4eiroyugbw3ree4gewGQ
nvm forgot end and comma
perfect
Very first tarot done, it was simple but very good for learning
Should use pseudorandom instead of math.random
can_use can be simplified to return #G.jokers.cards > 0
I'm actually getting quite confused by this code (which is for pulling cards from booster packs)
the latter two elseifs I understand
well, actually, hm
what I'm trying to do is patch this so that it has a context specifically for using one from a booster pack
but it seems there's no distinction logically from using one that came from a booster pack and just using a consumable you already had in your consumable slot, while in the booster pack interface
you might be able to check if card.added_to_deck
that's true, I can't think of any circumstances where a consumable activating without being in your deck isn't from a booster pack
you can also check card.area ~= G.consumeables
i haven't tried it tho
hope it works
good luck
hmm
I tried it as just card.area too and it did the same thing
would it be card.config.area? maybe?
nope
context.consumeable.area iirc
oh huh, I see
I’d check if it was equal to G.pack_cards otherwise shop uses would trigger too
yeah it's passed as context.consumeable
ah that's true too, good catch
Right here
What’s the difference
pseudorandom is what's used for actual randomization in vanilla balatro
and it plays better with seeded runs
this... should work, right?
but consumables just act normally and never trigger this
pseudorandom actually makes seeds have an effect
If you don't, then you can just reset the game forever until you get the desired outcome
And seeded runs will not work with it
quick question anyone know the colour tag of whatever ecto uses for the negative text?
dark_edition
thank you that worked 
this is getting really confusing?
oops, bad crop
if I go back to the old thing of just checking if it isnt in the consumables slot
it suddenly works, but now always triggers, even when in the consumable slot
which makes absolutely no sense
Maybe they get removed from their area before being used, which would make this more difficult
checking if it's in g.pack_cards causes it to never occur even if it's in a pack, and checking if it's not in the g.consumeables causes it to always occur even if in the consumables slot
so... it's going somewhere else regardless of where it came from
just what I needed
do you have debug plus
yep
Try print(blahblah.area) right after the context check
I guess, you'd have to look at the use consumeable function to see exactly what it's doing
It might be in G.play
ah yeah literally right before the calculate
Bruh
Oh that’s a pain
I don't know if removing the line is a good solution
Just patch a last area value before it
probably not but i'm curious what'll happen so I can't not try
wait smods actually patches this line with something else already
You should look at Mods/lovely/dump
For the code after all lovely patched were applied
given a standard playing card what's the best way to get it's rank, suit, enhancement, ability, and seal?
and worse: not just get the in game values, but the actual words used for them, like "spades" and "steel" and "red seal"
ah I didn't know about that, thanks
you can parse the words from the localisation files
i thinks
For rank and suit make sure to use SMODS.has_no_suit and SMODS.has_no_rank to ensure u don't accidentally try to get suit or rank from a card that doesn't have it
And you can get the text form of them by doing card.base.value for rank and card.base.suit
If you're going to display that text I strongly recommend localizing it by paasing it to localize with "ranks" or "suits_plural" (or singular) as the 2nd argument
heya! so I've coded this blind called "The Journey" and it's meant to function so that each consecutive hand must not have a lower base score than the last one
however, I've discovered that if one was to: play a hand, close the game, then re-open it and load back into the save, their hands were no longer debuffed, essentially ruining the entire point of the blind
is there a fix for this so that the score requirement carries through even after the game is closed?
this is working, but there's one last, extremely odd issue. here's my patch
origin is the original area value, and i'm passing it through the context for debugging purposes
for some reason, consumables that are bought directly from the shop appear to pass this check, meaning origin == G.pack_cards (somehow??)
but then, once you open any booster pack, consumables from the shop will no longer pass this check, and everything works as intended
How are you checking they pass?
well obviously there is a fix for this, let me rephrase: what would be the best fix for this?
I'm setting origin to card.area before the rest of the code sets it to nothing
then later on, checking if origin == G.pack_cards, and if so, setting the consumable_from_booster context to true
I'd just do something like
if card.area == G.pack_cards then card.from_pack = true end```
hmm, true
then in your calculate check for
if context.consumeable.from_pack then```
trying to make my custom consumables all use a shader at all times by injecting through lovely, but it isn't working. any help?
[manifest]
version = "1.0.0"
dump_lua = true
priority = 0
[[patches]] # CHAK
[patches.pattern]
target = "card"
pattern = '''function Card:draw(layer)'''
position = "at"
payload = '''
-- CHAK START
local card_drawref = Card.draw
function Card:draw(layer)
local card_drawref = card_drawref(self, layer)
if (layer == 'card' or layer == 'both') then
if card.sprite_facing == 'front' then
if card.consumable.set == 'ChakraConsumableType' then
card.children.center:draw_shader('booster', nil, card.ARGS.send_to_shader)
end
end
end
return card_drawref
-- CHAK END
'''
match_indent = true
why are you trying to insert a hook over the definition of card draw?
imma be so fr it is 5:37 in the morning i am not liable for being stupid
i jus wanna get this done
but yeah i'll move it to within card draw, see what happens
either way, you want a patch like this
## Mythos Draw Shader
[[patches]]
[patches.pattern]
target = 'card.lua'
pattern = '''if (self.ability.set == 'Voucher' or self.config.center.demo) and (self.ability.name ~= 'Antimatter' or not (self.config.center.discovered or self.bypass_discovery_center)) then'''
position = 'before'
match_indent = true
payload = '''
if self.ability.set == 'Mythos' then
self.children.center:draw_shader('ortalab_mythos', nil, self.ARGS.send_to_shader)
end
'''
thanks i'll try this code out, i got the majority of the other code from somewhere else in the server
this works, but it behaves identically, so the issue is still present
specifically shop consumables?
yes
for some reason, card.area == G.pack_card for consumables in shop until you use a booster pack
but also that can't be true??
I don't know
i might just need to make like a lovely patch or something but it would be great if i could avoid doing that for as long as possible
thank you this worked btw
you're my goat
is update the only method to live update variables like these in a joker?
save your variables in G.GAME.blind.discards_sub and G.GAME.blind.hands_sub instead of the blind's config
without hooking to the save and load functions, these are (two of) the few variable names that get saved
this is bizarre I have no idea why this happens
i think when you buy it from shop the area is saved as G.shop_jokers, which gets nil'd after the shop ends while G.pack_card is also nil when not opening a pack
so, I should have an or card.area ~= G.shop_jokers in the if statement?
card.area will be G.consumeables after being bought/taken from pack
so that doesnt make sense
we're looking at being used though
if you use a card from the shop, it has area of pack_card until you've opened a booster
or at least, in the use function it does
qhar...
the idea I'm implementing is that if you use a consumable from a booster pack, you get a negative copy of it
i was overthinking my fix way too much...ty for the quick solution!
this logic works correctly only after you've already opened a booster pack, if you haven't done that yet, card.area == G.pack_cards will be true even if it's in the shop
but, not if it's in the consumables slots, that works fine
only the shop
let me check something
huhh
here's video of this happening, by the way
yeah when used from shop the card's area is nil
wait no
fuck
eval dp.hovered doesnt work because the card cant be hovered
o_O
awful
where the fuck does it go after you use a booster
also I'm glad you didn't mention this line of code because yes, I have tried changing it to just "return (number bigger)" rather than "if (number bigger) return true else return false", and for some reason, that just doesn't
using a consumable always sets its area to nil, so i'm saving whether or not it was in a booster pack in card.from_pack before it ever sets as nil
so i'm stuck with it being spaghetti
why does it think it's from a booster until you open a booster
oh damn is that why an oddity was being weird with buy and use earlier
????
are you flipping, selecting, unflipping and unselecting to make them jump like that
highlight > flip > juice > unhighlight > flip > juice
very creative
ooh that is a very satisfying flip
popcorn