#💻・modding-dev
1 messages · Page 432 of 1
It seems to work.
the problem is using samplejimbos
use a newer example mod
dang
what is this example mod you speak of?
yeah absolutely do not use that
thats me there
i was about to post that
that code is over 14 months old
oopsie daisy
you can refer to examples, the wiki, and smods itself here https://github.com/Steamodded
you can also refer to here https://github.com/nh6574/VanillaRemade for some good practices
hmm
Would it be possible to do a similar thing for seals?
how is a context created? id love to see an example so i can make mine
SMODS.calculate_context({modprefix_contextname = true}) I think.
Mod prefix is not required but it is reccomended.
oh ok
ok
and how do i code it?
You can find examples in Steamodded itself by searching the source code for that function call.
yeah i was searching and didnt find it
How are you searching for it? Those function calls should be there.
found it nvm

wait what, there's nothing?
i thunk you found lsp definitions
maybe
yeah i did
oh found it at utils
well yeah i found it but um now what
i suck at this 😭
you call calculate_context then the game makes every joker run its calculation routine with the context you fed it
ok
SMODS.calculate_context( {
example_jimbo_annihilated = true
})
then if another joker has stuff like
if context.example_jimbo_annihilated then
-- give morbillion xmult
end
it will run
the hard part is getting the calculate_context call to be at the right place
which requires patching the game half the time
and how do i make it check if a card is destroyed...
You would hook Card:remove()
0 days since last "check joker is destroyed" question
You'd have to find the right function to patch, make a lovely patch for it with your custom context called at the right time, then check for that context in your card.
man what do i do if i suck at this 😭
i will make another smods pr
You can also search this discord channel to see if others have had your same question, and what they did to fix their code
If you can't do it yourself, perhaps others have done it already
(this is like hand.visible but as a function)
which might have happened
the easiest answer is look at how paperback did it and copy it
No, hooking is sufficient here.
Oh, this is cool. Does this context happen in booster packs as well, or just during blinds?
it's just a function, you can put whatever
nice idea
Ah
yeah i alr had it
local oldcardremove = Card.remove
function Card:remove()
if self.added_to_deck and self.ability.set == 'Joker' and not G.CONTROLLER.locks.selling_card then
SMODS.calculate_context({modprefix_context = true})
end
return oldcardremove(self)
end
wow thanks
im just going to save this post
actually where do i put that
Anywhere in your code.
oh ok
Can somebody help me with rarities, I'm having a hard time with trying to find something that works Tried modding chat but they pointed me here
What is the issue?
ik i have it wrong, but idk how to put it correctly. how should i put that in the calculate?
if im reading the wiki right, final_scoring_step only works for score modification
Oh, this is so much simpler than patching. Of course there are variables in a Card object to track state, didn't even know about the added to deck variable. Cool!
if context.whatyoucalledthecontext then
- Pools are messed up
- Ive been trying for days and I'm getting sick of coding witch I don't want that to happen
- With the example I was able to scrap, the pools are blank and the keys don't match
oh
It also all dumbs down to me not knowing wth i'm doing when it comes to rarities
what do you wanna do at the base of it all ?
Code?
epic
Code?
WOW!
I wanna be them!
It even has a jojo reference It's so awesome 111!!1!1!1
final_scoring_step is a specific timing in the scoring pipeline, you can use an event to do any animation you want in there and it should work
what i dont know is if it is the correct timing you were looking for
im very new to this
i wanna make a deck that starts you with some jokers and sets winning ante to 10
how would i do that
The event timeline i'm wanting for the joker is
Score Jack/King
Flip, become queen while showing card back
Flip back to show it is now a queen
Discard
ive a problem, and it's that my keyboard layout won't let me open the debugger (ctrl + /)
You don't need to open the console to see the print.
then it didnt work
Where did you put the hook?
Wait no, you swapped card and destroyed in your context.
on the very beginning of my full script
guys i think my code has the Oops all 6's curse, for some reason my random number between 1 and 9 keeps returning 6 every time ```calculate = function(self, card, context)
if context.joker_main then
-- use Joker ID and current hand to generate a changing seed
local seed_base = "calculator_" .. tostring(card.ability.id or 0) .. "_" .. tostring(G.GAME and G.GAME.round_resets and G.GAME.round_resets.hands_played or love.timer.getTime())
local op = pseudorandom_element({ "add", "sub", "mul" }, pseudoseed(seed_base .. "_op"))
local val = pseudorandom(1, 9, pseudoseed(seed_base .. "_val"))
if op == "add" then
return {
mult = val,
colour = G.C.WHITE,
card = self
}
elseif op == "sub" then
return {
mult = -val,
colour = G.C.WHITE,
card = self
}
elseif op == "mul" then
return {
xmult = val,
colour = G.C.WHITE,
card = self
}
end
end
end```
ub_carddestroyed and ub_destroyedcard
.
🙂 🔫
why is it always the dumbest things
it works now
last thing
how can i check what card is being destroyed?
Put in SMODS.calculate_context, ub_cardbeingdestroyed = self
ok
I keep crashing when I open the shop
So within the event manager do I call on the step by just doing "if context.final_scoring_step and context.cardarea == G.play then" followed by card:flip()?
or do i call for context before the manager?
before
Ok thank you
after thinking about it i realsied it made a lot more sense to call context first lol
IT WORKS
YAYYSS
tysm
The only thing I'm confused about is why my list keeps resetting.
Also the negative hand size seems to not go away.
yes
you can still play them tho, they just dont count for anything that looks for visible poker hands
Casual yes
Mhm
Interesting
Yo you made the family
Useless
And the trio
And the other one
no those actually dont care about if the pokerhand is visible
I can only think of to do list
basically only to do list and obelisk do
Fuck obelisk
So I think i have no idea what im doing, how do i go about having an event trigger on the final scoring step? and am I even using card:flip() correctly?
remove the cardarea check
also right click > format document
this doesnt work this way in lua either
how can i make a floating thing like the legendary jokers?
it does work in game though, at least as far as i can tell
but i may need to do more testing
You set soul_pos
ok
ok seems like i misremembered
it in fact does not
it'll always be true because if your random number isn't equal to 1, it checks if the value 2 is truthy, which it is
do i need to have both floating and base sprites on a same atlas?
ok
So how do I properly code a 3/4 chance with pseudorandom?
if not pseudorandom("whatever_you_want") < G.GAME.probabilities.normal / 4 then
although this method will make oops all 6s a bad joker to have haha
How so?
still need help
G.Game.probabilities.normal is 1 times 2^oops! count
if you have zero oops, the if statement checks if your chance is higher than 25% (3/4ths of the time
if you have one oops, the if statement checks if your chance is higher than 50% (1/2 of the time)
and if you have three, higher than 100% (impossible)
I did it
since you're making your own rarity, you need to use the mod's id too. iirc the setup is r_modid_name
No, it is 2 ^ amountofoops
It doubles probabilities, not adds.
Ok cool thanks
ok, fixed the message
Is there a method I could use to make oops all sixes not lower the rates? Also the real statistic for male calicos is roughly 1 in 3000, would that be any easier to code and or not suffer as big a drawback from oops all sixes?
in this case it would be 1 in 3000 to not trigger
just don't use G.GAME.probabilities.normal and oops can't do anything
you could do if pseudorandom() < 2+G.GAME.probabilities.normal / 3 + G.GAME.probabilities.normal
which would basically get to 100% at 4 oops!
oh wait
I got it
ah well nvm
how could i make a section in decks selection ui?, like in sleeves mod when selecting a sleeve
well, it would work
if you do if pseudorandom() < G.GAME.probabilities.normal / (4/3) then that would work as a 3/4ths chance, but it would also basically just be a slightly better 1 in 2 chance since it becomes guaranteed with one oops!
also replacing (4/3) with 1.3333 would do effectively the same thing
ive decided to go down the 1/3000 of not triggering route, whats the symbol used to indicate a not equals? or if it doesn't support not equals what would i do instead?
~= is probably what you're looking for
Oh also, how does oops look at a jokers code to change the values for numbers in text? I know the text numbers need values assigned but how does oops look at that
oops! only changes G.GAME.probabilities.normal
and then all the other jokers just use that variable
hmmmm ok, how would i code the descriptions text to update the odds when oops is there?
like with vanilla jokers
wdym? like galdur?
or just the default "new run" menu
this
I mean, this'll sound selfish but I probably wouldn't recommend adding another bar like that
not a lot of space on that menu anymore
So what do you recommend?
depends, I have no idea what your plans are for adding such a bar
add it as a galdur page
no
also while I wait for an answer to that, how do i have an event trigger the cards to flip on the final scoring step?
currently codded like this but it doesn't trigger in game:
like sorting decks into categories
so a better new run menu? to navigate easier?
yea
what's the improvement over the galdur approach?
I don't like Galdur 😔
why's that?
i could make a galdur compat but idk
the animations
you can turn the animations off
I feel like you can disable those but I'd have to double check
well if eremel says you can it's probably true lol
oh no...
Entire idea of stringified Talisman can be dead rn
oh
wouldn't this only work if both sides were string
The main point of idea to allow compate big number with regular number
the entire issue has always been that you can't override the comparing table <-> number because of the number (if it's table <-> table it's fine)
I assumed that this problem relevant only for tables
I also have a question, can you define the order in which the decks are displayed?, like adding decks between the vanilla ones?
bump
the playing cards or the joker?
@wintry solar looks like my idea for Talisman is dead. Can't compare string and number, just like table with number
(
the playing cards, jacks and kings that are scoring specifically
there should be a context.full_hand var in the final_scoring_step timing?
or context.scoring_hand if that's better
what its meant to do is: score the kings and jacks, flip them and swap them into queens, flip back and discard
I don't think luajit is a bad solution though
is there an example or mod I could use for reference? not sure where I'd use this and probably will end up asking a lot more questions
If force LuaJIT as part of Talisman that's fine
yeah exactly
.
luajit sounds amazing
i get why the buttons extend to match the middle box but it looks so bad 😭
i just wanted to add more sorting options..
Does anyone know what mod uses the prefix "G"?
@tepid crow meant to reply with this to you
can you extend horizontally instead?
Yeah that should be doable if you iterate over context.scoring_hand
I have a single buzzing insect instead of a brain, what exactly does that mean tvt
maybe put the options in one row
you can check out the implementation of e.g. strength if you don't really know how to approach it
ok
Guys what is the best documentation for creating consumable type like it keeps crashing when I enter the shop
but you'll want to iterate over the cards in context.scoring_hand and make an event to flip each one
yeah thats nicer
strength does it with multiple events per card (1 to flip, 1 to change, 1 to flip back) so you probably want to copy that
I'm really curious what month is, I'm guessing it's part of your mod but how a card can have a month really intriuges me
Why if the use_consumeable function triggers twice for gateway or similar consumables that destroy jokers it does not destroy jokers on the second trigger?
there are a lot of specific pokerhands too so the sorting was kinda needed lol
what file is strengths implementation in?
yeah that one's probably a bit more readable than the source code
my brain is just not putting the pieces together
maybe i should try and find an actually good coder instead
But then id need to become a decent pixel artist
I've been reworking Joker values for the Balatro Community Update mod, but I was told in order to rework the actual effects, I'd need to make a lovely patch for effects, where can I learn more on that?
ok now to figure out how to hide them
How can I choose where a sticker is placed on the card, like visually? I could swear it was a thing
A sticker you made yourself? Because the position depends on the sprite
oh that makes sense, just add empty space in the sprite right?
and yes I mean a new sticker
Yeah just make a 71x95 sprite the same way a joker would be but just put the sticker where it should go
yay
anyone know how you set the sound effect of a new calculate key that i added?
the mult^ operator is a little underwhelming when it makes the same noise as the foil edition
please
did you look at basegame files
Thankss
I was told to stop in here to ask how to mod this game
oh i have to hook card eval status effect waht if i dont do that and just make it play another sound on top 😭
how do i add a joker when a run starts?
Just giving random ideas here, not at PC, but maybe you could return a sound variable along with the message, or a func with play_sound in it?
is this supposed to be done by default with a mod installed or with a certain feature on?
if it's as a part of a deck, check documentation for SMODS.Back
function SMODS.current_mod.reset_game_globals(run_start)
if run_start then
local my_joker = SMODS.create_card{set = 'Joker', key = 'my_joker'}
G.jokers:emplace(my_joker)
card_eval_status_text(my_joker, 'extra', nil, nil, nil, {message = "my joker Added!"})
end
end
Can someone help me with galdur?
Is a this code needed for self made mods like mods you arent planning to share?
"name": "BalaQuints",
"id": "BalaQuints",
"prefix": "quints",
"version": "1.1",
"badge_colour": "40C040",
"dependencies": ["malverk (>=1.1.3~)"],
"main_file": "main.lua",
"description": "Retextures the legendary jokers in the theme of Go-Toubun no Hanayome!",
"author": ["Lumine"],
"website_url": "https://github.com/Luuumine/BalaQuints"
}```
That's needed for all mods.
ok
Uhhhhhhhhh i dont think that's a pair, game
Yeah it contains the information required to actually load your mod
oops
Ik what's causing it but this is rly funny to me
How would I check the enhancement of a selected playing card?
SMODS.has_enhancement(G.hand.highlighted[1], "m_modprefix_key")
Thanks!
in the code for Glass Joker (at least on vanilla remade), there's a check to see if Hanged Man is being used because it can destroy cards. I have a few of my own consumables that destroy cards in hand, and I tried to add it to this check, but it didn't work. Here's the relevant code:
if context.using_consumeable and not context.blueprint and
(context.consumeable.config.center.key == "c_hanged_man" or
context.consumeable.config.center.key == "c_tboi_r_devil" or
context.consumeable.config.center.key == "c_tboi_r_hanged_man" or
context.consumeable.config.center.key == "c_tboi_r_moon" or
context.consumeable.config.center.key == "c_tboi_r_star" or
context.consumeable.config.center.key == "c_tboi_r_sun" or
context.consumeable.config.center.key == "c_tboi_r_world") then
-- We need to run this code for anything that can potentially destroy cards in hand
local glass_cards = 0
local temp_hand = {}
for _, playing_card in ipairs(G.hand.cards) do temp_hand[#temp_hand + 1] = playing_card end
for _, removed_card in ipairs(G.hand.highlighted) do
if SMODS.has_enhancement(removed_card, "m_glass") then glass_cards = glass_cards + 1 end
end
if glass_cards > 0 then
card.ability.extra.Xmult = card.ability.extra.Xmult + card.ability.extra.Xmult_gain * glass_cards
return {
message = localize ({
type = "variable",
key = "a_xmult",
vars = { card.ability.extra.Xmult }
})
}
end
end
even though I rewrote the code to find which cards get destroyed in my own way, it still works for the Hanged Man, so idk what I did wrong
if it works for hanged man still, wouldn't that imply the key for your consumables aren't matching?
I thought that too but no, the only difference that my consumeables seem to have is that you don't select the cards that get deleted, the same way you don't select the ones for Immolate
I have no clue, sorry
well here's the thing
after saying that I tried immolate, and it doesn't update glass joker either
so I'm gonna have to reprogram immolate too lol
or at least take ownership of its use funciton
Isn't that a known bug that Immolate doesn't trigger glass joker?
guess I just discovered it for myself lol
lol that would make sense I reckon if yours work like Immolate.
I suppose I can wait for the game to get patched so I don't have to do it myself, I'm gonna be working on this for months anyway
https://balatrogame.fandom.com/wiki/Bugs
Looks like glass joker doesn't interact with any of the card destroying spectrals
Could someone help me out with this joker? Trying to make stone cards bypass the card selection limit.
calculate = function(self, card, context)
if context.cardarea == G.play and context.main_scoring then
local stone = 0
for i = 1, #G.hand.cards do
if SMODS.has_enhancement(G.hand.highlighted[i], "m_stone") then
stone = stone + 1
end
end
SMODS.change_play_limit(stone)
SMODS.change_discard_limit(stone)
end
end
this is a super jank solution but you could temporarily make them negative and then take the enhancement away after lmao
you could look into the code of The Serpent on vanilla remade to see how they add excess cards to your hand
Doesn't negative just affect hand size on playing cards?
ohh card selection limit mb
What is it doing/not doing currently?
Well, this code I have does absolutely nothing as far as I can tell.
would the intention be for it to modify the limit when a stone card is selected or just by the amount in your drawn hand?
bump bump
When the card is selected.
also, I think this code implies that your selection size will be increased for each stone card in hand, right? so could you select 6 cards not including any stone?
crash says the audio does not exist, what did i do wrong here 💔
maybe try to change it so that when a stone card is selected, THATs when your selection limit changes
So, just to ensure I understand, lets say I have a hand size of 8, selection limit of 5. I have 3 stone cards and 5 other cards in hand. I select the 3 stone cards, and my selection limit increases by 3, to 8, so I can then select my entire hand?
Yep
What would i write here ||I've never modded before|| code referenced from https://discord.com/channels/1116389027176787968/1341041293119459449
wtf why are you jumping into animations as your first task
cuz i wanted to make showman into tenna from deltarune plus i want to do something since im unemployed
So, to start,If I understand it correctly, I believe the context.main_scoring is too late for what your trying to acheive, because the hand is played by that point.
pain for pleasure wtf
i reccomend maybe doing a bunch of other jokers first
preferably not animated
Yeah, that sounds right, I'll remove that
Assuming its not doing that currently?
yeah :'(
holdo n one second
okay so if this hand contains a seven its supposed to destroy entire hand and create one random joker per seven destroyed
alright
Not sure what context is correct for you, but from what I can see on the wiki, context_pre_discard is probably the closest. I'm just not sure if that triggers on card selection or after pressing discard.
after pressing discard
Thats what I kinda assumed. Is there a context for them that triggers on card selection?
context.debuff_hand and context.modify_scoring_hand both do iirc
^@wild escarp maybe start with those
Is it possible to have multiple edition shaders drawn on one card at the same time?
bump
Yep, debuff_hand got it!
So, if you have no jokers and play a hand of 5OAK 7's, it should destroy the 7's and spawn 5 jokers?
yes
but if you play two sevens and three fives it destroys the sevens and the fives and spawns two jokers
If it contains only one 7, it should still destroy the entire hand, but only spawn one joker?
yes
Okay, I understand
Yes but it won’t look good
Everything is drawn with shaders, so if they don’t have an alpha value of < 1 they will cover what’s underneath
Is there something I can check for unhighlighted cards?
If you were wanting to modify play size on clicking a card, I’d hook Card:highlight
I have it upping the card selection limit, it just doesn't go back down.
You can do that in the hook too
If I want to check if a card is on the jokers, what would be the call?
I can think of a rondabout way, wich is iterating through the jokers and checking if any of them equal [card], but I assume there is a easier way @w@
next(SMODS.find_card("j_modprefix_key"))
So I don't think I can give you a full answer, because I have not played with spawning jokers but I can give you my experience from earlier on identifying and destroying cards. My instance, I was trying to destroy card when there was a singular unscored card in hand. As I understand it from my earlier experiments, context.destroy_card triggers for each individual card in hand. I think I'd look at doing your logic for checking for the amount of 7's (if any) in hand in an earlier context where the full hand exists, make note of the check with a flag variable. Then in context_destroy_card, as long as your flag is present, mark that card for destruction (since you're destroying all cards anyway). Then maybe in some final context handle your joker spawning based on determined number of 7's from original logic. That is how I'd approach it.
guys guys
I have heard feedback about my jokers
so i changed them
thoughts?
Whats the purchase price of a rare cocktail?
capitilize Ethereal Tag and Charm Tag.
its normal prices, 3, 5 and 8
with half sell value its 2, 3 and 4 cost
(with available space)
which means it helps except in late game
what is happening dude 💔
which i think is balanced
Sound good to me
Where is the file stored
Also if we're doing feedback
How does this UI look
is it maybe a little too cheap?
I have a file loading system that shows the errors instead of crashing
maybe the rarity compensates
fire
Nah, once you mentioned the sell price with the rarity, I think its good
awesome
:D
isn't it looking for it in resources/sounds/ not assets/sounds
8$ is the price of the big spectral pack btw
But you get the sell value of the joker back, that was my initial thought too
EZ OMG
play_sound needs the mod's prefix
It's not actually
This seems to be the correct location
I'm getting a bug where simply scrolling to page 8 while in a run is crashing the game. I took ownership of a couple of Jokers on page 8, but nothing crashes unless I'm in a run, on the main menu its fine
sells at $4
so its $4 for a spectral pac
Mhm
What sorry?
if i didn't need to specify the folder in joker atlas why should i on sound atlas,,
im very impressed by your ui skillz
"play_sound('xmpl_e_padres')" like this?
I haven't played with sounds, I just was looking at the file path in the crash screenshot. I'll bow out to others with more knowledge
Here’s on of my latest works
1 in 2 chance to copy the right joker at the start of the round
Otherwise copy a random joker because she’s moody
if xmpl is your mod's prefix yes
but also you should change it to something more unique
Love the artwork!
wdym
Thanks 💗
This is the first ever piece of UI I created 💀
can it copy itself?
xmpl is used by example mods so a lot of other mods might have the exact same prefix, you want a different one
And make a loop that crashes the game ? Yes
Is it possible to change badge size?
👏 amazin
you need to fix that loop
I imagine
crashing the game is bad
oh
I'm proud of the end result, it even supplies the full traceback that you'd get with a crash
nice
I've also made the same thing but for when a card causes an error
I can keep it and add a warning for fps drop lmao
How would i check if a joker is being added or removed from my joker slots in a hook of Card:add_to_deck and Card:remove_from_deck? self.area == G.jokers does not work.
what a tsundere
google it
Ikr ahahahaha
eh, im pretty new at this so i think it works better for using example mods as reference you know,,
i think thats a check in the context.
This worked like a charm btw!!! Main issue now is limiting status text messages
i dont have context its a hook
fok
the mod's prefix is just a string, it doesn't have any influence on the code quality lol
just pick something random
ohh i see
make it as long as possible
It's not about the size of the prefix-
also make sure its unique (mainly that means cry is taken)
I just made mine the name of my mod cos why not
use only prefixes that are already in use
and make sure the items within the mod use the same keys as those form other mods
to ensure collsions and bugs
joy is also taken
no more joy
You should actually do that for a mod
Balatro modding in a nutshell
Is it a content mod that utilises the prefix tho
Then make a content mod with it to make crossmod a pain :D
okay so is dollar buffer / joker buffer how many times the extra dollars/ extra jokers triggers?
four is good, five is pushing it, six should be banned
does anyone have a mod with the prefix "yip" already?
because dollars and jokers are added in events usually, you need to have a temporary buffer so other cards can check total dollars/jokers before the event gets called
mine is PNMH
from "panama hat"
sounds cool to me
where can i see the setup for set_sprites?
anyone know why this patch doesnt allow alternate atlas use with set_ability?
wdym
not yet iirc
"local jokers_to_create == context.full.hand[1]:get_id() == 7
Can i get some help, this for some reason isnt increasing the number
calculate = function(self, card, context)
if context.cardarea == G.play and context.main_scoring then
if card:is_suit('Hearts') then
card.ability.extra.multgiven = card.ability.extra.multgiven + 1
end
end
if context.joker_main then
end
Is this an enhancement?
Joker
how do i make it creates jokers depending on how many sevens there are in yhadn
Change main_scoring to individual
are you trying to count the number of 7s in hand?
yes
I ask because of this:
JESUS
quantum editions testing?
Yes.
you should loop through the hand and increase a counter every time a card is a 7
yea, this still doesnt update the number
SMODS.Joker {
key = "Ral",
loc_txt = {
name = "Ralsei",
text = {
"This joker gains {C:mult}+2{} mult per {C:hearts}heart{} suit played",
"{c:inactive}(Currently {C:mult}+#1#{} mult){}"
}
},
config = {
extra = {multgiven = 0}
},
loc_vars = function(self, info_queue, card)
return {
vars = {card.ability.extra.multgiven}
}
end,
atlas = "JevilArt",
pos = {x = 0, y = 1}, -- This will be animated
rarity = 2,
cost = 6,
blueprint_compat = false,
eternal_compat = true,
perishable_compat = true,
calculate = function(self, card, context)
if context.cardarea == G.play and context.individual then
if card:is_suit('Hearts') then
card.ability.extra.multgiven = card.ability.extra.multgiven + 1
end
end
if context.joker_main then
end
end,
ohgod, its more code than i thought
Change card:is_suit to context.other_card:is_suit
i dont know how to do that😭
thank you
local count = 0
for k, v in pairs(context.scoring_hand) do
if v:get_id() == 7 then
count = count + 1
end
end
```?
does anyone know how i could go abt making a joker that makes all other jokers equally likely to spawn regardless of rarity
thank you so much
Try looking at Deck of Equilibrium from Cryptid
is there a bool to tell if a card object is flipped
card.facing == "back"?
What is SMODS.Center?
Is there a way to instance some retriggers to be different from other sources of retriggers?
What is the goal?
We have a card enhancement that has a mult bonus, and are trying to make a joker that retriggers any scored card with that enhancement, but the retrigger only gives half the mult bonus
Then yes.
Where are the built-in ability evaluation keys handled? I.E. chips, mult, x_mult, etc
I only see it for playing cards specifically, not jokers
SMODS.calculate_individual_effect?
No yeah, that's what I mean
The only place I see chips, mult, etc scored for anything here is for playing cards
okay im still havbing one issue
how do i make context.full_hand[1] be all of the ranks of a hand
would i have to do the same thing over and over but with the numbers increasing
You want the first card played to have multiple ranks?
no
i want to check if hand contauins a certain card
but i dont want to trigger each event indivisually
@formal parrot This is what i have so far (since it was dev help i figured I should post it here and @you)
i alkso want to destroy all cards in hand if it contains a seven
Card here would refer to the joker and not the played cards
if context.destroy_card and (context.cardarea == G.play or context.cardarea == "unscored") then
for k, v in pairs(context.full_hand) do
if v:get_id() == 7 then
return {remove = true}
end
end
end
yeah i know i need to edit the event as it doesn't work
Also you don't nest those context checks
Just put them all in one if?
im very much a newbie, does that refer to them all using seperate if thens?
final_scoring_step shouldn't be inside context.individual
they will never happen at the same time
I took ownership over Driver's License, and rewriting its loc_vars like this causes the driver_tally to not update properly:
loc_vars = function(self, info_queue, card)
local driver_tally = 0
for _, playing_card in pairs(G.playing_cards) do
if next(SMODS.get_enhancements(playing_card)) then driver_tally = driver_tally + 1 end
end
return {
vars = {
card.ability.extra.Xmult,
card.ability.extra.driver_amount,
driver_tally
}
}
end
this is taken from Vanilla Remade, so idk whats wrong
also the calculate works just fine despite using the same code, its just the description that;s not updating
Where should the event be to trigger then? (im aware the event code itself is incorrecct, im gonna try and fix that soon)
Do you wanna flip the joker or playing cards ?
The playing cards, specifically scored jacks and kings
You can do
For i=0 , #Context.scoring_hand
And
If Context.scoring_hand[i]’s id is jack or king
No, lua starts indexes at 1 and lua is case sensitive.
Context.scoring_hand[i]:flip()
My bad
I didnt code for a while lol
And the change its suit
I mean rank
And then reflip it by doing the same function
Should work
so
I should run the card rank change inside an event as opposed to in the calculate function?
so that it flips, changes, flips back?
I think thats a way to do it
Or you can just make 2 events
Basically experiment , I’m sorry i’m not on my pc and its 3 am sadly i cant help more
Your ok lol
And i think
You should change ranks before scoring
Use context.before and cardarea==G.play
Individual is used for repetitions ,
whats the pixel size for the boss blind tokens?
34x34
Well the way ive written the joker is that scored kings and jacks become queens
would I have to use a seperate key for that since the one I currently have is 71 by 95?
and im not sure how to rewrite that if its better gameplay to change them first
Separate key?
My idea is you make a for to check every card’s rank in scored hand and if it’a a king or a jack flip it change suit and flip it back
Its your choice
You can do final scoring step if you want
this thingamajig
Yes should be changed
the way you have it now is more difficult to do the flip, and it will check the chance every time it's scored, so a king that scores 20 times will have a much higher chance than 1 in 4 to turn into a queen
The key is unique to any added atlas
You need to create new atlases for any new sprites you use
Its an almost gaurentee to become a queen, 1 in 3000 of not becoming one
I realised it kinda broke the theming to not use the actual rough stat for male calicos vs female
0.0003% chance is crazy
Sounded like estrogen pills for me lmao
anyway, you should do this in context.after imo
and if you do it in before the cards won't actually score as if they were queens, they will score as their previous rank
I know, i want it to flip after xd
Lol
Well they are meant to score as kings and jacks then become queens
Does changing ranks require an event
in that case do context.after
(context.before would make them look like queens while scoring as kings/jacks)
im using
if context.individual and context.cardarea == G.play then
if context.other_card:get_id() == 11 or
context.other_card:get_id() == 13 then
return {
assert(SMODS.change_base(context.other_card, nil, 'Queen')) }
to change them currently
no, it's not required
its in the calculate function
if you want to make it look good you will want to use them tho
otherwise it will just change abruptly
yeah thats what it does rn and i want it to look good
I think there’s a better way to do it
im open to suggestions
My idea using a for flips card one by one
And add another flip to make it look good
Probably should sleep lmao
Code wise hows that look
also yeah probably a good idea
Instead of individual use context.after
And make a for
There’s an example in the
Forgot
The name
……
if context.after then
for _, v in ipairs(context.scoring_hand) do
if v:get_id() == 11 or v:get_id() == 13 then
-- stuff here
end
end
end
Bloodstone !!! In vanilla remade
Bloodstone wouldn't use context.after tho
sap out my if context individual for this?
swap*
I’m talking about the for and the implementation of for
Yes
Put the flip and change rank in
—stuff here
Add an event
Basically
Context.scoring_hand[i]:flip() or v[i]:flip()
Since you’re using a variable in for :3
Test and come back if you have any problems
Also have a good night :>
night
when i place it into vscodium the lua script checker says that everything from the second if to the first end is an empty code block, any idea why?
hm ok deleteing and retying the v fixed it
odd
this joker is suppsded to destroy hand and spawn jokers depending on how many sevens there are if a seven is played
but when i play a full house with three sevens it creates 15 jokers
Behold my sadism at work
It's because you're checking for every card.
Could someone help me with this? I'd like this joker to effectively make stone cards playable without taking away from other card selection. (Allowing flushes with stone cards). However, any card selecting/deselecting with a stone card selected makes the card selection limit go up, and it doesn't go down.
calculate = function(self, card, context)
if context.debuff_hand then
local extra_limit = 0
for k, v in ipairs(G.hand.highlighted) do
if SMODS.has_enhancement(v, "m_stone") then
extra_limit = extra_limit + 1
end
end
SMODS.change_play_limit(extra_limit)
SMODS.change_discard_limit(extra_limit)
end
end
how would i fix that
how would i change a cards spawn pool
like making planets appear in the other booster packs as well
You have to hook Card:highlight
You do the joker creating outside of the destroy_card context.
how would i go about creating a sticker that has the same effect as negative? (without the shader)
Looks like nothing in there deals with playing cards and card selection limit, so I don't know how it could be useful.
@normal crest Would i need to put anything in the return field then, if i do change.base within the event
youd have to hijack the check for if you can select a card and change it based on stone cards
you don't return anything here, unless you want to show a message
and if you do, you do it outside the event
would yall help me in changing certain cards spawn pool?
it doesnt sound very complicated to implement but im not sure how to do it
What is the goal?
i have a deck that makes rare jokers have a chance to appear in the other booster packs
thats the goal
how do i set up a config for a mod?
can you define the order in which the decks are displayed?, like adding decks between the vanilla ones?
i believe so because i think cryptid does it
@normal crest sorry to bother again, what context should i be using for the first flip again?
within the event
I checked and cryptid doesn't do it
Yeah, sorry, I have no clue how to use this.
Can anyone tell me how to use card:flip() to flip certain playing cards
putting the method inside of an event seemed to do it for me
What exactly is the method used? The wiki has like no mention of card:flip at all
No need for any more context checks
you just do the flip inside the event
its <variable>:flip(), where the variable name is whatever you have the card as
ive spent the last 30 minutes trying to figure out how to do this
it needs to be a card object. So for example, to flip a played card, you could do:
context.scoring_hand[i]:flip()
and that would flip the card you want
So if i want to flip scoring jacks and kings, what would I use? (sorry if i come off as really dumb, im just new to this)
okay os this joker uis syuppsoed to discard all cards in hand and give one joker per seven played if a seven is played
but instead of making one joker per seven its making 15 joker for a hand of 3 sevens
Something like this:
for i = 1, #context.scoring_hand do
local _card = context.scoring_hand[i]
if _card:get_id() == 11 or _card:get_id() == 13 then --11 is Jacks, 13 is Kings
G.E_MANAGER:add_event(Event({
func = function()
_card:flip()
return true
end}))
end
end
note that this only flips the card ONCE, so it will be facing down. you can add youre other functionality in between the flip and the return statement.
also, don't feel dumb. We all start somewhere 🙂
BUMP
So do I need to do card:flip again after my functionality, or does the return stement flip it back?
or do i need another event
you need to do it a second time. The return statement just returns true for the inner function, it doesn't really do anything to my knowledge but I always see it at the end of functions that are made for the event manager
bump
from what i read in the wiki it stops it from triggerin on the next event again, just asked to make sure
what exactly is the issue you're facing?
when i play a hand containing a seven it makes way more jokers then its supposed
its supposed to create one joker per seven in hand
instead it creates what i think is hand size times seven amount
not sure if this is how it works in Lua, but first I'd make sure the indentation matches the structure of your conditionals
i dont think that affects the code it just makes it easier to write and reas
wghich tbh i dont care about too muhc
Are your contexts correct? Because it's supposed to discard every card in hand, then create a Joker for each discarded 7, correct?
itys supposed to destroy every card in hand
but yes
if you're destroying lots of cards at once, and you only care if they are sevens, could you do
context.destroy_card and context.cardarea == G.hand and context.other_card:get_id() == 7 or something like that
Ok im getting an crash caused by my .change_base code but ive forgotten what i need to do for it to not crash, any ideas?
if you already have a loop to find the Jacks and Kings you won't need a second one btw
but if you want to change them into queens you can use this:
local suit_prefix = string.sub(_suit, 1, 1).."_"
_card:set_base(G.P_CARDS[suit_prefix.."Q"])
assuming you just want to change the rank, not the suit
wait hang on
dont use that lol
oki
other card not deifned
assert(SMODS.modify_rank(G.hand.highlighted[i], -1)) for Kings
assert(SMODS.modify_rank(G.hand.highlighted[i], 1)) for Jacks
there's probably a better way lol but thats all I got tbh
those lines go between the card flips?
yeah
and do i delete the change for them into queen?
what does the Joker do? Is it supposed to mess with Queens at all?
bc if not then yeah, just replace what you have between the flips
It turns scored jacks and kings into queens
make sure to add a conditional so that you change the ranks of Jacks and Kings properly
with a 1 in 3000 chance to not do ( Calico fun fact, 1 in 3000 are male)
once again, dumb newbie, how do i do that tvt
local _change = -1
if v:get_id() == 13 then
_change = 1
end
assert(SMODS.modify_rank(G.hand.highlighted[i], _change))
something like this should work to change them how you want
put this in between the flips
actually thats backwards lol, the 1 should be first and -1 second
sorry
easy change lol
not sure then, sorry
hmmm when it should trigger im getting a attempt to index local 'card' a nill value crash
code.?
got it?
no, thought i did
reading a diffrent persons response to the same error it seemingly comes from v being undefined
if context.after then
for _, v in ipairs(context.scoring_hand) do
if v:get_id() == 11 or v:get_id() == 13 then
G.E_MANAGER:add_event(Event({
func = function()
_card:flip()
local _change = 1
if v:get_id() == 13 then
_change = -1
end
assert(SMODS.modify_rank(v, _change))
_card:flip()
return true
end}))
end
end
end
ok if this one fails I give up on coding
I just wrote the whole thing lol
this one in particular
why does this loop after each round and not based off number of jokers?
so ittl be v:flip instead of _card:flip
ye
same error but with v now
i think its because v is undefined, should i copy that persons definition fo v
and if so where should i place it
v comes from the loop, idk why it doesn't work. My bad
well if anyone knows how to fix this, i would appreciate
replace _v with v
ok it works!
but
can i have it pause the discard long ennough for the flip animations to play
cuz the flips occur at the same time rn
idk
that's the part I never got the hang of tbh, I got the flipping to work but the delaying part is tough
what you could do is have multiple events, where they flip the cards individually and you put delay in between them. You can look at the VanillaRemade for the Strength card if you want examples
ok so it seems like delay just doesn't work in my code
for testing i just yoinked the bit of remade strength that handels it
and theres no change
yeah, like I said I never got the hand of that bit. sorry I wasn't much help
Your good
the discard animations are an event tho right?
if so delay should work
afaik
or wait
delay just delays the event
not the event after it
is there any vanilla joker that does something to cards after scoring but before discad?
is there a vanilla remade file for glass cards and the other enhancements?
I'd probably still just use context.after
is it possiblr to do context.after a context and also context.before another context
cuz then i just need the context for discarding
How can I check if a particular joker is owned?
@grim stirrup any idea?
if next(SMODS.find_card("j_<modprefix>_<joker-key>")) then
What are the correct .UIT values for "hand_mult_area", "hand_mult", and "flame_mult"?
ok whar was i talking about lol
that isnt how those things work lol
How would I go about making vfx
Like if I wanted to change the brightness of a card for an effect
for anyone who might know what to do, im basicaly wanting to pause the discard untill the flip animations are done
also looking at remade glass im not seeing how its break supposed to trigger before discard at all
like i know thats what it does
but i dont see how
hi anyone has code for this kind of description?
what elemetnt of the description :?
ah
im new but description wise im pretty sure you just need to asign them values in config, not sure how your supposed to update those values tho
take a look at the vanilla remade jokers
yeah i was doing that but they dont seem to have description text
thats why i asked here
ahh
Description text for that is all stored in the localization folder.
while chat is active again, anyone know how glass cards breaking trigger before discard?
i need to do simliar behavior but for running a flip animation
VanillaRemade uses context.cardarea == G.play, maybe that's what you're looking for?
that just checks to make sure the card is one of the played ones
need to find a way to pause the next event in the event queue
bump
Wouldn't that context make everything inside it run during that dedicated time? I don't know exactly how all the contexts work.
ok in theory adding blocking = true should allow the event to work but im assuming the discard is labled as unblockable
how would I make a card like Medium (but for a different seal)
I cannot get consumables to work
id assume you can look at remade medium and just change the seal it uses? (along with any other information)
where is remade medium?
like where do i find it
loc_vars = function(self, card, info_queue)
return {
vars = {
card.ability.extra.mult,
card.ability.extra.mult_mod
}
}
end
is there something wrong with this loc_vars
I always do (self, info_queue, card), but I don't know if the order matters.
ok actually, how do you use the queue argument front
the wiki mentions it
but theres no example
instead of doing G.E_MANAGER:add_event(e) you do G.E_MANAGER:add_event(e, nil, true)
the relevant code in the game is simple enough
before i make the edit, would putting my event at the front of the queue make the flip animations play before the discard? for context I need some cards after being scored to then get flipped and then discarded
i don't think so, this will likely make them flip before they're scored, unless steamodded lets you manually trigger scoring and what happens on each step of it
i've never used smods, only modded the game through lovely so im not sure, and i would recommend u just make the edit and see what happens
got given a nil value crash when it shud have triggered :/
heres current code
everthing is correct except the flips happen during discard
instead of befroe
i have a suggestion that might be terrible, adding an event during context.before (if that's a thing) then checking inside the event if context.after to trigger the flips and having the event's func return context.after instead of true
context.before is only for effects that happen before scoring\
yes, during before you'll slot in an event that checks if we're after to do its work, and otherwise will fail (by returning context.after's value which is nil/false), failed events keep retrying until they succeed so only when context.after becomes true the event will trigger
that's assuming the context object stays alive / isn't cloned between scoring stages
this ensures you added your event to the queue early but it only executed after score calculation
(bypassing the need for the front argument)
maybe its because its late but im having trouble translating this out into actual code, would it be
oops
1 min
im having a hard time putting what's on my mind in writing too, if you could link me a dev branch ill make a PR demonstrating my point (and would like to test it myself too)
Oh i dont even have a github for this setup yet
hi! am i doing this properly? how does coloring go for these again? @w@
not even sure if ill make this a public mod yet lol, i do have an idea for a proper themed mod tho
but thats for later on
this aint the name of that joker lmao
i got confused lmao
i dont think ill be much help here but how on earth are you using a bright mode text editor(?) for modding
you can paste the joker in chat 👀
im disturbed
it's temporary
i'm installing
VSC
atm
ahh
SMODS.Atlas {
key = 'calico',
path = 'calico.jpg',
px = 71,
py = 95
}
SMODS.Joker {
key = 'calico',
loc_txt = {
name = 'Calico',
text = {
'When a {C:attention} King {} or {C:attention} Jack {} is scored',
'turn it into a {C:attention} Queen',
'{C:green} 1 in 3000 {} chance to not trigger'
}
},
rarity = 2,
atlas = 'calico',
pos = { x = 0, y = 0 },
cost = 5,
blueprint_compat = false,
calculate = function(self, card, context)
if context.after then
for _, v in ipairs(context.scoring_hand) do
if v:get_id() == 11 or v:get_id() == 13 then
G.E_MANAGER:add_event(Event({
blocking = true,
func = function()
v:flip()
local _change = 1
if v:get_id() == 13 then
_change = -1
end
assert(SMODS.modify_rank(v, _change))
v:flip()
return true
end
}))
end
end
end
end
}
but wifis bein a bitch
Hey
beginner coder here
im trying to have a joker do a simple 1.5x mult but the code's not working
any reason why?
what is the error caused
Not necessarily the problem, but you can condense your return table to simply be this:
return {
x_mult = card.ability.extra.Xmult
}```
This
can we see the config?
ok so i added blockable = false and now the flip happens before scoring
also realised for some reason its not showing the back of the card
This?
you're missing a }
replace the
Xmult = 1.5
to
config = {extra = {Xmult = 1.5}},
i think its ignoring the context for some reason, i tried changing it to .final-scoring-step
Pretend the dashes are underscores \
oh and consider changing the rarity to common/uncommon
how can it be a legendary when it only gives x1.5 mult
Planning on having it be summoned by another joker at the start of a blind twice
you can create a miscellaneous rarity
im having a hard time getting it to do anything consistently
just like how polterworx did it
I see some mods having xchips, how do I put xchips in my mod?
how so?
remove the two extra }
look at the code
What code
something like big cube from cryptid
The one's under config?
did that, still error
after {x = 0, y = 0} is missing a comma
do i need to put a comma after end
still
before end add a }
also i recommend you to add localization variables
loc_vars = function(self, info_queue, card)
return {vars = {card.ability.extra.Xmult}}
end,
loc_txt = {
name = 'Sheep',
text = {
'{X:mult,C:white}X#1#{} Mult'
},
unlock = {
'...' -- add the unlock condition
}
},
anyone know why exactly my cards would be flipping at the same time as they are discarded?
It just says xchips and that's it, it doesn't say how it's make
Where do i put this?
Does xchips already come on steammodded?
replace the loc_txt with this
and add the unlock condition
(delete all comments afterwards if you want)
?
So the xchips already comes with the steamodded itself?
tbh i wanna learn proper smods just to give joker mods proper forcetrigger support
That sounds fun actually
bump
how i make that someone help me
i think i did it correctly
The error msg doesn't lead me to think i messed it up
where is line 191
also replace the unlock condition with you originally had (or remove it completely if you don't have one)
the if needs an end
elaborate
got it working with this
SMODS.Atlas {
key = "calico",
path = "calico.jpg",
px = 71,
py = 95,
}
SMODS.Joker {
key = "calico",
loc_txt = {
name = "Calico",
text = {
"When a {C:attention} King {} or {C:attention} Jack {} is scored",
"turn it into a {C:attention} Queen",
"{C:green} 1 in 3000 {} chance to not trigger",
},
},
rarity = 2,
atlas = "calico",
pos = { x = 0, y = 0 },
cost = 5,
blueprintcompat = false,
calculate = function(self, card, context)
if context.cardarea == G.jokers and context.joker_main == true then
for _, v in ipairs(context.scoring_hand) do
if v:get_id() == 11 or v:get_id() == 13 then
G.E_MANAGER:add_event(Event {
blocking = true,
func = function()
v:flip()
local _change = 1
if v:get_id() == 13 then _change = -1 end
assert(SMODS.modify_rank(v, _change))
v:flip()
return true
end,
})
end
end
end
end,
}
note that i changed the atlas to .png, undo this to avoid a crash
use this for calculate: ```lua
calculate = function(self, card, context)
if context.joker_main then
return {
x_mult = card.ability.extra.Xmult
}
end
end
is this the intended behaviour?
yes, but it should be showing the card back before showing that its a queen
It works!
ohh, then you need to schedule the second flip in a new event
but thats a seperate issue to the one we wanted to fix
gotcha
and probably make the event type after with a delay
would it be a duplicate of the first event or just an event with v:flip and the delay
not very sure tbh, i tried this but it didn't really work, im not sure if it even slowed down the animation
but i'd recommend sth like this, with a larger delay and maybe the game on 1x speed
to see if it make any effect
bump
No card back showing with a delay of 2
so i think it doesnt change anything
i think i saw someone with a simliar problem earlier today
but i cant remember the contetns of the messge to look it up
also don't forget the 1 in 3,000 chance to fail
how would I apply an enhancment to a card?
All the ways I can find do not seem to work
im playing with sth like this
SMODS.Atlas {
key = "calico",
path = "calico.jpg",
px = 71,
py = 95,
}
SMODS.Joker {
key = "calico",
loc_txt = {
name = "Calico",
text = {
"When a {C:attention} King {} or {C:attention} Jack {} is scored",
"turn it into a {C:attention} Queen",
"{C:green} 1 in 3000 {} chance to not trigger",
},
},
rarity = 2,
atlas = "calico",
pos = { x = 0, y = 0 },
cost = 5,
blueprintcompat = false,
calculate = function(self, card, context)
if context.cardarea == G.jokers and context.joker_main == true then
for _, v in ipairs(context.scoring_hand) do
if v:get_id() == 11 or v:get_id() == 13 then
G.E_MANAGER:add_event(Event {
blocking = true,
blockable = false,
func = function()
v:flip()
local _change = 1
if v:get_id() == 13 then _change = -1 end
assert(SMODS.modify_rank(v, _change))
G.E_MANAGER:add_event(
Event {
blocking = true,
trigger = "after",
delay = 0.1,
func = function()
v:flip()
return true
end,
},
nil,
true
)
return true
end,
})
end
end
end
end,
}
but it crashes the game 👍
lol
currently reimplementing the psuedorandom that got lost in the chain of telephone that it has been to code this joker
getting an odd syntax error in vscodium
How do you access the full UI tree given a UIBox? I tried using .UIRoot.nodes but that seems to error
ok done
back to the card back problem
@night juniper this person has roughly the same second event as I have, and it worked for them so not sure whats up
SOLVED IT
one is "before" and the second is "after" while you code I think has one as "immediate" and the second as "after"
i just had to make the second event unblockable
can someone help explain to me how if next(SMODS.find_card('j.egg')) then [...] always seems to return false regardless of if the player has an Egg, but if SMODS.find_card('j_egg') then [...] is always true? trying to get the length of the find_card table and checking against that doesnt seem to work either, as well as checking if the table ~= {} and ~= nil
(yes im kinda new with lua sadly)
hmm did just realise they flip before scoring tho
no they flip after
completely new to modding, how would i go about adding a joker card to the mod
with this code
i already know about SMODS.Atlas
notice that i used the joker context instead
i think a side effect of making the second unblockable is that it triggers early for some reason
i might try adding more delay
it would do this if you added it to the front
if you still have nil, true there omit it
no nil, true,
not sure why its getting put at the front
i just want this to work like it should tvt
How do I make a spectral/tarot card apply an enhancement such as steel? I can't find any way to make it work.
btw a flip without a pause is what happens with death and strength
so maybe not fighting the game's design conventions is just better
maybe reading how death does this and copying its code verbatim is the best approach🤔🤔
ill check it out
aside from the strength function only stuff and then my own function stuff, the flip is how mine is
two seperate events
with a target
ok ive tried a few more things and am just not getting anywhere, is there anyway to practically use an if statement to check if the played owns a given card?
The first way you have is correct but you have a . instead of a _ in your key
ah heck.
its 3a where i am, my eyes cant see the difference and thats the story im sticking with 
ty ty
Hello everyone, does anyone know the code for creating consumables like the tarot card “The Empress”?
If you want to find the code in the game engine balatro.exe in .lua, which one is it? Thank you.
in the game archive it should be in card.lua iirc
steamodded allows for the create_card() call though which is a bit nicer
i see
i have a style recommendation for this, instead of nesting your logic inside if statements, use ifs with early return as guards, so sth like
if pseudorandom(..) == G.GAME.probabilities.normal then return end
this will allow you to have all cancel conditions listed clearly at the top of your function and the actually relevant code separated below it with no unnecessary indent levels
ill probably do that once i fix this
_ _
maybe try looking at code for justice, lovers, etc?
I have but it doeasn't seem to work
I'm trying to use card:set_enhancement(card.ability.extra.enhancement) but it too does not want to work
It’s set_ability
...