#💻・modding-dev
1 messages · Page 627 of 1
Is there a context
For if you're in a boss blind
Not selecting or beating
Just in
misc = {
challenge_names = {
c_nflame_moderntech = "Day-One Patches"
},
dictionary = {
b_evidence_cards = "Evidence Pieces",
k_evidence = "Evidence",
},
poker_hands = {
nflame_generic = "Poker Hand All"
},
poker_hand_descriptions = {
nflame_generic = { "Any cards." }
},
labels = {
evidence = "Evidence Piece",
}
},```
not context but you can do if G.GAME.blind.boss and G.GAME.blind.in_blind
you could extend SMODS.Center and make a new object and then just put it in a cardarea like normal
and what does the consumable type definition look like
SMODS.ConsumableType {
key = "evidence",
primary_colour = HEX("a58547"),
secondary_colour = HEX("eeba6e"),
shop_rate = 1.0,
can_stack = false,
can_divide = false
}```
Oh ok, so SMODS.Center is what I need to extend
okay i dpont know anymore
:(
-- do stuff ig
end``` im confident that this is fine
you probably want context.other_joker instead of card there
idk if this ever worked properly in the first place now that I'm trying again
calculate = function(self, card, context)
if context.joker_main then
local currChips = hand_chips
local currMult = mult
hand_chips = currMult
mult = currChips
update_hand_text({delay = 0}, {chips = hand_chips, mult = mult})
return {
message = localize('mirror_swap'),
}
end
end
just return swap = true 😭
hrm, idk when that was added
iirc its an unused vanilla feature? i might be wrong though
...I think SMODS itself added that at some point as a valid return value.
I haven't touched this code in gods know how long, and idk if I even wrote all of it
As I had done something like that for one of my Jokers, but then Eremel pointed me to the swap key.
it was before this year at least
Are there any other mods that add custom card types I could use as reference?
Oh wow I did not know I could do that lol
am I allowed to put specific joker keys in SMODS.destroy_cards(card)
no
you have to specify the exact card object(s)
but you can get a list of jokers with that exact key
then pass it into SMODS.destroy_cards
so what If i want do destroy 5 specific jokers, and nothing else
SMODS.destroy_cards(SMODS.find_card("key"))
oh if it's 5 different ones then the logic is more complicated
i think I can just use 5 seperate instacnes of SMODS.destroy_cards(SMODS.find_card("key"))
and just change the keys
that will destroy all copies btw
fine by me
i dont remember if it crashes when the list is empty
for a calculate function, when is the last context where returning xmult = 2 will affect mult
final scoring step
neat
I'm not exactly sure what's going on here, can anyone help me out?
Before I added the loc_txt, it was crashing when I hovered over the object, but now it just crashes on startup
you need to have the table in the localization file i think
not the loc_txt part but the object's table like Joker
What do you mean?
you know how a localization file has like Joker and Tarot and Blind and stuff
Like the en_us.json file?
isnt it a .lua file
Why does it have to have a localization file? loc_txt works fine for all of the vanilla card types, doesn't it?
because those exist
yours is new
it's trying to insert your loc_txt there and it cant (from what im reading in the crash i could be wrong)
Ohh, that makes sense
if next(SMODS.find_card("j_jabong_cjimbod")) and
next(SMODS.find_card("j_jabong_lajim")) and
next(SMODS.find_card("j_jabong_rajim")) and
next(SMODS.find_card("j_jabong_rlejim")) and
next(SMODS.find_card("j_jabong_llejim"))
then
SMODS.destroy_cards(SMODS.find_card("j_jabong_cjimbod"))
SMODS.destroy_cards(SMODS.find_card("j_jabong_rajim"))
SMODS.destroy_cards(SMODS.find_card("j_jabong_lajim"))
SMODS.destroy_cards(SMODS.find_card("j_jabong_rlejim"))
SMODS.destroy_cards(SMODS.find_card("j_jabong_llejim"))
SMODS.add_card{ key = "j_jabong_Jimbodiafull" }
return{
play_sound('jabong_boop'),m
}
end
end``` I wanna mke this a passive ability (its currently oustide of any SMODS objects), so how would I do that
... ignore the random m after the comma in the return
m
so do I put this somewhere or not
I wouldnt have it as a passive at all, I would use add_to_deck in those jokers for this
ohhh ok
What's going on here? The game started doing this when I added my own atlas
if next(SMODS.find_card("j_jabong_cjimbod")) and
next(SMODS.find_card("j_jabong_lajim")) and
next(SMODS.find_card("j_jabong_rajim")) and
next(SMODS.find_card("j_jabong_rlejim")) and
next(SMODS.find_card("j_jabong_llejim"))
then
SMODS.destroy_cards(SMODS.find_card("j_jabong_cjimbod"))
SMODS.destroy_cards(SMODS.find_card("j_jabong_rajim"))
SMODS.destroy_cards(SMODS.find_card("j_jabong_lajim"))
SMODS.destroy_cards(SMODS.find_card("j_jabong_rlejim"))
SMODS.destroy_cards(SMODS.find_card("j_jabong_llejim"))
SMODS.add_card{ key = "j_jabong_Jimbodiafull" }
return{
play_sound('jabong_boop'),
}
end
end``` why he no work
Ok nvm, I figured it out, I just forgot the mod prefix lol
Yayyy, my custom object type can show up in CardAreas now
Now how do I make it not just say ERROR
is there a way i can make an existing joker eternal
card:set_eternal(true) I think
thanks!
card:add_sticker('eternal', true)
I need something to happen every time a hand is played. What function would I need to hook?
No, use the mod calculate
probably better to use global mod calculate here instead
So you can use calculate outside of an object for situations like these?
yup
Yes.
SMODS.current_mod.calculate = function(self, context)
-- code
end```
this does nothing
deck_joker:add_sticker('eternal')```
card:set_eternal(true) ?
Yes, add true as the second input.
that works, how would you add custom stickers though
ohhhh
card:add_sticker('modprefix_key', true)
i get this now, i meant because eternal was its own function
thanks for the help
Trying to get the table to reset each hand played. Right now, its not doing anything. Any idea as to why?
hey anyone got a sprite sheet for the vanilla game's assets for reference?
Nevermind, I think I know what I did
unzip the exe or use https://www.spriters-resource.com/pc_computer/balatro/
oh right the exe's just a zip
First two implementations work, third doesn't, can anyone tell why?
[manifest]
version = "1.0.0"
dump_lua = true
priority = 0
# Makes Magic Trick always have enhanced cards and illusion have 20% seals (as it has 20% editions)
## Always pick 'Enhanced' when any playing_card_rate
[[patches]]
[patches.pattern]
target = "functions/UI_definitions.lua"
pattern = '''
{type = (G.GAME.used_vouchers["v_illusion"] and pseudorandom(pseudoseed('illusion')) > 0.6) and 'Enhanced' or 'Base', val = G.GAME.playing_card_rate},
'''
position = 'at'
payload = '''
{type = 'Enhanced', val = G.GAME.playing_card_rate},
'''
match_indent = true
## Seal RNG (20% of cards)
[[patches]]
[patches.pattern]
target = "functions/UI_definitions.lua"
pattern = '''
if (v.type == 'Base' or v.type == 'Enhanced') and G.GAME.used_vouchers["v_illusion"] and pseudorandom(pseudoseed('illusion')) > 0.8 then
'''
position = 'before'
payload = '''
if (v.type == 'Base' or v.type == 'Enhanced') and G.GAME.used_vouchers["v_illusion"] and pseudorandom(pseudoseed('illusion')) > 0.8 then
local seal_poll = pseudorandom(pseudoseed('illusion'))
local result_seal
if seal_poll >= 0.75 then result_seal = 'Red'
elseif seal_poll >= 0.5 then result_seal = 'Gold'
elseif seal_poll >= 0.25 then result_seal = 'Purple'
else result_seal = 'Blue'
end
card:set_seal(result_seal)
end
'''
match_indent = true
## Seal prices +$3
[[patches]]
[patches.pattern]
target = "card.lua"
pattern = '''
function Card:set_cost()
'''
position = 'after'
payload = '''
if self.seal then
self.extra_cost = self.extra_cost + 3
end
'''
match_indent = true
Is there a way to change the number of slots used by a consumable?
card.ability.extra_slots_used = number
Thanks
Can anyone tell me how I can do this? I figured out how to change the color, but not to make it say "Pin" instead of "ERROR"
ok how do you deal with attempt to compare number with table
you use cdataman instead of talisman :3
Code?
can_use = function(self, card)
if to_big(math.floor(G.GAME.chips / 2)) > to_big(G.GAME.blind.chips) then return false end```
Log?
what about the full logs
nvm installing cdataman fixed it
ok it seems like steammodded or whatever is COMPLETELY ignoring everything im putting in my localization misc.dictionary
since manually setting G.localization.misc.dictionary works perfectly
any idea how to fix that
nvm im an idiot and somehow made everything under the "descriptions" table
by messing up braces
how do i make a playing card in pool if theres a specific deck? heck anything that can detect a certain deck? this doesnt work and idk what can
decks have prefix b_
ah
Also you can shorten that to return G.GAME.selected_back.effect.center.key == "b_mvan_royal"
Am I doing something wrong with this patch? I'd like to get the table of eligible bosses from the get_new_boss() function put into a global variable that I can access. Never done a patch before, and willatro_boss1 seems to be nil.
[manifest]
version = "0.1.0"
dump_lua = true
priority = 0
[[patches]]
[patches.pattern]
target = "functions/common_events.lua"
pattern = "return boss"
position = 'before'
match_indent = true
payload = '''
G.GAME.willatro_boss1 = eligible_bosses
'''
Check in Mods/lovely/dump/functions/common_events.lua to see if your patch applied properly
Seems like it did not.
is the line "return boss" in the lovely dumps?
or do you have other mods messing with it
Yeah, that line is there.
Where is your toml file
the patch itself seems fine, looks like the issue is with either your toml filename or location
hi larswijn
hi srock 👋
Does it need to be in a specific file? I just have it in a separate folder called Patches
name the folder lovely and that should fix it
Ah, that's done it, thanks!
Can anyone help? I'm trying to patch the deck view field, but it's not showing up at all. I see my code injected in the lovely dump so I know it's not an issue with the patch
Ohhh wait SMODS overrides it nvm
how does one make a config menu or like a credits menu
see also config_tab lower down
jokerdisplay is a better example for config
This is my first time working with UI, how do I make these boxes greedy and take up as much space as they can?
Follow up question (sorry for ping)
How would I add images beside text? ill be reading from a table of tables each table would be something like this
{
text = "Hello World!"
img = {x=0,y=0} -- but can change to specific atlas or any image
}
I've also added an image as an idea
waiyt
gimme a sec for thew image
here
actually exactly like aikoyori's does
havent seen a good lorem ipsum in a while
this does exactly what i'd like it to functionally, but it doesn't make the card wiggle on every "pulse" of the level up
how would i be able to have it do that?
if context.discard and context.other_card == card then
local target_hand
local available_hands = {}
for hand, value in pairs(G.GAME.hands) do
if value.visible and value.level >= to_big(1) then
table.insert(available_hands, hand)
end
end
target_hand = #available_hands > 0 and pseudorandom_element(available_hands, pseudoseed("m_chm_old")) or "High Card"
return {
level_up = card.ability.extra.levels,
level_up_hand = target_hand
}
end
for context, this is on an enhancement
trying to make a card that destroys all 8s if hand contains more than 2 8s. this is halfway done but i just wanted to test if the condition check is working, so i just made it give 88 chips. the error says that there is no other_card.
calculate = function(self, card, context)
if context.destroying_card and not context.blueprint then
local tally = {} -- tally hall
for _, scored_card in ipairs(context.scoring_hand) do
if context.other_card:get_id() == 8 then
tally[#tally + 1] = scored_card
end
end
if tally >= 2 then
return {
chips = card.ability.extra.chips
}
end
end
end
Yes, it would be scored_card not context.other_card
What does card_w do exactly in CardArea? I've tried looking at the code but I can't tell
I can tell it has to do with the width of cards, but I have no idea what it does with that information
Something to do with how it aligns the cards but idk what
what exactly does context.other_card do
It's the card being calculated in context.individual, context.repetition, context.post_trigger, context.retrigger_joker_check, context.modify_scoring_hand, context.discard, context.check_enhancement and context.check_eternal
ah
no idea why this deckskin code doesn't work
SMODS.Atlas({ key = 'tcg_lc', path = 'deck_tcg_lc.png', px = 71, py = 95 })
local suits = {'Hearts', 'Diamonds', 'Clubs', 'Spades'}
local ranks = {"Ace", "2", "3", "4", "5", "6", "7", "8", "9", "10", "Jack", "Queen", "King"}
local suitcol = {
["Hearts"] = HEX("FF5B87"),
["Diamonds"] = G.C.SUITS["Diamonds"],
["Clubs"] = HEX("2B83FD"),
["Spades"] = G.C.SUITS["Spades"]
}
for _, v in ipairs(suits) do
SMODS.DeckSkin{
key = "deck_tcg_"..v:lower(),
suit = v,
ranks = ranks,
display_ranks = {"Ace", "King", "Queen", "Jack", "10", "9", "8", "7", "6", "5", "4", "3", "2"},
palettes = {
{
key = 'lc',
ranks = ranks,
atlas = 'tcg_lc',
display_ranks = {"Ace", "King", "Queen", "Jack", "10", "9", "8", "7", "6", "5", "4", "3", "2"},
pos_style = 'deck',
colour = suitcol[v]
},
{
key = 'hc',
ranks = ranks,
atlas = 'tcg_lc',
display_ranks = {"Ace", "King", "Queen", "Jack", "10", "9", "8", "7", "6", "5", "4", "3", "2"},
pos_style = 'deck',
colour = suitcol[v]
},
},
loc_txt = {
['en-us'] = v .." by TCG"
},
prefix_config = { key = false },
}
end
the error says attempt to index field 'atlas'
there is a file both in 1x and 2x called deck_tcg_lc
Not 100% sure but I think the modprefix is added to the atlas so in your deckskin it might be 'atlas = modprefix_tcg_lc'
oh
okay it doesn't work :(
Maybe vanilla remade's wiki has an entry on why that error happens
i copied ts from an older mod and just changed all the names and filenames
idk why it's not working
If I just want to replace a single club card; the ace, is there a way to do it without having to make the image 760 pixles tall with lots of blank space above?
how do i make a joker create tags and lower the blinds score?
(not at the same time)
vanillaremade wiki has examples for both effects
this thing?
yes
like the entire thing?
Yes
-# Löve2D project
I am so stumped, I have no clue why stepping on a button doesn't open the doors??
https://github.com/Ch3rryC0d3r/bloxee
the wires are correctly connected?
rule 8
modding dev is for balatro mods
i dont think anybody would know about ths tho its not like balatro m9ods require love2d stuff often
true 🥀
when saved from a gave over, i assume saved also points to a localization entry, where do i put it in the localization lua?
In the misc dictionary iirc
thank you
when does calculate = function() work?
SMODS.Joker:take_ownership('bloodstone', { config = { extra = {odds = 3, Xmult = 1.5} }, calculate = function(self, card, context) if context.mod_probability then return { numerator = context.numerator * 2 } end end }, true )
This doesnt seem to work(shows 1 in 3)
i remember your message but it didnt work somehow. i will try again and if it doesnt work i will delete my code and just use yours and see
What’s your smods version?
how can I check this?
Top right of main menu
did you try what i said
you said to change config
i can freely change the odds(2 to 3), but not the numerator(1 to 2)
I said to use the calculate from vanillaremade
you should also use the loc_vars
and change the numbers there
calculate = function(self, card, context)
if context.individual and context.cardarea == G.play and context.other_card:is_suit("Hearts") and
SMODS.pseudorandom_probability(card, 'vremade_bloodstone', 1, card.ability.extra.odds) then
return {
xmult = card.ability.extra.Xmult
}
end
end,
this one i believe
yes, just change the 1
Oh yeah it’s this if you don’t have a custom loc vars
Your calculate function is actually working
SMODS.Joker:take_ownership('bloodstone',
{
config = { extra = {odds = 3, Xmult = 1.5} },
loc_vars = function(self, info_queue, card)
local numerator, denominator = SMODS.get_probability_vars(card, 2, card.ability.extra.odds, 'vremade_bloodstone')
return { vars = { numerator, denominator, card.ability.extra.Xmult } }
end,
calculate = function(self, card, context)
if context.mod_probability and not context.blueprint then
return {
numerator = context.numerator * 2
}
end
if context.individual and context.cardarea == G.play and context.other_card:is_suit("Hearts") and
SMODS.pseudorandom_probability(card, 'vremade_bloodstone', 2, card.ability.extra.odds) then
return {
xmult = card.ability.extra.Xmult
}
end
end,
},
true
)
i believe this should work
😭🙏
time to change 5 more joker, lucky cards and 2 stickers
You’ve just hardcoded it to start at 2 in 3 wtf is this code
i mean thats the idea..?
Then what is your mod probability for
change luck based events to be more lucky
thats it
But this just makes it a 4 in 3
why..?
Because you’ve set the base numerator to 2 and then doubled it when it rolls
is loc_vars making it 2 and calculate makes it not-visibly x2?
You need to have it in game for the modifying to work
ohhhh
and i was looking at my collection
thats so weird
It would crash if it did
i can understand why
so 1/odds is just a magic number i need to brute change and odds
Just delete the context inidivual block and change the 2 to a 1 in the loc vars function
If what you’re trying to do is change all probabilities
If you’re just trying to change bloodstone it’s different
i am trying to change all probabilities but to different values
SMODS.Joker:take_ownership('bloodstone',
{
config = { extra = {odds = 3, Xmult = 1.5} },
loc_vars = function(self, info_queue, card)
local numerator, denominator = SMODS.get_probability_vars(card, 2, card.ability.extra.odds, 'vremade_bloodstone')
return { vars = { numerator, denominator, card.ability.extra.Xmult } }
end,
calculate = function(self, card, context)
if context.individual and context.cardarea == G.play and context.other_card:is_suit("Hearts") and
SMODS.pseudorandom_probability(card, 'vremade_bloodstone', 2, card.ability.extra.odds) then
return {
xmult = card.ability.extra.Xmult
}
end
end,
},
true
)
this works
SMODS.Joker:take_ownership('bloodstone',
{
config = { extra = {odds = 3, Xmult = 1.5} },
loc_vars = function(self, info_queue, card)
local numerator, denominator = SMODS.get_probability_vars(card, 2, card.ability.extra.odds, 'vremade_bloodstone')
return { vars = { numerator, denominator, card.ability.extra.Xmult } }
end,
},
true
)
this may work too
Are you taking ownership of lots of things?
not yet but it will be 6 jokers, lucky cards and 2 seals
Right now, I am trying to get this message to appear every time I play a hand. I believe this is the right function needed to get this to happen, but nothing is. Even when I remove the context and just print, nothing happens. Does anyone know what I am missing or if it needs to be in a certain place? Right now, I just have it in a random file of my mod.
Yes, the file is being loaded. I have other items in the file and they are appearing.
what is your steamodded version?
smods-1.0.0-beta-1016c
is the mod calculate not inside some other function?
I am not sure. I don't think?
context.play_hand isn't a thing
the closest equivalent is probably context.press_play, which runs on Blind:press_play()
For actual hand information, the earliest is context.before
How would I be able to trigger a joker effect multiple times, such as having a joker give say 5 mult 10 times and then give xmult after that?
return {mult = number, extra = {mult = number, extra = {mult = number, extra = {mult = number, extra = {mult = number, extra = {xmult = number}}}}}}
Alright thanks
Changed the context, still not printing to the console.
Wait, nevermind
It did, just not in game for some reason
you need debugplus
I thought I had it installed. I redid my current mods after the last issue to see if they were part of the problem. Thanks for the help though!
if you do have it installed debugplus has a config option that disables things printing to the ingame console
sƃuᴉɥʇ ɹǝƃuɐɹʇs
how would I create a joker if 2+ specific ones are woned
if next(SMODS.find_card('j_modprefix_key1')) and next(SMODS.find_card('j_modprefix_key2')) then SMODS.add_card({set = 'Joker'}) end
ok, and would I make that trigger passivley, or do I attatch it into a joker
Is there a way to completely overwrite or "hide" the sprite the game uses for the playing cards? It's a weird question, but I promise it is important for something I'm making. I am talking about the white card the game uses before overlaying the suits and numbers to make the playing cards. I tried overwriting the one on the Enhancers.png or the one for Malverk, but I can't get it work. Any ideas?
Can anyone help me find where in the code the debug outlines (enabled with G+A) are drawn? They're useful, but they're so thick that it's almost impossible to see things when there's a lot of UI elements close together
I've spent a while trying to find it and can't figure it out
function Node:draw_boundingrect() in engine/node.lua:91 I'm pretty sure
Yeah I figured that out, but thank you for your help! :)
For some reason my copy of the code just had node.lua and event.lua missing for some reason lol
🤔
create a pull request
https://github.com/skyline69/balatro-mod-index
What does card_w do exactly in CardArea? I've tried looking at the code, and I can tell it has to do with the width of cards and does something with it to align the cards, but I can't figure out what exactly it does
Is there a way to manipulate the score requirement
i literally checked
It's okay! I know I miss things like that all the time lol
?
Is there any way to make a CardArea that's left-aligned without adding my own CardArea type?
That kind of looks like a typo, is the name correct?
i dont think so
which part, the prefix?
it is othe
Oh ok, just checking
Damn, now I have to figure out whatever this mess means
othe is your mod prefix, correct?
ye
First of all, that's not going to create a copy, that just makes a Joker of the same type
If you want it to copy editions, stickers, etc. you need to use copy_card I think
i want it to create itself
hey how would a boss blind get if an individual card is coring

Where is G.jokers initially defined?
game.lua probably
Aha, thanks
If I wanna do funny business when a single hand (not necessarily the first) beats blind, how to do it? I tried the following but the last if-statement doesn't trigger when I need it to
Edit with more intuitive yet not working logic:
calculate = function(self, card, context)
if context.blind then
card.ability.chips_so_far = 0
end
if context.after then
local last_hand_chips = G.GAME.chips - card.ability.chips_so_far
if last_hand_chips - G.GAME.blind.chips then
-- the good stuff that works when the above if-statement is True
end
card.ability.chips_so_far = G.GAME.chips
end
end
hmm, the difference calculation is flawed
it technically should check (by that above implementation) if all the score, not considering the previous hand, being over the blind chips, but it doesn't do that either
how do i make a joker check its own edition
I figured out the selection of back thing works if i skip the intro, but if i wait for the full thing to load it gives this error. How can I fix it?
i tried adding parenthesis and "or 0" but that did nothing
check if the value exists before accessing it
weird spot for in_pool to be called, but I don't see why that disqualifies my suggestion
fair enough
you should be able to do something like return x and x.y and x.y.z == "..."
okay i fixed it actually by adding a check to see if youre in a game
that also works yea
I'd just check if G.GAME.selected_back exists
kw ill find another wya
Hi there! Is there any examples or documentation on how to edit the popup messages, for instance the "NOPE" in WoF or the "upgrade" in Yorick?
Got it, you can put it in the localization by using k_package_effect = "Text Effect"
Why does I get an error on the first line
use a period, not a colon
the colon is only for if you're actually calling the function
and then you need to pass self as the first argument whenever you call eddy_the_edition
like that
but I dont understand why sometimes I am supposed to use self and some other times I need to pass all the argument
no you always need to pass all the arguments
you just need to add self before all the other arguments
so the first one is eddy_the_edition(self, edition, delay_sprites) and the second one is eddy_the_edition(self, 'e_giga_s_foil', delay_sprites)
ok but I don't think my shit is working cause like I want it to generate my edition like 10% of time when a foil edition is generate, pull, etc like whenever a foil is generate
local eddy_the_edition = Card.set_ability
function Card:set_ability(edition, delay_sprites)
local ret = eddy_the_edition(self, edition, delay_sprites)
if edition == 'e_foil' then
return eddy_the_edition(self, 'e_giga_s_foil', delay_sprites)
end
return ret
end
I have this right now btw
anyone know a way to change the rates of jokers spawning in the shop by rarity? like if I wanted to make uncommon jokers more common
oh wait i'm stupid lol
set_ability isn't used for editions in the first place
replace set_ability with set_edition, and the new arguments are (edition, immediate, silent, delay)
(don't forget to still add self as an extra argument when you call it)
oh ok thx
and your not stupid you just wasnt knowing what I want to do
Modify G.GAME.uncommon_mod
ok yeah I did correct the code but it still doesnt work
thank you
where can I see chances for stickers in VanillaRemake?
You can't, but it's 0.3
that means I cant change them too, right?
No, you can.
-- 8 Ball
SMODS.Joker:take_ownership('8_ball',
{
config = { extra = {odds = 2} }, -- extra off?
loc_vars = function(self, info_queue, card)
local numerator, denominator = SMODS.get_probability_vars(card, 1, card.ability.extra.odds, 'vremade_8ball')
return { vars = { numerator, denominator } }
end,
calculate = function(self, card, context)
if context.individual and context.cardarea == G.play and
#G.consumeables.cards + G.GAME.consumeable_buffer < G.consumeables.config.card_limit then
if (context.other_card:get_id() == 8) and SMODS.pseudorandom_probability(card, 'vremade_8ball', 1, card.ability.extra.odds) then
G.GAME.consumeable_buffer = G.GAME.consumeable_buffer + 1
return {
extra = {
message = localize('k_plus_tarot'),
message_card = card,
func = function()
G.E_MANAGER:add_event(Event({
func = (function()
SMODS.add_card {
set = 'Tarot',
key_append = 'vremade_8_ball'
}
G.GAME.consumeable_buffer = 0
return true
end)
}))
end
},
}
end
end
end,
},
true
)
why does my game crashes here? i guess its because of extra
Yes, it is.
thanks
I cannot figure out how to remove a joker from spawning for the life of me.
ive tried SMODS.Joker:take_ownership('j_joker', {
rarity = 4,
cost = 1,
})
to make it a legendary rarity so that it never spawns but does not work, is anyone able to help me out with how to remove this joker from the game entirely?
in_pool = function() return false end
that works, thanks, now I think my issue is a bit more complicated
without the banner mod, this works as intended you are the goat, however when I use banner mod, and I only have rare jokers selected the joker card still shows
is there a way to either delete the card all together or to make the game not restrict joker cards in the early rounds to being common/lower rarity?
completely new to modding balatro sorry if that makes no sense
how do i watch a joker
No, because Joker is the default joker.
okay thanks man, I appreciate it
made a workaround which makes it self destruct and gives another joker copying some other examples, thank you so much for your help, stopped me from going down a rabbit hole 🐐
question: how do i maek new blinds
code them in
i know that
but do i need to make new files for it or smth
no idea i'm.not a coder
💀
search tutorials
ehh
They can go into any file as long as it's loaded
Files are purely an organisation thing
...jokers it is
hi, when use debug plus to unlock a boss I made for my mod the game crashes
any idea why?
It also crashes if I unlock it normally and then visit it in the collection
I think it is related to the sprite not working
Eventhough it suposedly has the correct atlas and path to the png
you're missing the boss colour i think
ohhhh
I thought that wasn't necessary
thx!!
yeah the docs are missing that it is
did you set it as an animated atlas
I have just solved it, thx anyway
However I now have a new problem
I have this pos
And this are the boss images
but it gives me the red icon
instead of the purple one
blinds ignore the x value because theyre supposed to be animated
this is changed in the next smods release
ok, so I have to change the png to have them on a vertical line?
for now yes
ok, thx
how do i debuff all non-base (enhancement/edition) cards for a Blind.
use the recalc_debuff function in the blind; if you return true, the card card will be debuffed
note that the card that's passed to the function can be any card (including jokers)
so i would have to check the area?
however you want to check if the card is a playing card; checking the area is a bit tricky because playing cards can be in a couple of different areas during gameplay but that can work yea
card.area ~= G.jokers?
ye that should work
and how do i check if the card has any edition?
for the enhancement do i do SMODS.has_enhancement(card)....?
alr thanks
why won't this work? I'm trying to (for a blind) make it to where held-in-hand abilities will not trigger
local score_card_ref = SMODS.score_card
function SMODS.score_card(card, context)
if G.GAME.blind and (not G.GAME.blind.disabled) and G.GAME.blind.in_blind and G.GAME.blind.key == 'salmon' then
if context.cardarea == G.hand then
return nil
end
end
return score_card_ref(card, context)
end
I would also like to know how do I get the type of a consumeable (Tarot, Planet, Spectral)?
like G.consumeables.cards[1].what_here
.ability.set
have you considered using debugplus to eval dp.hovered while you're hovering over a card and now you can see everything contained in the card
oh i never used eval
but that's nice to know!
I have no clue what's wrong with this ^..
is it a string?
Yes
?
is it 'e_modprefix_edition' or 'modprefix_e_edition'?
e_ first
oh ok
also do you know why this wont work?... (i'm trying to make the blind disable all held-in-hand abilities)
local score_card_ref = SMODS.score_card
function SMODS.score_card(card, context)
if G.GAME.blind and (not G.GAME.blind.disabled) and G.GAME.blind.in_blind and G.GAME.blind.key == 'salmon' then
if context.cardarea == G.hand then
return nil
end
end
return score_card_ref(card, context)
end
no
so like c.edition.key == 'e_modprefix_edition'?
yes
Key is wrong
Woooooo performance improvement on my palette editor done!
A little longer to cache/load early, but makes up for it with much faster iterations later
how do I prevent that from happening like I hook the set_edition but know its doing it in the collection
There is probably a global that fix this
like if not G.Collection then
if not G.SETTINGS.PAUSED iirc?
hey how would ytou go about overriding another mod's localization entries
put the same keys in your mod's localization files
my mod needs to load before the mod i'm overriding for other reasosn
and make sure you have higher priority i think? so your override actually overrides the old localization
okay well then idk
Is there some context to check score after a played hand? When I do context.after, the first time it gives me that G.GAME.chips == 0 is true, so that doesn't help me.
Crash upon using hanged man on 2 cards
Added hover tooltips to my generated credits
very cool
Can Boss Blinds keep extra variables?
yes, stored in G.GAME.blind.effect
or just blind.effect if its in the blind calculate
Ah
How do you make it so a joker makes it so a run doesn't end until all hands are scored?
https://github.com/AlexanderAndersonAmenAmen/Handsome-Devils/blob/fdd4860d0d6e7f1d54d2741be5dc90b40ddda9be/lovely.toml#L72-L85 use this patch from a mod i work on, just replace the joker key check with another one
it works mostly fine besides like one wierd edge case bug thing that was reported once
which idk what causes that
Oh thx
Tried that but it didn't work
how so
whats the blind code
SMODS.Atlas({
key = 'clacklume',
path = "clackerblinds.png",
atlas_table = 'ANIMATION_ATLAS',
frames = 21,
px = 34,
py = 34
})
SMODS.Blind {
key = 'clacklume',
atlas = 'clacklume',
unlocked = true,
discovered = true,
pos = {x = 0, y = 3},
dollars = 5,
mult = 2,
boss = {min = 1},
effect = {suit = "Hearts"},
boss_colour = HEX("827144"),
calculate = function(self, blind, context)
if not blind.disabled then
if context.stay_flipped and context.to_area == G.hand and
context.other_card:is_suit(blind.effect.suit) then
return {
stay_flipped = true
}
end
end
end,
disable = function(self)
for i = 1, #G.hand.cards do
if G.hand.cards[i].facing == 'back' then
G.hand.cards[i]:flip()
end
end
for _, playing_card in pairs(G.playing_cards) do
playing_card.ability.wheel_flipped = nil
end
end,
loc_vars = function(self, info_queue, blind)
return { vars = {localize(blind.effect.suit, 'suits_singular')} }
end,
}```
that shouldnt change it
info_queue and blind don't exist in loc_vars
It happens in the loc vars function
is there any way to make h_chips visible on a card
Dammit
i have a consumable that adds +30 h_chips to 2 selected cards and they functionally work but still display with only their normal chips
How do you make it work then?
You mean perma_h_chips?
Or like, find the blind?
self.effect.suit
I don't think that would work well in collection
you would need to do the wheel method i think
oh in that case should it be G.hand.highlighted[i].ability.perma_h_chips instead of just G.hand.highlighted[i].ability.h_chips?
Yes.
okie thank you
It works!
which tbh idk how that works
No, blind.effect.suit doesn't seem to be changed.
Tho not in the collection
Oh btw how do you disable the vanilla boss blinds and override small and big blinds?
oh
Yes, you use collection_loc_vars
It works, thx
the mod object page
but it basically just tells you the function exists
what does the true/false in the second portion of ease_dollars do?
ease_dollars(mod, instant)
that doesn't really tell me much
Executes the change immediately instead of putting it into an event.
i see
G.E_MANAGER:add_event(Event({
func = function()
SMODS.add_card {
set = 'Kantine',
ability = {
}
}
return true
end
}))
this function summons a joker, and everything works functionally however how do i add a check that makes the summoned joker do something if it was spawned this way
key_append = self.key and hook create_card
how can I make a joker always be inmortal?
if context.check_eternal and context.other_card == card then return {no_destroy = true} end
thx
SMODS.Atlas({
key = "santile",
path = "jokers.png",
px = 71,
py = 95
})
SMODS.Joker{
key = "santile",
config = { extra = {odds = 4, chips = 150}},
pos = { x = 2, y = 3 },
rarity = 2,
cost = 5,
blueprint_compat=true,
eternal_compat=true,
perishable_compat=false,
unlocked = true,
discovered = true,
effect=nil,
soul_pos=nil,
atlas = 'santile',
calculate = function(self,card,context)
if context.individual and context.cardarea == G.play then
if SMODS.has_enhancement(context.other_card, 'm_stone') then
return {
chips = card.ability.extra.chips,
colour = G.C.CHIPS
}
end
end
if context.after and not context.blueprint then
for _, scored_card in ipairs(context.scoring_hand) do
if SMODS.has_enhancement(scored_card, 'm_stone') and SMODS.pseudorandom_probability(card, 'grasslanders_santile', 1, card.ability.extra.odds) then
SMODS.destroy_cards(scored_card, nil, nil, true)
end
end
end
end,
loc_vars = function(self, info_queue, card)
return { vars = {}, key = self.key }
end
}
does someone know of a library that add something simulair like the omega num from cryptid. but even bigger?
I want to make it so the destroyed card plays a custom sound and has the glass shatter animation, what's the best way to do that?
No, use context.destroy_card
Also how do you add an option like this in the config tab?
No, it's Talisman, but still no.
Yes, there isn't.
that is kinda a bummer
i mean
you are not getting bigger than talisman
unless youre tryna do like bignum hyperoperators
that's like literally the only way to go above i believe
even then it gives you Infinity instead of naneinf
the limit is 1e308{1e308}1e308
so yeah
idk what it actually does when you reach it tbh because ive never seen it
every supposed Infinity ive seen is most definitely just talisman changing how NaN is displayed for whatever reason
what does cryptposting even have that can get that big
uhhh
yeah
no you just need to manually do that
wdym
with lenient_bignum iirc
oh ew
cryptid does that
i mean for scaling jokers??
yeah
does it still work
it would be really bad if talisman just started touching random values of jokers
so you have to do it manually to get above 1e308 values
dont, dont say it that way
i will say it that way
i dont wan to think of talisman randomly touching
lets not take a look
oh right this is #💻・modding-dev
why doesn't this work?
SMODS.Consumable {
key = "stars",
name = "Stars",
set = "Lenormand",
pos = {x = 8, y = 2},
config = { extra = { levels = 1 } },
cost = 4,
atlas = "consumable",
loc_vars = function(self, info_queue, card)
return {
vars = {
card.ability.extra.levels,
G.GAME.skips or 0
}
}
end,
can_use = function(self, card)
return G.GAME.skips ~= 0
end,
use = function(self, card, area, copier)
local used_card = copier or card
local target_hand
local available_hands = {}
for hand, value in pairs(G.GAME.hands) do
if value.visible then
table.insert(available_hands, hand)
end
end
target_hand = #available_hands > 0 and pseudorandom_element(available_hands, pseudoseed("c_chm_stars")) or "High Card"
return {
level_up = card.ability.extra.levels * G.GAME.skips,
level_up_hand = target_hand
}
end
}
it just does nothing when used
Yes, it's SMODS.is_poker_hand_visible(hand) not value.visible, also returns in use functions don't do anything.
Replace the return with SMODS.calculate_effect
oh so just like this
SMODS.Consumable {
key = "stars",
name = "Stars",
set = "Lenormand",
pos = {x = 8, y = 2},
config = { extra = { levels = 1 } },
cost = 4,
atlas = "consumable",
loc_vars = function(self, info_queue, card)
return {
vars = {
card.ability.extra.levels,
G.GAME.skips or 0
}
}
end,
can_use = function(self, card)
return G.GAME.skips ~= 0
end,
use = function(self, card, area, copier)
local used_card = copier or card
local target_hand
local available_hands = {}
for hand, value in pairs(G.GAME.hands) do
if SMODS.is_poker_hand_visible(hand) then
table.insert(available_hands, hand)
end
end
target_hand = #available_hands > 0 and pseudorandom_element(available_hands, pseudoseed("c_chm_stars")) or "High Card"
SMODS.calculate_effect({
level_up = card.ability.extra.levels * G.GAME.skips,
level_up_hand = target_hand
})
end
}
added the parentheses bc i've seen it done with parentheses elsewhere
No, put used_card as the second input for SMODS.calculate_effect
so just
SMODS.calculate_effect({level_up = card.ability.extra.levels * G.GAME.skips, used_card})
No, outside of the table.
Also put the level_up_hand back.
okay okay i see so this
SMODS.calculate_effect({
level_up = card.ability.extra.levels * G.GAME.skips,
level_up_hand = target_hand
}, used_card)
Idk what to hook so my custom edition can be considered as a other enhancement.
Like I know how it work with enhancement, by hooking SMODS.has_enhancement
SMODS.get_enhancements.
like if my card has a custom edition, a calculate has card.edition.type == 'foil' and the custom edition is consider as a foil it should return true
still hook the same right? since youre still making something count as another enhancement
oh editions
yeah edition
idk take the seals on everything code because it probably has quantum editions
i wouldnt be suprised if it did
No, it would be card.edition.foil
Yes, it has quantum everything, I've already told you this.
ok
idk how literal "everything" was 😭
hmmmmm
Idk if like it is what I am looking for
cause I want to do th same thing as that but for edition
You can't, because there is no has_edition function.
Yes, but it can break.
yeah
I mean imagine Steamodded add SMODS.has_edition or something like that
how do I add ui elements to a premade ui such as the ui thats between blinds and shops
like for the payout
You can patch it in with the right target, just redeclare the UI entirely or partially (i.e. change a node list table), or do some funky table.insert stuff (which, if given three values, the first is the target table, the second is the index to insert into, and the third is the data being inserted)
The last one is painful tho
I know how to use table insert
Ill try both
starting with patching
do you have any idea on what file it is?
Usually functions/ui_definitions.lua
The big question is "which function" which i dont remember
hey guys
hey
we're making a new server for modders, where we have a whole server instead of just a couple channels to discuss mods
to like get more feedback and help with code or art and stuff
and we do weekly promos of mods of random members
we get to break all of the rules in #📜・modding-rules btw (lies)
is there a way to save a card to joker's config for later use? trying to have it save a card when scored then copy it at end of round
i saw that card:save() and card:load() exist but idrk how to use them or if theyre even useful here, this just freezes and crashes the game
if context.individual and context.cardarea == G.play then
card.ability.extra.storedcard = context.other_card:save()
elseif context.end_of_round then
local _card = SMODS.add_card({set = 'Base', area = G.hand, rank = 'A', suit = 'S'})
_card:load(card.ability.extra.storedcard)
end
Log?
you mean crash log? dont got one that i can see, it just freezes and i have to end process
unless theres one saved somewhere in the process
No, I mean the one in Mods/lovely/log
for reference before it crashed all i did was load the debug+ slot and play a winning hand with the joker owned
How long was it frozen before you closed it?
well it started freezing pretty much right as the round ended
the animation of the cards flying around was still going on and it just did that thing where it stops and eventually it said its not responding
so probably like ~10 seconds or something? roughly
Try waiting longer and see if anything appears in the lovely console.
the lovely console? is that different from the debugplus console? sorry im not too familiar with lovely itself
oh i think you mean the command prompt looking thing
ok ive given it a minute or two, nothing
i assume its something to do with me using card:save() and/or card:load() incorrectly
How would I go about making a joker predict the next three boss blinds? I'm actually so lost right now.
since it's freezing it's most likely an infinite loop somewhere
Also, what should localization look like for a sticker?
modprefix_key in Other i think
i'm having fun :D
yep :D
How would I reference a joker with a given sticker in that stickers code? I'd like to destroy and give 4x a jokers sell value if it has the sticker.
if card.ability.modprefix_key
Nearly nearly nearly finished my palette editor. Just working on saving and loading presets now
I am currently trying to add my own suits, as well as Apostles that correspond with those custom suits.
However, I'm not sure how to take ownership of the rank in a way that allows it to use Paperback's existing atlas and the new atlas for my custom suits, because otherwise, it would require copying paperback's existing file which will break with new versions of paperback (+ inconvenient)
Am I brainfarting, why are button nodes are getting placed horizontally despite their parent node being a column node?
Nvm i realized
why is my dynatext red :(
DynaText({string = {" ".."Grade Achieved", colours = {G.C.UI.TEXT_LIGHT}, shadow = true, pop_in = 0, scale = 0.4*scale, silent = true}})
patched in btw
need help with a thing
the text of the ui preceding the text_input isn't showing up until i click the text input
function G.UIDEF.overstock_overview()
local ref_table = { card_key = "j_joker", cutoff = G.GAME.interest_cap }
return create_UIBox_generic_options({ back_func = 'exit_overlay_menu', contents = {
{n=G.UIT.C, config={align = "cm", padding = 0.2, r = 0.2, colour = G.C.BLACK}, nodes={
{n=G.UIT.R, config={align = "cm"}, nodes={{n=G.UIT.T, config={text = localize("k_overstock_menu"), scale = 1, colour = G.C.UI.TEXT_DARK}}}},
{n=G.UIT.R, config = {minh=0.5}},
{n=G.UIT.R, config={align = "cm"}, nodes={{n=G.UIT.T, config={text = "Key of card:", scale = 0.45, colour = G.C.WHITE}}}},
{n=G.UIT.R, config={align = "cm"}, nodes={create_text_input({
w = 4, max_length = 64, prompt_text = localize('k_overstock_enter_id'),
ref_table = ref_table, ref_value = 'card_key', keyboard_offset = 1, extended_corpus = true
})}},
{n=G.UIT.R, config = {minh=0.1}},
{n=G.UIT.R, config={align = "cm"}, nodes={{n=G.UIT.T, config={text = localize("k_overstock_cutoff"), scale = 0.45, colour = G.C.WHITE}}}},
{n=G.UIT.R, config={align = "cm"}, nodes={create_inline_number_select({
w = 2, colour = G.C.MONEY, h = 0.5, ref_table = ref_table, ref_value = 'cutoff', prefix=localize'$', default = math.min(G.GAME.interest_cap, 50), step = 1, min = G.GAME.bankrupt_at
})}},
{n=G.UIT.R, config = {minh=0.1}},
{n=G.UIT.R, config = {align = "cm"}, nodes={{n = G.UIT.C,
config = {align = "cm", r = 0.1, minw = 1.5, minh = 0.6, hover = true, colour = G.C.GREEN, shadow = true, focus_args = { type = 'none' }, button = "overstock_start_rerolling", ref_table = ref_table},
nodes = {{n=G.UIT.T, config={text = localize('k_reroll'), scale = 0.5, colour = G.C.WHITE, shadow = true}}}
}}},
}}
}})
end
(for those interested the key card input thing is probably not final if i can find any other better way of putting it in that doesn't give me a fucking migarine with cross mod stuff)
G.OVERLAY_MENU:recalculate()
but when?
Ommediately after you create overlay
Quick question, is there a context I could use for a joker that happens just after a hand is scored? I want the joker's sprite and text to change after the hand is played to sort of establish what to do and then after the hand fully plays out then it changes, not before it like with context.joker_main, if not is there a place I could find all the contexts for Balatro? Thanks
context.after
It's kind of funny to ask this question and have it answered with someone with such a perfect username, thank you
There is also a semi complete list on the smods wiki
Ah gotcha
last i checked smods isn't really built to handle this yet
the relevant code is a bit of a mess that nobody wants to wade into
what's the easiest way yall think i can make legendries spawn in shop as normal jokers ? but make them rare so it's not too op
taking ownership of the legendary rarity and giving it a non zero spawn rate would be my first thought
i thought about doing that but idk where to start
Idk how to answer the first part but try utilizing the spawn rate of normal jokers and apply a lower one to legendaries
Maybe look at the code for the vouchers that make tarots and planets spawn more often and see if that helps you
ooh thanks a lot <:
I wouldn't know if it does
i'll check it out
thank you for the suggestions
Take my advice with a grain of salt I can only imagine how code would corrolate
test if taking ownership works by giving legendary a weight of like a billion, then if it does change it to a more balanced number
thats a shame
looks like I may need to do the inconvenient method likely
how do i check the internal key of jokers ?
search the localization file for its name
but if you're editing the legendary rarity itself you shouldn't need to handle any individual jokers
oh wait i can edit the ENTIRE legendary rarity ? how
it's the thing I've been talking about this whole time???
mb 😔 what i had in mind was changing each legendary joker
How do I have my card back add jokers? I tried doing it the same way the ghost deck adds Hex in https://github.com/nh6574/VanillaRemade/blob/main/src/backs.lua but am getting a crash which reads, "attempt to index local 'center' (a nil value)"
eventually, I cannibalized Aikoyori's method of crossmod apostles to create this
why are you upside down
why arent you?
they fell
anyone know how to correctly use card:save() and card:load()? i dont think this is right since it freezes and crashes the game
commenting out the load() prevents the crash so its definetely something wrong there
save and load are for saving the card to the run's save state, if anyone told you to use them for this they probably meant that you need to hook those functions to prevent the crash from trying to save a card inside a card
personally ive never done that because there are other ways to accomplish that without saving a card inside a card
how do you watch a joker
ah that figures
thanks N'
like realtime changes, just like how you watch shader
i figured it'd be easier to edit my localization that way
you cant
damn it
you could look into how the game reloads localization to recreate that
i think wilson was talking about adding it?
@rough furnace real?
Is that one balatro text tool not accurate enough?
where
hm
Theres multiple it seems, just google "balatro text tool"
okay i need some lua help
i have a "root" table and a "hierarchy" table, and i want to insert an value to the root table via the hierarchy table indexes and create an empty table if a corresponding table doesnt exist
for example, lets say the root table is {other_key = "other_val"}, the hierarchy table is {"j", "a", "k"}, and the value i want to write to it is "val"
how would i write a function so that the root table turns into {other_key = "other_val", j = {a = { k = {"val"}}}}
probably a really stupid question but im really tired and i cant figure it out
nvm figured it out
wdym? did i not type it right?
SMODS.Blind {
name = "salmon",
key = "salmon",
...etc...
}
local score_card_ref = SMODS.score_card
function SMODS.score_card(card, context)
if G.GAME.blind and (not G.GAME.blind.disabled) and G.GAME.blind.in_blind and G.GAME.blind.key == 'salmon' then
if context.cardarea == G.hand then
return nil
end
end
return score_card_ref(card, context)
end
bl_modprefix_key
ohhhh 😭 😭 😭 😭
how do i do the second one
if context.debuff_card and context.debuff_card.ability.set == "Joker" then return { prevent_debuff = true } end
update or calculate?
did i set this up properly?lua use = function(self, card, area, copier) if not next(SMODS.find_card('j_busterb_saitama')) then local deletable_jokers = {} for k, v in pairs(G.jokers.cards) do if not SMODS.is_eternal(v) then deletable_jokers[#deletable_jokers + 1] = v end end G.E_MANAGER:add_event(Event({ trigger = "before", delay = 0.75, func = function() for k, v in pairs(deletable_jokers) do v:start_dissolve(nil, _first_dissolve) _first_dissolve = true end return true end, })) G.E_MANAGER:add_event(Event({ trigger = 'after', delay = 0.4, func = function() play_sound("timpani") local card = create_card("Joker", G.jokers, nil, "busterb_Grandiose", nil, nil, nil, "busterb_Fantasy") card:add_to_deck() G.jokers:emplace(card) card:juice_up(0.3, 0.5) return true end })) delay(0.6) else G.E_MANAGER:add_event(Event({ trigger = 'after', delay = 0.4, func = function() play_sound('timpani') SMODS.add_card({ set = 'Joker', rarity = "busterb_Fantastic" }) card:juice_up(0.3, 0.5) return true end })) delay(0.6) end can_use = function(self, card) return G.jokers end end,
test it..?
ok
maybe change can_use to
can_use = function(self, card)
return G.jokers and (#G.jokers.cards > 0) or false
end
card in question
also, i think i found poopshit indentation
i don't think can_use should be put in use
oh yeah
dynatext
dynatext?
that's not what dynatext does
unless i'm misunderstandinf what you want
do you want a joker's localized text to update in real time?
yes
they want it to update in real time as they're editing it
but even if they wanted it to change dynamically dynatext is not necessary
dynatext is just animated text
ok well what about using consumables that should debuff jokers?
That should also work
Though if the consumable is coded wierdly that might change things so i dont know
Is there a template to mod the text (like the mod Dr Spectred uses)?
not even the perishable sticker is being prevented by the joker
check any localization in any mod but use the vanilla keys instead
steamodded changes some text like lucky cards too
are there existing jokers that prevent other jokers from being debuffed?
modded ones
there are a couple in joyousspring
they just do SMODS.debuff_card(card, "prevent_debuff", "key")
how do i spawn a booster pack
how do i use this SMODS.debuff_card?
in the shop?
yes
SMODS.add_booster_to_shop
for my papyrus joker, it's SMODS.add_booster_to_shop("p_arcana_mega_1")
how do i use this SMODS.debuff_card thing
can you "update function > for loop on jokers > smods debuff card"?
or is that impossible
it's not impossible but it depends on what you want to do
this is not meant to be applied continuously
i would do it in that joker's add_to_deck and remove_from_deck
that's how i do it in my mod
you don't need to
wha
the function prevents any joker from being debuffed
oh i forgot that you also need to apply it to new jokers
i want it to remove debuffing from all jokers at all
yea
this is how i do it
i have a function that applies to added jokers below but you can use context.card_added instead
https://github.com/nh6574/JoyousSpring/blob/0a5c0f6951f7f3073acb7f06ee1fafed950eef16/src/jokers/20Invoked.lua#L1169
this has a bug with multiple copies that ive only just realized lol i fixed it in other jokers
which joker
how to check if jokers are debuffed
joker.debuff
but again, you don't need to for this
it's spright sprind i think? basically i just made the source strings unique
like this?lua add_to_deck = function(self, card, from_debuff) if context.card_added then SMODS.debuff_card(joker, "prevent_debuff", "j_joy_invoked_meltdown") end end,
i think this should be for calculate
i'm probably doing too much
i'll test this tomorrow
remove_from_deck needs to have false instead of "prevent_debuff"
so it removes it
Ok (turned off puter, will do it tomorrow, wondering if this is at most 99% foolproof)
This crashes on rerolling the shop; anyone got any guess as to why or how to fix it?
I think its where it says card.ability.extra.rolls >= rolls_needed,
instead of rolls_needed it should be card.ability.extra.rolls_neededas your getting it from the config
you're welcome! 
Watch center works with loc_txt. There was some code for reloading localization I was looking into (like the reload atlases) but there were some issues I was wanting to iron out first
Debugplus' watch is such a nice feature
fellow devs
need me some technical support
how would i check if a card from a given string key both 1. exists and 2. is available in the top part of the shop
---@param card_key string The key of the card to check.
---@return boolean
local function can_reroll_into(card_key)
-- ...
end
local function can_reroll_into(card_key)
local center = G.P_CENTERS[card_key]
if not center then return false end
if not center.unlocked then return false end
if G.GAME.banned_keys and G.GAME.banned_keys[card_key] then return false end
if center.no_appear_in_shop then return false end
if (({
Enhanced = true, Edition = true, Back = true,
Spectral = G.GAME.spectral_rate <= 0, Code = G.GAME.code_rate and G.GAME.code_rate <= 0
})[center.set]) then return false end
return true
end
this is what i have so far
Can't you just check if the card is in the pool?
local pool = get_current_pool(center.set)
for k, v in pairs(pool) do
if v == center.key then
return true
end
end
```?
Log?
no crash
i havent made it
i removed it again since it just doesnt work
then i went to bed and now its morning
so I dont have a save
@daring fern ?
SMODS.Joker {
key = 'Rubber_ducky',
pools = { ["Scalala"] = true, },
loc_txt = {
name = 'Rubber ducky',
text = {
"Spawns a copy of self at end of round"
}
},
rarity = 1,
cost = 6,
blueprint_compat = true,
eternal_compat = true,
perishable_compat = true,
unlocked = true,
discovered = true,
atlas = 'Jokers',
pos = { x = 1, y = 0 },
config = { extra = {
},
},
loc_vars = function(self, info_queue,center)
return { vars = {} }
end,
calculate = function(self, card, context)
if context.end_of_round then
SMODS.add_card {
key = 'Rubber_ducky',
set = 'Joker'
}
end
end
}
why does this give me that error
SMODS.add_card({key = self.key})
But if you want it to be a true copy, you should use copy_card
Also it would be if context.end_of_round and context.main_eval
i want it to spawn one at the end
so if you have two of this joker
it still gives one
Yes, but do you want it to just spawn a fresh version of the joker, or do you want to actually copy the joker?
wdym fresh version?
A version of the joker that does not have any properties from the original joker, and can spawn with other properties, like it could spawn with foil.
oh yes
i want that
i was thinking maybe they spawn negative
bcs i want the base joker to be weak
Then you would do this: #💻・modding-dev message
does it need a mod prfexi?
No, because you're not putting the key anywhere.
self.key is the key of the joker, with prefixes.
SMODS.Joker {
key = 'Rubber_ducky',
pools = { ["Scalala"] = true, },
loc_txt = {
name = 'Rubber ducky',
text = {
"Spawns a copy of self at end of round"
}
},
rarity = 1,
cost = 6,
blueprint_compat = true,
eternal_compat = true,
perishable_compat = true,
unlocked = true,
discovered = true,
atlas = 'Jokers',
pos = { x = 1, y = 0 },
config = { extra = {
},
},
loc_vars = function(self, info_queue, center)
return { vars = {} }
end,
calculate = function(self, card, context)
if context.end_of_round and context.main_eval then
SMODS.add_card({
key = self.key })
end
end
}
```this currently just freezes my game tho
if context.end_of_round and context.main_eval and not card.modprefix_no then
local drac = SMODS.add_card({key = self.key})
drac.modprefix_no = true
G.E_MANAGER:add_event(Event({func = function() drac.modprefix_no = false return true end}))
end
guys.
is there a context
that can trigger when a blind is skipped
but like before getting the tags?
this works but if i have two i gain four and if i have four i gain eight etc etc
how do i make it just one?
Do you always want it to only be one or only ones that are not copies?
Remove the event.
so a invis or anhked ons till makes two
i dont think so
how would I make a joker appear flipped
like
when smth goes off in calculate, make it do a 180
like this
you can add a function to the card object that adjusts the rotation in the shader
which every card object needs to have in order to be able to dissolve
pretty sure there are other jokers that exist already and flip themselves like that, although i can't think of a specific example off the top of my head
aiko?
if you mean the aikoyori self insert joker, then that's just the soul sprite spinning unattached to any calculates. so it's probably applicable but would need a lot of tweaking
if you mean another joker in aikoshen then yea maybe that sounds like something in aikoshen
i dont know something similar tbh
i distinctly remember some joker that had one effect and then it'd flip at the end of the round and have another effect for the next round
although i might be conflating that with a joker from polterworx that toggled between effects but didn't actually do the physical rotation part
flip flop from fusion jokers?
that has two entire sprites it flips between
hm, I'm remembering a joker that has four states and rotates between them
but it might do the same thing. i don't remember what mod it was from so i can't check
the only way i know how to do it is to rotate the card object but that also flips the buttons upside down
Great how would I get G in a place where G doesnt exist yet
You wouldn't, because it doesn't exist yet.
Even if it did it would have nothing in it.
I mean like an alternative
actually no
im dumb
im too locked in on smods
nvm
i cant just make it a function on its own
thoguhts on the balance of this
Why the hell does this happen? why does it not stay locked 😭, this code is taken off vremade's code for the standard tag,
Goal: when I click cashout (custom context that works) give me a standard pack
thats all that matters
What is the problem exactly?
Or are the problems that the shop opens, the shop goes away when you close it, and that you can select infinite cards?
You mean the shop should be locked from opening?
G.CONTROLLER.locks[lock] becomes false like a few frames after set to true
i dunno how to make it not
No, it should be 0 frames, because you're doing it at the same time you're setting it to true
Put it in an event.
ahh
ty for ur patience
err did you mean like this
local lock = "R-pack-".. math.random()
G.CONTROLLER.locks[lock] = true
G.E_MANAGER:add_event(Event({
func = function()
local booster = SMODS.create_card { key = 'p_standard_mega_1', area = G.play }
booster.T.x = G.play.T.x + G.play.T.w / 2 - G.CARD_W * 1.27 / 2
booster.T.y = G.play.T.y + G.play.T.h / 2 - G.CARD_H * 1.27 / 2
booster.T.w = G.CARD_W * 1.27
booster.T.h = G.CARD_H * 1.27
booster.cost = 0
booster.from_tag = false
G.FUNCS.use_card({ config = { ref_table = booster } })
booster:start_materialize()
return true
end
}))
G.CONTROLLER.locks[lock] = nil
or am I dumb, I did try G.CONTROLLER.locks[lock] = nil before return true, and I've done the same with G.CONTROLLER.locks[lock] = true
because its not working
And I dont know what you mean man
Have you tried doing it on context.starting_shop instead?
question: how 2 make booster packs
You mean you want to add 2 booster packs to the game or create 2 booster packs in game?
make a booster pack
i wanna add booster packs to my mod
- How do I access the table where all owned consumables live
- How do I modify how many slots a existing consumable takes up
I believe both of those are properties of G.consumeables. The first is “cards” and I forget the second
G.consumeables.cards and card.ability.extra_slots_used
set it to a negative (not int) value?
(for less slots taken up)
Yes.
Does that work for playing cards?
Yes, if you're referring to the second one.
Nice
it seems to have accessed the wrong cardarea
also @timid parrot
yeah?
you also replied to my question
Code?
local consumables = G.consumeables.cards
for i = 1, #consumables do
local v = consumables[i]
local adjustvalue = card.ability.extra_slots_used
local timesdivided = card.ability.compressed_times_divided
-- you can't halve zero!
if adjustvalue == 0 or adjustvalue == nil then
card.ability.extra_slots_used = -0.5
card.ability.compressed_times_divided = 1
else
card.ability.extra_slots_used = -(1/(2*timesdivided))
end
end```
You would change card to v
I was just gonna point you to a joker I made to adjust consumable slots https://github.com/Eman-3600/BalatroOnTheClocktower/blob/master/jokers/turkey.lua
card rot
no i see the issue here
but the extra_slots_used thing sounds better
No, you should use CardArea:change_size
ah
I assume that runs some extra routines that modifying the variable doesn't?
No, CardArea.config.card_limit isn't actually a real value.
if that's not a real value then idk why it works lmao
Because it makes it change CardArea.config.card_limits.mod instead of CardArea.config.card_limit
what are the parameters?
delta
Fully featured (mostly)
I need to add an option on the hud to edit the badge color
Now if I only I could figure out how to manage the garbage that reloading this palette seems to create b/c even though I should've done the memory management required for FFI pointers, it's still slowly tanking the framerate every time the palette is refresshed 🤷♀️
How do I get the most recently used consumable of a custom consumable type?
No, you have to set it manually.
and how would I do that?
SMODS.current_mod.calculate = function(self, context) if context.using_consumeable and context.consumeable.ability.set == 'key' then G.GAME['last_'..context.consumeable.ability.set] = context.consumeable.config.center.key end end
where would I put that?
what causes it to display this
In the main file.
You mean the ERROR?
yes
You need group_name in loc_txt or group_key = 'Pack Pack' in Localization > misc > dictionary
thanks
where and how do i insert it specifically am lost
Do you use loc_txt or a localization file?
file
why does the game crash when i hover over my new consumable
update: my dumbass forgot to use '' instead of "" 😭
Why are you yelling :(
why they gotta be so similar istg
It would be group_key or if you don't define the group key it would be k_booster_group_boosterkey
nvm the problem persists
ah thanks
Did you input the seed first instead of the table in pseudorandom_element?
not talking about that problem tho
the one w/ the booster pack has been fixed
Yes, I'm referring to this: #💻・modding-dev message
You wouldn't check the card.