#💻・modding-dev
1 messages · Page 643 of 1
yes
if the random number doesn't hit it's still gonna be false wouldn't it?
it needs to change state though
ah
if it doesn’t set debuff and it already has it will still be
what about the SMODS.debuff_card() function?
you should probably be using that
not that I think that’ll fix it
you should just be preferring smods apis
SMODS.debuff_card(card, debuff, source)
guessing source would be card.ability.extra.odds
like I said rusty with lua lol
okay what is actually happening
does it show the debuff at all but doesn’t act like it
or does it just not
oh yeah the context if statement needs to be both pre_joker and before a playing card is triggered
i am currently out so can’t reasonably make that for you
but one N’ has been hovering
notably main scoring does not trigger before the playing card does and therefore debuff should not work I think since it would be debuffing after
is it possible to add like a debug text somewhere
like to see errors in console that wouldn't typically crash a game
print()
do you have debugplus
yeah
cool
use print
you can use it even without but the lovely console is a bitch and a half to read
isn't lovely needed to mod balatro tho lol
yes
oh nevermind misread what u said
where should I put print()
in the if and else
ok
lmfao
you printed nothing
but also weird
like show me the code again
with the prints
if SMODS.pseudorandom_probability(self, 'e_ttv_bootleg', 1, card.ability.extra.odds) then
print()
card:set_debuff(true)```
gonna try this
same thing only this time when I hover over the jokers
wait I forgor to remove the old one
okay can literally anyone else help this guy please I literally can’t look up SMODS shit or anything
it's fine i'll tinker around
the print didn't work
i'm gonna just tinker with spaghetti code until something just works
use SMODS.debuff_card(card, true, source)
source should be a somewhat unique string
how do i get whether the cursor is over a ui node
G.CONTROLLER.hovering.target:is(UIElement)
i think
hovering over a ui node in an overlay menu
which kind of ui node
G.UIT.R
is there a reason
to make the colour change when hovered over
there's a config for that im pretty sure
hey
im looking for it
thanks
I'm trying to make a card that randomly gets a debuff and a buff at the same time but I can't seem to be able to do so without finding some sort of error anyone has any ideia in how to fix this
SMODS.Joker {
key = "nedd",
blueprint_compat = true,
rarity = 2,
cost = 4,
atlas = 'Joker',
pos = { x = 8, y = 3 },
config = {extra = { nedd_buff = 0, nedd_debuff = 0, chips = 400, mult = 50, xmult = 1.30, h_size = 3, hands = 1 } },
loc_vars = function(self, info_queue, card)
info_queue[#info_queue + 1] = { key = "fnaf_sprite_WIP", set = "Other" }
return { vars = { card.ability.extra.chips } }
end,
calculate = function(self, card, context)
local hand_size
local hands
local chip
local multi
local xmulti
local current_hand_chips = hand_chips
local current_hand_mult = mult
if context.setting_blind then
card.ability.extra.nedd_buff = pseudorandom('neddbuff', 1, 5)
print(card.ability.extra.nedd_buff)
card.ability.extra.nedd_debuff = pseudorandom('nedddebuff', 1, 5)
print(card.ability.extra.nedd_debuff)
while card.ability.extra.nedd_buff == card.ability.extra.nedd_debuff do
card.ability.extra.nedd_debuff = pseudorandom('nedddebuff', 1, 5)
print(card.ability.extra.nedd_debuff)
end
if card.ability.extra.nedd_buff == 4 then
hand_size = card.ability.extra.h_size
elseif card.ability.extra.nedd_buff == 5 then
hands = card.ability.extra.hands
end
if card.ability.extra.nedd_debuff == 4 then
hand_size = -card.ability.extra.h_size
elseif card.ability.extra.nedd_debuff == 5 then
hands = -card.ability.extra.hands
end
G.hand:change_size(hand_size)
ease_hands_played(hands)
end
if context.end_of_round then
if card.ability.extra.nedd_buff == 4 then
hand_size = -card.ability.extra.h_size
elseif card.ability.extra.nedd_buff == 5 then
hands = -card.ability.extra.hands
end
if card.ability.extra.nedd_debuff == 4 then
hand_size = card.ability.extra.h_size
elseif card.ability.extra.nedd_debuff == 5 then
hands = card.ability.extra.hands
end
G.hand:change_size(hand_size)
ease_hands_played(hands)
hand_size = 0
hands = 0
chip = 0
multi = 0
xmulti = 0
end
if context.joker_main then
if card.ability.extra.nedd_buff == 1 then
chip = card.ability.extra.chips
elseif card.ability.extra.nedd_buff == 2 then
multi = card.ability.extra.mult
elseif card.ability.extra.nedd_buff == 3 then
xmulti = card.ability.extra.xmult
end
--- debuff
if card.ability.extra.nedd_debuff == 1 then
if (current_hand_chips - card.ability.extra.chips) <= 0 then
chip = card.ability.extra.chips - (current_hand_chips - card.ability.extra.chips)
else
chip = -card.ability.extra.chips
end
elseif card.ability.extra.nedd_debuff == 2 then
if (current_hand_mult - card.ability.extra.chips) <= 0 then
multi = card.ability.extra.mult - (current_hand_mult - card.ability.extra.mult)
else
multi = -card.ability.extra.mult
end
elseif card.ability.extra.nedd_debuff == 3 then
xmulti = 1-card.ability.extra.xmult
end
return {
chips = chip,
mult = multi,
xmult = xmulti,
}
end
end,
remove_from_deck = function(self, card, from_debuff)
G.hand:change_size(-1*hand_size)
ease_hands_played(-1*hands)
end
}
I was trying to implement something to stop the card into making the player's score go to the negative, but that failed.
And I had also placed something so that when I get rid of the card the effects are removed.
It kinda didn't work out.
crash log for when you remove the card
hmm no it doesnt seem to detect hover unless its an object or button
maybe you can make it a dummy button?
oh then its weird the first thing didnt work
can you add a func to it and check e.states.hover.is?
i know that Joker sprites are 71 by 95 but I think theres supposed to be an empty border around each sprite, right? like this?
yea
When I call this custom context, it kicks in immediately after "Play Hand" is pressed. How do I make sure it only happens when G.FUNCS.draw_from_play_to_discard() is called?
local old_draw_discard = G.FUNCS.draw_from_play_to_discard
G.FUNCS.draw_from_play_to_discard = function(e)
SMODS.calculate_context({LAPSEMS_after_played_hand_has_scored = true})
old_draw_discard(e)
end
it should only be called then
That means clicking the play hand button calls that function
Or it leads to it being called
For stuff that I want to happen after a hand has finished scoring, I have to put it in an event with trigger = 'after'. Is there any workaround to that, say, in the context definition itself?
the context would need to be called after the entire hand calculation and animations play
context.drawing_cards does that im pretty sure
I wanted a context that kicks in before the cards get carted away after scoring, which I don't remember context.drawing_cards doing. Here's what I want it for:
ah
alright what determines load order exactly. i thought these were doing that, but apparently they aren't sorting anything
thats context.after
you need an event
there's no real way around it
from what i see in the code you're loading the jokers in the order the files are in, which is 99% of the time alphabetical
i see
you can 1) instead of looping through the folder make a list of filenames and loop through that or 2) be lazy like me and add numbers to your filenames
alright if it's just the file names then that's doable
i can't believe somehow 11 comes before 1 so i have to put 01. that's so stupid
well thats is alphabetical lol
Bump this
me trying to use Balatro black and it gave me this
what
-# sorry
how can I make this work? Its supposed to be in pool only if you have a six-seven rank (yes, I know, I know), but it shows up in a standard 52 deck
how do i tell that a card is a playing card
May I have a playtester?
Also, the following bit of code isn't working
if context.yes_is_no == true then
if context.individual and context.cardarea == G.play then
G.GAME.xiferp_lineseven_xmult = (G.GAME.xiferp_lineseven_xmult or 1) + 5
local destructable_jokers = {}
for i = 1, #G.jokers.cards do
if G.jokers.cards[i] ~= card and not SMODS.is_eternal(G.jokers.cards[i], card) and not G.jokers.cards[i].getting_sliced then
destructable_jokers[#destructable_jokers + 1] =
G.jokers.cards[i]
end
end
local joker_to_destroy = pseudorandom_element(destructable_jokers, 'coronium_poisoning')
if joker_to_destroy then
xiferp_xif_x = joker_to_destroy.config.center.rarity - 1
print "card making time~!"
SMODS.add_card { set = "Joker", rarity = xiferp_xif_x }
SMODS.add_card { set = "Joker", rarity = xiferp_xif_x }
joker_to_destroy.getting_sliced = true
G.E_MANAGER:add_event(Event({
func = function()
joker_to_destroy:start_dissolve({ G.C.RED }, nil, 1.6)
return true
end
}))
end
end
end
if context.individual and context.cardarea == G.play then
if SMODS.pseudorandom_probability(card, 'c_xiferp_coronium', 1, card.ability.extra.odds) then
SMODS.destroy_cards(card, nil, nil, true)
SMODS.add_card({ key = 'c_xiferp_comykelium' })
end
end
end
}```
It's not accessing the "card making time~!" line
whats context.yes_is_no
It's what I use on occasion for delayed usage
also it should be print("your line")
well, the lines below it aren't working either
i think it's because it just can't run something if a line is broken and can't do anything past the line because it wants the line to be read
or smth like that idk
you might just wanna fix the line first tbh
they weren't working before I added the print line
Yea, line's right but still doesn't work
not that
key = 'bootleg',
shader = 'holo',
prefix_config = {
-- This allows using the vanilla shader
-- Not needed when using your own
shader = false
},
config = {
extra = {
odds = 1
}
},
in_shop = true,
apply_to_float = false,
sound = { sound = "ttv_fart_sound1", per = 1.2, vol = 0.4 },
disable_shadow = false,
disable_base_shader = false,
loc_txt = {
name = 'Bootleg',
label = 'Bootleg',
text = {
[1] = '{C:green}1 in 2{} chance to fail'
}
},
unlocked = true,
discovered = true,
no_collection = false,
get_weight = function(self)
return G.GAME.edition_rate * self.weight
end,
-- loc_vars = function(self, info_queue, card)
-- local new_numerator, new_denominator = SMODS.get_probability_vars(card, 1, card.ability.extra.odds, 'e_ttv_bootleg')
-- return {vars = {new_numerator, new_denominator}}
-- end,
calculate = function(self, card, context)
if context.pre_joker or (context.main_scoring and context.cardarea == G.play) then
if SMODS.pseudorandom_probability(card, 'e_ttv_bootleg', 1, card.ability.extra.odds) then
card:set_debuff(true)
else
card:set_debuff(false)
end
end
end
}```
tried the pseudorandom but error just says my local denominator is a nil value
card.ability doesnt work because its an edition and not a card
it chould be card.edition
well
its card.ability in collection but not in game
im pretty sure
I think i've tried that before in previous attempts i'll try again
does anyone know how to make it so you can make a tag out of another tag
i don't mean something like double tag where it makes a copy, i mean a tag that just makes a random tag (either just purely randomly or from a specific set of tags)
OMFG THANK YOU
3 hours
finally
it works
now to see if the odds actually work
bump
of the yes_is_no?
yes
i can almost guarantee its not a context
in the code of the rest of the card
actually lua has stringcalls so its technically okay???
that's not the issue line!
no it is
The issue line is it won't make new jokers
can you just show where the context is defined
im not seeing a context
so its not context.yes_is_no
it should be card.ability.extra.yes_is_no
you should try learning how to debug your code
you should also https://tryitands.ee sometimes because i can guarantee you that people wont find every single issue in your code immediately
bumping
({ key = pseudorandom_element({ 'c_xiferp_scandium', 'c_xiferp_gallium', 'c_xiferp_germanium', 'c_xiferp_technetium', 'c_xiferp_hafnium', 'c_xiferp_rhenium', 'c_xiferp_polonium', 'c_xiferp_astatine', 'c_xiferp_francium', 'c_xiferp_radium', 'c_xiferp_actinium', 'c_xiferp_protactinium' }, 'Prediction_Order' )} ) something like this, but with tags?
this should work
this is meaningless on its own
hardcoding every tag is also like not happening
yeah, Imma just work on my own mod
so where it says selected_tag is where the key for the tag would be right
sorry if this is like blitheringly obvious i'm just very tired right now
yeah
if i wanted to make it so it randomly picked like one of 5 tags how would i go around that
you can just skip the get_current_pool stuff then and do a pseudorandom_element on a table of the tag keys to get the selected tag
so here in the example code the table would go into
tag_pool
shadertoy is like the closest thing i think
or you can use debugplus watch shader which allows updating the shader in real time iirc
though i forgot how that command works exactly
have i put this in wrong or something?
I tried shadertoy but I gues i can't just copy paste the shader code into the website to get a visual version
wanna see if I can get a shader to look like this
to give that real bootleg stank
you put the code in the middle of a table
idk where you want it but it should be inside a function
Is there a way to make it where the message says +X mult?
(With X being replaced with the variable number thing)
message = localize { type = 'variable', key = 'a_mult', vars = { variable } }?
I'll try that, thanks
it says +nil, but it's progress
you need to replace variable with your variable
I used CardArea:handle_card_limit() to increase my Card-Area Limits, I noticed that the function has fundamentally changed and I'm unsure on how to increase/decrease Card-Areas correctly now... Any tips?
I used it to simply increase an Areas limit but I also used it to fill up 2 additional slots (Basically a Joker that uses both Joker-Slots and Consumable Slots)
wasnt it always just CardArea:change_size?
That's for simply increasing/decreasing the Total -> I can use that yeah
But what about the Extra-Slot thingy?
i think you need to hook CardArea:count_property and increase the return of extra_slots_used by 1 for the area the card is not in
what is this function called within?
I'm upgrading from 0827c and the function used to take parameters: CardArea:handle_card_limit(card_limit, card_slots)
yeah but whats the full context of the snippet you shared
That snippet is in the "Remove-From-Deck" function, and the Adding part is a conditional "On Blind Start"
I also have another Joker that used it like this:
-# Yes I know I commented out the wrong part in the remove-function
yeah, I think you should just use CardArea:change_size and word your effects accordingly
I'm gonna say it: I don't like that approach
Can I not edit the Extra-Slots used of another Area?
i mean
no, it'll be auto recalculated
I don't quite get why that was removed, it was honestly really nice to not just outright remove the slots :/
because it didn't work properly
well its fairly obvious it was not meant to be a public api, no?
stability is not what you expect
It not being public doesn't really count when I recall having been told to look at the code for things 
Like, I don't wanna be mean here, I was just really surprised that the functionality is gone x'3
Sadge that it didn't work properly, I'll change the Flavour of my Cards then :(
what's the problem with this
oh yeah you could do that
this works fine
it was honestly really nice to not just outright remove the slots :/
That's the reason! I like looking at the Top right and seeing1/2instead of0/1^^'
maybe there can be a G.GAME global for at least the vanilla areas to add this automatically
cardarea keys when
The handle_card_limit function or the change_size?
do you have N' blocked or smth
I am not that quick chill 😢
I mean, I already have some code to change the Visuals so that slots in nicely x3
Yeah that will work wonderfully, Thank you @red flower!
I think this would end up looking pretty jank
unless it was hidden with a permanent_properties table within the cardarea or something
makes sense
reposting, I'm trying to make a joker in pool if theres a specific rank in deck, but this code doesn't work?
the in_pool seems to be nested inside another function
ah
ill try fixing htat
i think i see what i did wrong actually
yep i found it
fixed now
Can somebody please tell me what's the context that checks if a playing card or card in hand is retriggered?
Not when a Joker is retriggered, only for when a playing card or card in hand is retriggered...
I don't think there's one but I might be wrong
Dang...
hey is there a mod which lets you add jokers into your joker slots for debugging?
thx
you can probably do something where you check if a card is triggered once, store that card ID somewhere, and then if a second trigger happens check it against the stored IDs and if it’s on that list, do something (and if not, add it to the list).
Then at the end of a round, clear the list.
how do i see what cards are highlighted WITHOUT knowing the card area
G.I.CARDAREA has a list of cardareas
i am sure you can figure it out from there
just loop through em
though like
Ehmm... I'll... see what I can do with that...
i'll never tell
tricky...
it should be fairly simple
assuming the right card trigger context is available
As of right now, I don't know how to store the Card ID...
how do you properly format a pattern for a patch file? new to it and it seems it never finds the line i give it no matter what i do
it needs to be the full line
also make sure you're checking Mods/lovely/dump instead of the vanilla files
because that's post-smods patches
ah ok thanks, yeah i search for the line i input in there and it got patched out
guys, how do you get the name of a joker 😭
the key of a joker is unique to the specific joker
you can get it from a card object with card.config.center.key, where "card" is whatever variable you have the joker saved as
thanks!
btw, is there a mod which has a pretty good example of hooking onto set ability? i understand the very general concept of hooking, but I want to attach an additional line after the calculate function of whatever I transformed the joker into
that or at least calculate from using the joker key
what's the goal exactly?
I want to make a joker which acts like the most recently bought joker
does it have to be the most recent you own or even if you sell it
even if you sell it
good luck
gl mate
yea that's gonna be tricky
meanwhile i havent played in a year and i IMMEDIATELY wanna come back to modding to revive a modpack i made which got wiped out when my computer broke
yatta
been spending a stupid amount of time just to have this without the copying part 😭
is there a way to save a joker in a variable without being lost when exiting?
or an object in general really
there is not
however, if you know the object will be saved somewhere, you can use a load function to restore the connection
ortalab has pinkprint, which is fairly similar (copies ability of most recently sold joker)
you can try to reference how it works, but it's really confusing from just a glance lmao
o, ill take a look
i was trying to read this to see if i could get somewhere 😭
I attempting to make my card description changes on the fly, but I have encountered a problem where it's simply isn't localizing the text, despite localizing stuff already in the games code, like k_plus_joker normally, any help?
SMODS.Joker {
key = "nedd",
blueprint_compat = true,
rarity = 2,
cost = 4,
atlas = 'Joker',
pos = { x = 8, y = 3 },
config = {
extra = {
buff_description = localize('k_plus_joker'), -- 1
debuff_description = localize('k_plus_joker'), -- 2
nedd_buff = 0, nedd_debuff = 0,
chips = 400,
mult = 50,
xmultplier = 0.70,
h_size = 3,
hands = 1
}
},
loc_vars = function(self, info_queue, card)
info_queue[#info_queue + 1] = { key = "fnaf_sprite_WIP", set = "Other" }
return { vars = { card.ability.extra.buff_description, card.ability.extra.debuff_description } }
end,
end
j_fnaf_nedd = {
name = "Nedd Bear",
text = {
"Gives a random",
"{C:chips}Bonus{} and {C:red}Debuff{}",
"when {C:attention}Blind{} is selected",
"",
'#1#',
'#2#',
},
},
misc = {
dictionary = {
k_fnaf_nobuff = "No Buff Selected",
k_fnaf_nodebuff = "No Debuff Selected",
fnaf_va = "Voicelines for cards",
fnaf_va_volumeslider = "Volume for voicelines",
},
}
which one u think is better
still trying to figure out how to add randomness to the single one
you can make both seperate commands, with the one wiping out the hand have a higher price or something
if I add them both I wanna make an opposite that adds random cards
trying figure that out that out
I got jokers
This code is adapted from Midas Mask, but even though it turns the last played hand into Stone Cards, it does so immediately with no animation. What must I do differently?
calculate = function(self, blind, context)
if not blind.disabled then
if context.after then
G.E_MANAGER:add_event(Event({
trigger = 'before',
delay = 0,
func = function()
if (G.GAME.chips >= G.GAME.blind.chips) then
local _,_,_,scoring_cards,_ = G.FUNCS.get_poker_hand_info(G.play.cards)
for _, scored_card in ipairs(scoring_cards) do
scored_card:set_ability(self.config.extra.mod_conv, nil, true)
G.E_MANAGER:add_event(Event({
func = function()
scored_card:juice_up()
return true
end
}))
end
return {
message = localize('k_lapsems_bl_mage'),
colour = blind.boss_colour
}
end
return true
end
}))
end
end
end,
does anyone know how to apply a custom sticker
(this gives me an error, even though my prefix is lemon)
card:add_sticker('modprefix_key', true)
thanks! so for me it would be card:add_Sticker('lemon_s_mimic') right?
add_sticker*
Yes.
sweet thanks
well
if they were already having an error
this shouldn't fix it
you can directly call it and it'll work
its just that the add_sticker does one other thing
but this shouldn't solve the error
also it calls the should apply functions and such
which may cause further issues if they are not defined correctly
though actually considering the nil checks the error should be "resolved"
why are you calling set ability with the key?
instead of the center
i saw someone else doing that- does it change anything?
well from my knowledge it shouldn't work?
the source code doesn't seem to handle it
from a glance
oh smods explicitly handles it
either way considering you have the center right there
no reason to use the key
Log?
what about this
calculate = function(self, blind, context)
if not blind.disabled then
if context.after then
local scoring_cards = context.scoring_hand
for _, scored_card in ipairs(scoring_cards) do
G.E_MANAGER:add_event(Event({
func = function()
if (G.GAME.chips >= G.GAME.blind.chips) then
scored_card:set_ability("m_stone")
scored_card:juice_up()
end
return true
end
}))
end
if (G.GAME.chips >= G.GAME.blind.chips) then
return {
message = localize('k_lapsems_bl_mage'),
colour = blind.boss_colour
}
end
end
end
end
wait i mispasted something
there
this is from using add_sticker
wait
no nvm i thought i realized smth
oh thats funny because the nil check should prevent that
ah
you are explicitly bypassing that check
explains why the error can even appear, then
but your sticker key is seemingly incorrect
i dont know how im bypassing it-
true is bypassing the check
you SHOULD be
its just its crashing since your key is invalid in some way
This immediately turns the cards to stone, not pausing to let them twitch, and doesn't show the localized message. I thank your attention, though.
huh
but its just prefix in json _ stickerid no?
it does for me
in the key
does it have to show a message for each
o
ok ill try keeping it smimic then
No, just the one.
ah its because i deleted something later, let me redo it
there, it broke when i moved the message
calculate = function(self, blind, context)
if not blind.disabled then
if context.after then
local scoring_cards = context.scoring_hand
for _, scored_card in ipairs(scoring_cards) do
G.E_MANAGER:add_event(Event({
trigger = "after",
delay = 0.7,
func = function()
if (G.GAME.chips >= G.GAME.blind.chips) then
scored_card:set_ability("m_stone")
scored_card:juice_up()
end
return true
end
}))
end
if (G.GAME.chips + SMODS.calculate_round_score() >= G.GAME.blind.chips) then
return {
message = localize('k_lapsems_bl_mage'),
colour = blind.boss_colour
}
end
end
end
end
Works like a charm. Thank you, N'!
yoo check it
how do i get :is_suit() to count debuffed cards of a suit?
:is_suit(suit, true)
alright, i do want to add a little polish, how do i start a flip animation?
G.E_MANAGER:add_event(Event({
func = function()
card:flip()
return true
end
}))
delay(0.5)
G.E_MANAGER:add_event(Event({
func = function()
card:flip()
return true
end
}))
or something
no why would it
kk
it might look jank as it flips a million times
i have a similar transformation thing in my mod and i removed the flip animation for that reason
o
noted
luckily (most) games you don't buy jokers that rapidly and in those amounts
Bump
alright what does it mean for the whole game to close out without a crash repor-
It means that code is running infinitely.
oh awesome
is misc nested
So I took the advice of throwing the addition into an event function. Still nothing happening.
I've tried every single context that would make sense (joker_main, after, and another one I forgot)
Try putting the event in an event.
Like this?
No, the second event needs to be in the func of the first event.
Ok, maybe I need to chuck an extra return true somewhere.
But that was hilarious to me that it kept adding
like i told you last time this happened, G.GAME.chips doesn't update until well after a hand finishes calculating, so on the first hand of a round you'll always just be trying to add 10% of 0 = 0
events will continuously re-run the function until it returns true, which is why you get the infinite behavior if you remove a return true
So I need a different approach to this problem?
.
Yeah, I'm gonna try that rn. Should have earlier, but had work and forgot the next day.
Well, the code works. It's adding the chips a little too early, but that can probably be fixed by using an event.
yea the event should get the timing done properly
GitHub needs a contributor thing so I can throw you on there for that code.
score modifications should be in context.after imo
it's a lot easier to work that way
Agreed, but I'm not a contributor to SMODS, so I'll take what I get,
I may be a contributor, but I still write my own function for that
then integrate it into calculation pipeline so that I can simply return something like {sgt_ascore = 300} to add 300 to score
how would i let other jokers know if a specific joker is in the joker area
you can check for other_joker.area == G.jokers
other_joker is a placeholder in this case
What exactly are you trying to do
something tells me just checking for "joker_b".area wouldnt work
im trying to make a joker thatll double the effects of specific jokers when its held
i was originally making it retrigger them but that wasnt working exactly how i wanted it to
so now im trying to add a check for that joker in each of those specific jokers' code
to double the actual values while its present
In that case, use next(SMODS.find_card('joker_key'))
what would be the code surrounding it? imm a bit rusty so im having trouble visualizing how exactly thatll work
is it in some specific context?
That code snippet would essentially act as a conditional
Hmm, I'm thinking about it more and it may be a lot more difficult to do what you wanna do than you might think because of edge cases
Plus I do not know the code you're working with
what edge cases are you thinking exactly?
i was planning to just put the check in the calculate function i already have set up to use twice the value than normal
That'll probably work actually
Or if you wanna get really fancy, you can do effect_value * (next(SMODS.find_card('joker_key')) and 2 * #SMODS.find_card('joker_key') or 1) to make it work with multiple copies
that could work for most of them yeah
this is the only one that im confused about.
and another one thats nearly the same code as this.
because i think i have to make it loop the whole thing
actuallyy
hm
might not cause issues?
i wrote this code a while ago i apologize
i wanna come back to balatro modding but i havent done that in like a year and all my stuff got wiped out
as the most washed person in this chat how do i start
step 1 is to think of what youre gonna make
the worst mistake you can make is starting without a plan
Luckily there's actually a pretty well put together guide now
#1349064230825103441 message
well i'm gonna revive the project i had which got wiped out a year ago. i was gonna make vocaloid song jokers because. oh wait im not "furret the miku fan" here anymore god da-
i alr have like
half? of the arts
still remainng
and i still remember all the jokers i implemented
i had 12 back then :(
this is why you keep your stuff backed up on github or something similar
yatta
quick question, would this count blueprint too if it copies that joker
Yes
i have no reason to not make it blueprint compatible then
how do i find the blind of the current anti without being within the blind
That was in response to this btw
No, SMODS.find_card does not include blueprints.
ic
i think id rather just make it incompatible than figure out a way to make it count blueprints
Quick stupid question since I haven't modded in a damn year, we still use spritesheets like back then right
just wanna make sure
okay nice nice
key = 'bootleg',
shader = 'holo',
prefix_config = {
-- This allows using the vanilla shader
-- Not needed when using your own
shader = false
},
config = {
extra = {
odds = 1
}
},
in_shop = true,
apply_to_float = false,
sound = { sound = "ttv_fart_sound1", per = 1.2, vol = 0.4 },
disable_shadow = false,
disable_base_shader = false,
loc_txt = {
name = 'Bootleg',
label = 'Bootleg',
text = {
[1] = '{C:green}1 in 8{} chance to fail'
}
},
unlocked = true,
discovered = true,
no_collection = false,
get_weight = function(self)
return G.GAME.edition_rate * self.weight
end,
-- loc_vars = function(self, info_queue, card)
-- local new_numerator, new_denominator = SMODS.get_probability_vars(card, 1, card.ability.extra.odds, 'e_ttv_bootleg')
-- return {vars = {new_numerator, new_denominator}}
-- end,
calculate = function(self, card, context)
if context.pre_joker or (context.main_scoring and context.cardarea == G.play) then
if SMODS.pseudorandom_probability(card, 'e_ttv_bootleg', 1, card.edition.extra.odds) then
end
end
end
}```
reworked the bootleg abit
it disables the card.ability.extra.xChips = (card.ability.extra.xChips) + 0.25 with the 1 odds
but I want it to disble the xchip mult and other abilities if the roll hits the odds
key = 'bootleg',
shader = 'holo',
prefix_config = {
-- This allows using the vanilla shader
-- Not needed when using your own
shader = false
},
config = {
extra = {
odds = 8
}
},
in_shop = true,
apply_to_float = false,
sound = { sound = "ttv_fart_sound1", per = 1.2, vol = 0.4 },
disable_shadow = false,
disable_base_shader = false,
loc_txt = {
name = 'Bootleg',
label = 'Bootleg',
text = {
[1] = '{C:green}1 in 8{} chance to fail'
}
},
unlocked = true,
discovered = true,
no_collection = false,
get_weight = function(self)
return G.GAME.edition_rate * self.weight
end,
calculate = function(self, card, context)
if context.pre_joker or (context.main_scoring and context.cardarea == G.play) then
if SMODS.pseudorandom_probability(card, 'e_ttv_bootleg', 1, card.edition.extra.odds) then
SMODS.calculate_effect(card.ability.extra, card)
end
end
end
}```
anything else I can try? I've tried SMODS.card_effect calculate_effect
or does the pseudorandom calculations only work in the jokers effects
it works for anything
Nested? You mean hooked to the original code or something?
i mean that it's inside another table
it should be
return {
misc = { ... }
}
I mean yes, but on the localization files
Since I want to translate the text in other languages
But it worked for another joker when I wanted him to return a message similar to stone joker
can i see the entire thing
oh wait i think i know what it is
are you putting the localize straight to config.extra like in the code you shared?
vanilla localization is probably loaded by then but not your mod's
Probably, can you double chack I just pushed the thing now so you can see it on the code
Correct
9 hours ago is not just pushed
ok so what the fuck did I just pushed
ok its not important
yes I'm using localization to also translate the config , but if you see k_plus_pizza
either on pt_br or en-us it works
it localizes the message whenever I add a new card like stone joker
that's used in calculate which runs after localzation is loaded
you need to use localize in loc_vars instead
I remembered how I implemented something similar to another card and i replicated so now it works
G.GAME.blind.in_blind
oh thats quite simple
wow that took like 30 seconds to send
I will NOT be depositing five coins
is there currently an easy way to draw a shader on a deck?
i'd like to either use a draw function on the deck, or define a parameter
i tried to write a draw function but it's not working
draw = function(self, back, layer)
back.children.center:draw_shader('booster', nil, back.ARGS.send_to_shader)
end,```
No, you would use a SMODS.DrawStep
that does it i think
omg
wait this is like
the thing
:3
lemme look at this, thanks
hmm
SMODS.DrawStep {
key = 'deck_shader',
order = 5,
func = function(self)
if self.children.back then
local cback = self.params.galdur_back or (not self.params.viewed_back and G.GAME.selected_back) or
(self.params.viewed_back and G.GAME.viewed_back)
if cback then
local shader = nil
if cback.effect.center.phanta_deck_shader then shader = cback.effect.center.phanta_deck_shader end
if (shader and (self.config.center.set ~= "Sleeve"))
-- not the stake select from galdur or the stake chips
and ((self.area and not self.area.config.stake_select and not self.area.config.stake_chips) or not self.area) then
local t = (self.area and self.area.config.type == "deck") or self.config.center.set == "Back"
if t and not self.states.drag.is then self.ARGS.send_to_shader = { 1.0, self.ARGS.send_to_shader[2] } end
self.children.back:draw_shader(shader, nil, self.ARGS.send_to_shader, t, self.children.center, 0, 0)
end
end
end
end,
conditions = { vortex = false, facing = 'back' }
}```
i'm not quite sure what this crash means
i think the shader is missing the prefix
o
oh yeah
true this is a custom one
huzzah! it works for this one
not quite here though
but that's because it has a hole in it
you probably need to draw the shader on every card
oh the problem is the card's base shader is being rendered too
you can see on the first deck that all the cards are shiny
would i have to patch to get the deck to not render its base shader?
or is there like, an option in the drawstep or elsewise
-# i don't know why there would be an option there but
uhhh there's a property you can set
(which is? :3)
card.ignore_base_shader = {deck = true} something like this, but it's probably mega jank with when the cards are drawn face up
let me look a bit closer
alr 👍
you can hook Card:should_draw_base_shader too
aw
this is the relevant drawstep
Yo salty ghost
hihi
how to undebuff cards and how to flip cards
id like to undebuff every card and flip them all face up
which also means checking if theyre flipped
isnt that like card.flipped
do orbital tags just automatically pick a random hand when created via a joker effect?
they do now i think
im sure you could access and change the value of the tag right after you make it
force it to be whatever hand
i assume its in its set_ability
nah i was just curious since we were avoiding making them out of worry it could cause problems
but hell yeah
i think it got fixed in like the latest smods or something
yeah I think it did
the key of the mars planet would be "c_mars" right
or is it p for planets specifically
well then im stumped
checking
if context.using_consumeable and context.consumeable.key == "c_mars" then
isnt passing when using mars
im guessing its not just .key and its like
.config.center.key or something
couldve sworn
oh thats definitely it
yes
ok new different issue
when i use level_up_hand to level up a hand the level text and chips/mult values get stuck on screen
Hello everyone! Help me install Lovely for Balatro. Error: Balatro.exe - System Error
Cannot continue code execution because the system did not detect C:\Windows\System32\version.DLL. To fix this problem, try reinstalling the program. My antivirus is turned off. What's wrong? I downloaded everything from GitHub.
i want it to not do that
use SMODS.smart_level_up_hand
use the new smods one
SMODS.upgrade_poker_hand (i think)
smart is for back compat now iirc
right so which one should I be using
ah right
use SMODS.upgrade_poker_hands
utility page on the wiki should probably be updated to document upgrade_poker_hands then
if you dont specify a hand for upgrade it does all iirc
oh awesome
it wont do the black hole animation tho
here's the documentation for upgrade_poker_hands from the 1221a release post
december 21 a
(the latest version is 1224a but that was just a few bugfixes, released on dec 24)
i gotta update then
it still got stuck
the flames are new though
is it because of instant
this effect could be really annoying if its not instant
ok its not cause of instant
uhh
every planet card is doing this now
even without the joker with the effect
is this just an smods bug
could be engulf's fault
its not engulf
does this happen to anyone else or just me
did you start a new run
yes
hmm no idea
it might be my nopeus speed but i doubt it
oh that is it
is there a nopeus alternative yet
the text gets stuck if you have fast forward set to planets or higher
handy i think
handy settings are complicated
page 2 of quick actions
ok i think
my handy is just so outdated
that it doesnt have the speed settings
lol
latest version is 1.5.1o
oh its also here
oh yea there it is
what do i do with the lovely.toml file here
keep it in there
what
don't worry about it
it's not relevant
idk why it's there
just drag the folder in
but then ill have a folder called Handy.1.5.1 and a folder called HandyBalatro
so can I get rid of it
delete Handy.1.5.1
yes
check out Handy's way
the key part is to pre-hook init_localization
hi! is there any table containing all ranks/suits currently loaded (including modded ones)?
cant seem to find it in the smods docs
SMODS.Ranks SMODS.Suits
im assuming this runs when the language changes too
yep
awesome
you just need to append keys to G.localization
a pre-hook to it means that your added keys will be processed by the orig function, if it's in descriptions
check for idiots who unzip release without checking it
So much time people install it not properly so I decided to do this thing which crash on start
lol
smods supports nested folders iirc
it's lovely files that aren't running
that's why smods part have another idiot check for nested folder
lovely zip loading waiting room
lovely zip loading waiting room
waiting for the day I forgor to remove the release and confuse lovely 0.9
btw I found a really weird behavior with smods a while ago
trying to specify smods version by .lovelyignoreing the other smods folders just doesn't work for some reason
actually rename localization folder from loc_txt to actual localization and adding SMODS check kinda makes sense
Does anyone know what the issue can be? I don't get any crash logs, the game just freezes when entering the first shop:
function create_card(_type, area, legendary, _rarity, skip_materialize, soulable, forced_key, key_append)
local card = ccfs(_type, area, legendary, _rarity, skip_materialize, soulable, forced_key, key_append)
if card.ability.set ~= "Joker" then
return card
end
local card2 = SMODS.create_card {
set = "Joker",
rarity = "Uncommon",
area = area,
key_append = "m_uco"
}
return card2
end```
(The goal is to make all jokers uncommon)
infinite loop, presumably
yep lmao, you need to also just return the regular card if it's a joker that's already uncommon
Good point, thank you!
it's because of the function that finds the folder im pretty sure i saw that before
nvm it isnt because I need to do some stuff between loading default and actua localization
outsmarted myself
i am losing my mind my code is a mess and i don't know what to do (nun so che cazzo fa /ref)
wrong: loc_vars = function(code goes here)
right:
loc_vars = function(self, info_queue, card)
code goes here
end
😭
why does .lovelyignore not work there
now i'm more confused
you're missing an end but the while loop is unnecessary since none of the keys is UNAVAILABLE
an end where exactly???
An end for the while loop
removed the loop since n' said it was unnecessary and apparently it hates me because it's giving me the same error
although it might be me putting in the play_sound thing wrong
i had added that fully myself (it's a funny joke i came up with while brainstorming ideas for the mod) so that's probably where the issue arises
I've only ever done deck and joker mods, what's the equivalent of apply = function(...) when it comes to "global" mods?
As in, apply it always, regardless of the deck you're playing?
the mod's global calculate function
it's more similar to joker calculate than deck apply, check the release discussion for smods 0827 on github for details on how it works
Thank you!
mm, i need a little help, I want to make a Joker basically act like a permanent Uncommon Tag (without it being free). Would I just input in the calculate function the way tags add cards to the shop or something else?
tags and cards don't use the same code unfortunately
i think there was a recent addition for this let me check
SMODS.current_mod.reset_game_globals(run_start) with run_start set to true
is context.blind.boss and context.end_of_round a valid combination
yes, check create_shop_card
https://github.com/Steamodded/smods/discussions/1131
thank you!
context.beat_boss instead of the first one
it is technically an end_of_round thing but idk if it's used in other contexts
i will keep it in case then
huh
play_sound calls need to include the mod prefix
so it's not just play_sound("florida"), it's play_sound("modprefix_florida") (where you fill in whatever your mod's prefix is for modprefix)
and is that added to the file name or does it just stay as florida
your second screenshot is perfectly fine as is
you just need to add the mod prefix whenever you want to actually use the sound
sorry, but do you know where I could find shop_create_flags formatting?
Thank you!
there
return {
shop_create_flags = { set = "Joker", rarity = "Uncommon" }
}
is what it says you can do
sweet, thank you
escb should be the prefix but it's still giving me this error
fyi changed the file name as well as all the relevant things to "adrenalinasound" to make things easier for me
Oh my gosh, thank you for the reminder that this exists! 
wait, no hang on, might've misspelled the key give me two seconds
I'm getting "attempt to index field 'center' [a nil value] here:
if joker.config.center.rarity ~= 2 then
G.GAME.banned_keys[joker.key] = true
end
end```
Even though config.center.rarity is how baseball card checks for the rarity too
I see, thank you! 😁
ok nevermind it's still thinking it's a vanilla sound "effect"
`SMODS.Sound({
key = "adrenalinasound",
path = 'adrenalinasound.ogg',
})
SMODS.Tag {
key = "sm-2021",
atlas = 'sm-2021',
pos = { x = 0, y = 0 },
loc_txt = {
name = 'Adrenalina',
text = { 'Create a {C:attention}Standard Tag{}, {C:tarot}Charm Tag{}',
'{C:attention}Buffoon Tag{}, {C:planet}Meteor Tag',
'or {C:spectral}Ethereal Tag',
'{C:inactive}WARNING: contains Flo Rida'}
},
min_ante = 1,
config = { spawn_tag = 1 },
loc_vars = function(self, info_queue, tag)
selected_tag = pseudorandom_element({'standard_tag', 'charm_tag', 'buffoon_tag', 'meteor_tag', 'ethereal_tag'}, 'modprefix_seed')
local it = 1
play_sound("escb_adrenalinasound")
end
} `
are you sure that's your mod prefix
also is it supposed to play every time you hover the tag
yes, unless the json is gaslighting me
yo chat i need help with this joker lmao (codes a mess i know i basically stitched together sock and castle whilst changing some stuff, if the answer is super simple and im just dumb dont be surprised)
and is it in the right folder
(sry to interrupt)
it shouldn't be (it is doing that right now) but i'd wanna make sure the audio actually plays if not properly at first
what do you need help with
i've tried multiple places the file could be (assets/sounds/, resources/sounds and even assets/resources/sounds) and it hasn't worked a single time
well, every time i play a card, it doesnt trigger the effect, ive been assuming its smth with it not recognizing the suit or smth
did you try assets/sounds after adding the prefix
are you calling reset_carousel_card anywhere
yeah in the main file under function SMODS.current_mod.reset_game_globals(run_start)
yes, although looking at the files it might have been named incorrectly so i'll go back one more time
this is missing the .suit
ok no ain't working even in assets/sounds
no idea then
ok- so this is for a different joker, what if I want to add a specific joker rather than a generic rarity?
you're a lifesaver, thank you for being so patient with me
escb is 100% the prefix i am so confused
can i see the folder structure for your assets
ignore the empty resources folder
i think your sound file is cursed
you know it probably is
considering it's a bitcrushed 3 minute eurovision entry with flo rida
i don't think it can get more cursed than that
is the sound file name exactly as you typed it in the SMODS.Sound thing?
make sure it doesn't accidentally have double extension too
or trailing spaces
yes, they both have adrenalinasound.ogg, and it doesn't have a double extension, i have file extensions on in file explorer so i would know if that was the case
here's the file info if that helps
yo chat, need some more help lol, everything works well mechanically, but when it triggers, the joker doesnt shake and doesnt do the "Again!" message
iirc card should actually be the joker and not the one that's being retriggered
Also I don't think you need to specify not context.repetition_only
you can just remove the card = and the message
it handles that automatically
playing card retrigger does that?
but not joker retrigger 
For some reason I remembered retriggering still needing a card argument and idk why lol
it doesn't for some objects like decks iirc
i mean decks are like wierd to be fair
ok not only is the sound not working but also the tag doesn't create a tag like i want it to what the actual hell
well it's nothing to do with jokers like at all
hmm, thoughts on the floppy disk? too op? if not, should it be rare or keep it uncommon?
How can I prevent the first joker from appearing for a brief second? I destroy it as soon as I know it's a joker, but it's not enough and it still shows up only to be immediately destroyed
function create_card(_type, area, legendary, _rarity, skip_materialize, soulable, forced_key, key_append)
local card = ccfs(_type, area, legendary, _rarity, skip_materialize, soulable, forced_key, key_append)
if card.ability.set ~= "Joker" or card.config.center.rarity == 2 or card.config.center.key == "j_joker" then
return card
end
SMODS.destroy_cards(card, nil, nil, true)
card2 = SMODS.create_card {
set = "Joker",
rarity = "Uncommon",
area = area,
key_append = "m_uco"
}
return card2
end```
what is this for
theres probably a cleaner way to do this with SMODS.add_to_pool
I'd like the game to only offer uncommons, but don't flood the pool with Jimbos
you can hook SMODS.add_to_pool to remove from the pool every other rarity and you can also add a check to see if you hold all uncommons to disable it if you dont want jimbos
I mean it can give jimbos once the pool is out, but if I just ban not-uncommons, then everything that would spawn as a different rarity is a jimbo
oh yeah
im stupid, the correct way is to just make the other rarities rate 0
with this
i also wouldnt do this because it will mess with some other mods that expect a specific card to be made
I tried this, but commons are still showing up:
G.GAME["common" .. "uco_mod"] = 0
end```
Or at least I'm guessing lower() means I need to input the key in lower case
r_common isn't working either
common_mod
Is there a clean function to make copies of playing cards that I can use instead of what vremade's Cryptid does?
vanillaremade is the cleanest i know of which is why i write things that way
It works fine but it seems like the kind of thing that has a smods function
it doesn't
I see
What does G.playing_card = (G.playing_card and G.playing_card + 1) or 1 do? I thought it increased the total amount of cards, but that's G.playing_cards
Oh interesting
Thank you so much, it works!
would still like a little help here
here's the code in question
(play_sound commented out until i figure out what the fuck is wrong with the file
what the code is doing is picking a random tag when you read the tag description and then doing nothing with it
Doesn't SMODS.add_card() do mostly the same thing? Unless the code has to be written out in Cryptid so it can be a copy of a card and not a brand new card?
have you looked at the code for other tags
yes, copy_card does other things
i do think an SMODS.copy_card would be cool
kinda, only one that i can really look at for this type of thing in vanillaremade is double tag and that isn't exactly helping
double tag kinda does what you want, and you can see it has an apply functon where it does the effect
this is a tag that creates a different tag from a subset?
yes, it creates one of the tags that gives you a booster pack (at random)
also plays a eurovision song but that's unrelated to the point
ah i see it
so i just make it that add_tag line in there instead of (context.tag.key) it'll be something along the lines of (context.selected_tag)?
apply = function(self, tag, context)
if context.type == 'tag_add' then
local lock = tag.ID
G.CONTROLLER.locks[lock] = true
tag:yep('+', G.C.BLUE, function()
local selected_tag = pseudorandom_element({your stuff here}, "seed")
add_tag(Tag(selected_tag))
G.CONTROLLER.locks[lock] = nil
return true
end)
tag.triggered = true
end
end
like this
the context probably needs to be different tho
maybe 'immediate' instead of tag_add
i'll try both and see what works
i'll try tag_add first
ah god now i need to play the game i don't have the debug menu on me rn
ok tag_add didn't work so i'll do immediate
(i know the way i implemented it is ass and is prob the reason it isnt working but still lol) trying to make the suit cycle between the 4 every time the function is run (im currently using reset global values as a placeholder for when ill actually prefer to run it )
the shumbagala was just to test if the stuff gets ran, it does, just that for some reason the suit doesnt change
because every check is true
you change it from hearts to clubs then check if its clubs
need to use elseif instead of multiple ifs lolol
wdym that's ideal 
good news, it activated
bad news
i mean the vibes are emmaculate, but my ass ALWAYS forgets the basic shit
twas a joke
can i see how you have the code now
are those the correct keys
they should be
Don't you need to use G.P_TAGS[key] for that?
i think tag_ goes first
nope
yea tag comes first
ah ok lemme try that
I overcomplicate the simplest shit in my head all the time I swear lol
i love how i've been showing this tag troubleshooting it in this channel for a while and no one has stopped and noticed "WARNING: Containts Flo Rida"
not even close to some of the weirdest mod content we've helped debug
Is there a way to set the cost of a custom Spectral card?
yes you can just set cost = x as part of the SMODS.Consumable definition, you don't need to do anything special
just like you would in a joker
Thank you!
ok it's working thank god
oh yeah i remember why i didnt do the elseifs
now for the fun part! the audio!!!
(or i can just move on to another joker but where's the fun in that)
Can you show
Oh uh I already decided ill try to fix it tmrw so I closed my pc and stuff, sry I couldnt show-
ope all good
I'm trying to make a joker that let's you pick an extra card from a booster pack and I'm trying something similar to what I had for another that added another card to a pack, but it doesn't seem to be working at all. Am I missing something?
if context.open_booster and not context.blueprint and context.card then
local booster = context.card
booster.ability.choose = booster.ability.choose + 1
end
ok i hate that all the new features are divided between release notes lol
theres a recent functionality for this
https://github.com/Steamodded/smods/discussions/919
G.GAME.modifiers.booster_choice_mod
Can you make a spectral card usable, destroyable, but not sellable?
okay, i'll test this out and see what happens
hook Card:can_sell_card
U can look at what cryptid did for that if u want
Oh nvm u already got the answer lol
wiki is the bane of my life 😭
maybe I should just copy the release notes onto the wiki for now and worry about putting them in sensible places some other time
ok unrelated issue to the still prevelant music issue
did i make this too small or is the tag developing mitosis
That sounds really good, just to make all the new features searchable for
even if they were just organized by release it would be helpful
you might have put the 1x in the 2x folder
How do I check if a center is a plain card? A joker would be center.set == 'Joker' (doesn't work with 'Default', working with stickers)
should_apply = function(self, card, center, area, bypass_roll)
local is_playing_card = center.set == 'Default'
return is_playing_card
end
try "Base"
thanks vsc for making me realise i pressed the restart key for too long
This is why I use Ctrl+F5 lol
How do you add repetitions via enhancements/editions/what have you?
I know the main scoring context is used typically for other scoring
context.repetition works iirc
tried that, still smol
Is it the same context.repetition and context.cardarea == G.play?
Even if it's applying to the current card?
yeah, if i recall correctly it doesnt run for other cards
i tried it once because someone wanted to make an enhancement that retriggered adjacent cards
just making sure, what's the recommended size for the tag art? the friend of mine making all the art might've just gotten the dimensions wrong
34x34
doesn't work, sadge
no info queues supprt multiboxes
I mean, to make sticker appear only on cards, I could make it not appear on jokers, tarots, planets and spectrals xd
Best suggestion for trying to debug something that does not give a crash report or put anything in the log when it crashes?
Huh...... I'm having trouble getting these cards to receive the skip_blind context
I need all edition cards to upgrade when a blind is skipped, regardless if they're jokers or playing cards in the deck
Jokers receive it, but playing cards don't
im assuming the deck optional feature is on
Oh! Right, that's optiona;
check for any recent function you added that might call itself
^ sounds like an infinite recursion issue
My only problem with an infinite recursion idea is that the game doesn't freeze, it just crashes and closes.
