#💻・modding-dev
1 messages · Page 670 of 1
i may just
look at how debugplus does it
oh that isn't a hook
at least not a love.textinput one
local input = ui.TextInput.new(0)
local orig_textinput
local function textinput(t)
if not consoleOpen then
if orig_textinput then
orig_textinput(t)
end -- That way if another mod uses this, I don't clobber it's implementation
return
end
input:textinput(t)
end```
yea i tried looking at debugplus too, it's a bit strange
yes
that's why i suggested doing it in an event, love.textinput might not exist in the first instant or so of booting the game so you'd have to wait to define the hook until later
you should probably hook something like SMODS.injectItems and do it in there then
i doubt the event manager is initialized that early in loading
true
is where most mods are
also you should probably ask this in #⚙・modding-general or #⚙・modding-support
where can i find info on SMODS.injectItems?
i dont think its documented anywhere
but its usually hooked if something needs to be done later in loading
so what would the hook look like,,?
local inj = SMODS.injectItems
function SMODS.injectItems(...)
inj(...)
--hook love.textinput here
end
should prob also mention,, it only happens when i click a key, not at startup
oh
well yea that makes sense
the game doesn't actually try to call the nil value until love.textinput is run
so yea
it does this even in injectItems
another weird thing
it's definitely a problem with the local variable since the traceback shows that it is running love.textinput correctly otherwise
install balatro mod manager, it's a balatro mod browser app
bmm stinky
you can use the "ingame mod manager" instead
yea i'm stumped
and a print shows that love.textinput is nil when the hook is made
i may just make a slight hacky solution and if there's nil then it makes an empty love.textinput before the hook
worth a try
okay that worked
what's the issue with bmm
works well for me
most mods arent on there
because its hell for devs
also it downloads a wierd useless patch folder for no reason
which has only caused issues in the past
how is it hell for devs
i've submitted 2 mods to it it's very simple
it's frequently caused issues while updating steamodded, it installs its own useless "BMM-Compat" mod that does nothing smods doesn't already do, and yea it's missing a lot of mods as per eris
having to fork a github repository and create a pull request after adding your mod is very dev unfriendly
instead of just a proper upload form or something
Build and submit Balatro Mod Index pull requests with validated metadata, download URLs, and markdown preview support.
my biggest problem is the install issues
its still a very strange way of uploading and indexing mods regardless
and also very slow
and yeah it also frequently has issues installing mods
to me the initial upload is not the unfriendly part but wanting to update afterwards
or even requesting removal
like yes, you dont have to upload mod updates manually but if you want to change the description you need to pr again afaik
you do yeah
i also think it was lazy of the devs of it to supposedly never consider actual dependency management when that is very feasible
so what's imm then, because when you google it all you get is bmm
instead its just Does your mod need steamodded or talisman
like great what if my mod needs something else
its a mod manager thats ingame
the fact that bmm has a webpage to upload mods that nobody knows about speaks volumes
also yeah webpage isnt ever mentioned anywhere as far as i can tell
not on the bmi repo or the bmm website
or bmm repo
im so geeked i have to implement brainfuck in lua
im not going to copy from elsewhere that would be boring
looking at imm
isn't it based on bmi, making it basically the same as bmm
it pulls from a ton of different places
it also uses thunderstore (and i think photon?)
not just the BMI
photon is also great
yea it pulls from thunderstore, photon, and i think there's another one?
point is if your mod can be managed elsewhere it can be managed via IMM basically
the imm dev is also an active member of the community and easily contactable
this is the biggest plus for me
i don't know what the fuck i expected
while true do end indeed
i was originally going to do something else but i think today is Brainfuck Joker Day
genius!
try wrapping it in another pcall perhaps 
one thing i like about bmm is being able to boot the game without starting steam lol, kinda minor but i like it
...you can just make a shortcut to the executable yourself and do it that way too.
i guess if you write "+[]" in the brainfuck joker your game is just gonna crash
you probably deserve it anyway
ok so
i wanna do an effect
that chooses 2 card ranks randomly every round
like mail in rebate
is that a thing i can do?
https://github.com/nh6574/VanillaRemade/blob/f1cc39c18475a3aa866817d579caefb6a53dca40/src/jokers.lua#L4772 do you also have this to actually run that
ugh im still stuck D:
loc_vars = function(self, info_queue, card)
return { vars = { card.ability.extra.dollars, localize(SMODS.current_mod.reset_game_globals(run_start)) } }
end,
calculate = function(self, card, context)
if context.discard and not context.other_card.debuff and
context.other_card:get_id() == SMODS.current_mod.reset_game_globals(run_start) then
G.GAME.dollar_buffer = (G.GAME.dollar_buffer or 0) + card.ability.extra.dollars
return {
dollars = card.ability.extra.dollars,
func = function() -- This is for timing purposes, it runs after the dollar manipulation
G.E_MANAGER:add_event(Event({
func = function()
G.GAME.dollar_buffer = 0
return true
end
}))
end
}
end
end
}```
so this is just the mail in rebate code
but i replaced the stuff that specifically said mail in rebate
just doing this as a start
it's causing the game to crash tho
why are you doing == SMODS.current_mod.reset_game_globals(run_start)
that is the function that changes the value. not the value itself
plus current_mod doesnt exist after load
what should i replace it with? :[
with whatever value youre setting in the reset function
im not getting it ;-;
you need to create a function that changes the rank (https://github.com/nh6574/VanillaRemade/blob/f1cc39c18475a3aa866817d579caefb6a53dca40/src/jokers.lua#L2376)
and then call that in SMODS.current_mod.reset_game_globals (https://github.com/nh6574/VanillaRemade/blob/f1cc39c18475a3aa866817d579caefb6a53dca40/src/jokers.lua#L4772)
so i'd but this in the lua?
i dont think im gonna mess around with random ranks for a while
this stuff is just not computing with my brain
can someone playtest my mod?
this is the wrong channel pal, 98% of mod devs don't play the game
this is so real lol
can someone modtest my play
thats a lot to ask, im not sure if i possibly could
can some mod play one my test?
can some test one mod my play?
Can someone tell me how would I make a sticker for jokers that, when specific ranks are played, has a 1/2 chance of triggering the joker it’s applied to?
You probably want to look into forcetrigger functionality from spectrallib
If youre willing to add additional dependencies to your mod that is
Since there isnt really a way to generically trigger any joker normally
my code still doesn't work i want to DIE, if you do have instructions please try to be a little bit more specific please! SMODS.Joker {
key = "Universe",
loc_txt = {
name = "Universe",
text = {
"retrigger all played cards {C:attention}2{} times",
"if all played cards have",
"the {C:attention}same{} Enhancement"
},
},
config = {extra = {repetitions = 2}},
--unlocked = true
rarity = 3,
blueprint_compat = true,
eternal_compat = true,
Atlas = "jokerimage",
pos = { x = 0, y = 0 },
cost = 7,
loc_vars = function(self, info_queue, card)
return { vars = {context.repetiton} }
end,
message = localize('k_again_ex'),
calculate = function(self, card, context)
if context.repetition and context.cardarea == G.play then
local enhancement = context.full_hand[1].config.center_key
for i = 2, #context.full_hand do
if context.full_hand[i].config.center_key ~= enhancement then
return nil
end
end
return {
repetitions = card.ability.extra.repetitions,
}
end
end
}
can you please codeblock that
i kinda dont know how since im new to coding...
triple ` either side
SMODS.Joker {
key = "Universe",
loc_txt = {
name = "Universe",
text = {
"retrigger all played cards {C:attention}2{} times",
"if all played cards have",
"the {C:attention}same{} Enhancement"
},
},
config = {extra = {repetitions = 2}},
--unlocked = true
rarity = 3,
blueprint_compat = true,
eternal_compat = true,
Atlas = "jokerimage",
pos = { x = 0, y = 0 },
cost = 7,
loc_vars = function(self, info_queue, card)
return { vars = {context.repetiton} }
end,
message = localize('k_again_ex'),
calculate = function(self, card, context)
if context.repetition and context.cardarea == G.play then
local enhancement = context.full_hand[1].config.center_key
for i = 2, #context.full_hand do
if context.full_hand[i].config.center_key ~= enhancement then
return nil
end
end
return {
repetitions = card.ability.extra.repetitions,
}
end
end
}```
the only thing I'm spotting that's wrong with this is Atlas instead of atlas, which would cause the sprite to be wrong
also this is both wrong and completely irrelevant as you've put no variables in your description
neither of these things should concern the functionality of your joker though
so what's not working exactly
its supposed to retrigger cards played if they all have the same enhancement, but the retriggers never occur, even if they are of the same enhancement
have you started a new run since changing the config?
no let me go test this
that'd be it. you always need to do that. config just holds default values, a pre-existing card will continue to have the old values
can i see that
sure gimme a minute
SMODS.Joker {
key = "Universe",
loc_txt = {
name = "Universe",
text = {
"retrigger all played cards {C:attention}2{} times",
"if all played cards have",
"the {C:attention}same{} Enhancement"
},
},
config = {extra = {repetitions = 2}},
--unlocked = true
rarity = 3,
blueprint_compat = true,
eternal_compat = true,
atlas = "jokerimage",
pos = { x = 0, y = 0 },
cost = 7,
message = localize('k_again_ex'),
calculate = function(self, card, context)
if context.repetition and context.cardarea == G.play then
local enhancement = context.full_hand[1].config.center_key
for i = 2, #context.full_hand do
if context.full_hand[i].config.center_key ~= enhancement then
return nil
end
end
return {
repetitions = card.ability.extra.repetitions,
}
end
end
}```
i meant can i see it not working
oh okay lemme screen record some footage
would SMODS.get_enhancements help here any 
something like
local enhancement = SMODS.get_enhancements(context.full_hand[1])
for i = 2, #context.full_hand do
if SMODS.get_enhancements(context.full_hand[i]) ~= enhancement then
return nil
end
end
...hm no, that shouldn't change it not working
that's not how get_enhancements works

good point about it not supporting quantum enhancements though
for that to work, you'd have to check if there's any enhancement they all share
could you print something in this condition?
if context.full_hand[i].config.center_key ~= enhancement then
i'm wondering if that's entering when it's not supposed to
the code still looks right to me
sorry the footage is taking forever to get, realized i didn’t have a screen recorder on my new computer yet
press win+shift+s
just a sanity check to not waste anyone's time though, you have also tried restarting the game, right?
yes i tried closing, restarting, opening the game again
now that i look closer, it might actually just be better and simpler to do something like move the check to context.before, store the result in a config variable and then rely on that config variable for repetition. something like
calculate = function(self, card, context)
if
context.before
and context.main_eval
then
card.ability.extra.sameEnhance = true
local enhancement = context.full_hand[1].config.center_key
for i = 2, #context.full_hand do
if context.full_hand[i].config.center_key ~= enhancement then
card.ability.extra.sameEnhance = false
break
end
end
end
if
context.repetition
and context.cardarea == G.play
and card.ability.extra.sameEnhance
then
return { repetitions = card.ability.extra.repetitions }
end
end
hows that thing called where you override existing game objects? i want to change vanilla joker/tag
that does sound more efficient, but either should work, i see no reason why it wouldn't
take_ownership?
take ownership
i am also wondering if it's a case of full_hand being strange in the repetition context
i mean, it probably shouldn't
i've never heard of such a thing
but the only thing i can think of is if it's not working, then that condition isn't being fulfilled for whatever reason
for testing I'd put some debug logs before this return
mhm, that's why i said to try putting a print in that condition
but full_hand is definitely not being weird here
i did also think that context.full_hand[i] might be going out of the scope of full_hand, but then i realised that it'd be causing crashes if it did
also, that's going to cause crashes with high cards
can you print something from the enhancement condition and see if that prints anything to the lovely console?
like just stick a print after
if context.full_hand[i].config.center_key ~= enhancement then
before the return
okay you're definitely doing something wrong
i just tested the code on my end and it works
same
can you make sure you've saved everything and restart the game again?
okay i just realized i made a mistake, I was editing the code for the joker, but i specifically edited it in a secondary copy that wasnt actually attached to balatro. now that placed the new version in balatro, the game crashes as soon as i try to discover it
nice
i feel so stupid
that is probably because of the atlas thing aure said
atlas needs to be lowercase
unless you did do that
if I had a penny for every time I edited the wrong file, I would have quite a lot
it is lowercase
don't feel stupid because of it
oh also this is out of place and you might want to remove it, but that also won't crash the game
the only crash I see is if the atlas is wrong
that doesn't include it not existing due to being uppercase
could we see your joker code again please
and also where you declare that atlas (your SMODS.Atlas call)
give me a minute
okay, some weird stuff is happening, when i paste the new code into balatro, it opens the old code that didnt work, even though i saved the new code already
are your files set up correctly
i deleted the old folder, pasted the new folder with new code, and it opens the old code
what's your file structure like?
i fixed it, i copied the code from the newer verison, pasted it into the old one, deleted the old code, and then saved it
has to be just a files problem at this point, i'm sure
nice
the joker still doesnt work tho
huh
how so
the correct code opens, but when i enter balatro and interact with the joker, it crashes since atlas is a "nil value"
you haven't done this
the atlas probably doesn't match
yeah, need to see your joker and atlas code to figure out what's going wrong there
thanks for reminding me, got distracted
anywho simple stuff, good night
sleep well, thanks for the help!
this is the joker code ```lua
SMODS.Joker {
key = "Universe",
loc_txt = {
name = "Universe",
text = {
"retrigger all played cards {C:attention}2{} times",
"if all played cards have",
"the {C:attention}same{} Enhancement"
},
},
config = {extra = {repetitions = 2}},
--unlocked = true
rarity = 3,
blueprint_compat = true,
eternal_compat = true,
atlas = "jokerimage",
pos = { x = 0, y = 0 },
cost = 7,
message = localize('k_again_ex'),
calculate = function(self, card, context)
if context.repetition and context.cardarea == G.play then
local enhancement = context.full_hand[1].config.center_key
for i = 2, #context.full_hand do
if context.full_hand[i].config.center_key ~= enhancement then
return nil
end
end
return {
repetitions = card.ability.extra.repetitions,
}
end
end
}```
heres the atlas code for it lua SMODS.AtLAS{ key = 'jokerimage' , path = 'Universe.png' , px = 71, py = 95 }
I imagine its something to do with atlas
...why AtLAS?
i think SMODS.Atlas here is case-sensitive
i changed it to SMODS.Atlas it still crashes
is your atlas definition before your joker definition
That does not matter
oh, right
my atlases are in a different file from my jokers, i have for atlas's and one for jokers
they are still in the same folder, obviously
are both being loaded though
you can just put files places and have them loaded automatically
I made 2 jokers before this and both work with the format i have so i assumed it wasnt the issue
yes they still work after the edits i made
can we see your file structure and how you load the files
so a screenshot of inside the folder?
yes, and the code where the loading happens
the joker's image file including its location, as well
im pretty sure the image file isnt the issue, the two jokers i made before this don't images yet, and they still work
it's crashing because of the atlas though?
but your error is that the atlas is nil
or is the crash different now
heres an image of the files, and yes the crash is still a nil value
Also that atlas file looks pretty lonely. you said there were other files being loaded there
the main file is loaded because it's... well, the main file
the fact that SMODS.AtLAS wasn't crashing tells me that file is probably not being loaded to begin with
heres the code for my atlas then ```lua
SMODS.Atlas{
key = 'jokerimage' ,
path = 'Red.png',
px = 71,
py = 95
}
SMODS.Atlas{
key = 'jokerimage' ,
path = 'Blue.png' ,
px = 71,
py = 95
}
SMODS.Atlas{
key = 'jokerimage' ,
path = 'Universe.png' ,
px = 71,
py = 95
}
SMODS.AtLAS{
key = 'jokerimage' ,
path = 'Frog.png' ,
px = 71,
py = 95
}
SMODS.AtLAS{
key = 'jokerimage' ,
path = 'ATM.png' ,
px = 71,
py = 95
}```
thats a bad thing i imagine
there's also more AtLAS, so this would definitely crash if it were loaded
yes, keys must be unique
do you have anything loading this code, or is that just the entire lua file sitting in your mod directory - and your intuition was that it was loaded by virtue of it just being in your mod folder? 
no SMODS.load_file anywhere?
you could try doing assert(SMODS.load_file('atlas.lua'))() in your main lua file
...huh?
they all used to be the same, so i made them unique and messed around a little bit and now it works perfectly fine
the keys that is
huh, so the lua file does just load 
yeah it loads
how would one code this in lua
I have about 80 lines of code that I got to stop crashing, but I cannot figure out why the logic for this joker will not work. If i dump the code into this chat, would I possibly be able to get some guidance?
that is what the channel is for yes
I just didnt wanna start dumping
for the life of me i cannot figure out why I cannot actually "steal" other jokers
you should put that in a codeblock
SMODS.Joker {
key = 'shoplifter_hook',
atlas = "hr_jokers",
pos = { x = 8, y = 0 },
rarity = 3,
cost = 8,
blueprint_compat = false,
discovered = true,
config = { extra = { used_this_shop = false } },
loc_txt = {
name = "Shoplifter's Hook",
text = {
"Right-click a {C:attention}Joker{} in the shop",
"to add it to your inventory.",
"Deletes a {C:red}random{} owned Joker.",
"{C:inactive}(Once per shop){}",
"{C:inactive,s:0.8}Cannot delete itself{}"
}
},```
calculate = function(self, card, context)
if context.ending_shop or context.skip_blind or context.setting_blind then
card.ability.extra.used_this_shop = false
end
end
}
-- The Logic Injection
function SMODS.current_mod.post_process()
local old_secondary = Card.states.release.secondary
Card.states.release.secondary = function(self)
if G.STATE == G.STATES.SHOP and self.area == G.shop_jokers then
local hook_key = "shoplifterhook"
local hook = nil
for , v in ipairs(G.jokers.cards) do
if v.config.center.key == hook_key then
hook = v
break
end
end
if hook and not hook.ability.extra.used_this_shop then
local sacrificepool = {}
for , v in ipairs(G.jokers.cards) do
if v ~= hook then
table.insert(sacrifice_pool, v)
end
end
if #sacrifice_pool > 0 then
hook.ability.extra.used_this_shop = true
attention_text({
text = 'STOLEN!',
scale = 1.2, hold = 1, bg = G.C.RED,
align = 'cm', major = self
})
play_sound('cash_register', 1.2, 0.6)
local victim = pseudorandom_element(sacrifice_pool, pseudoseed('hook_kill'))
victim:start_dissolve()
self:add_to_deck()
G.jokers:emplace(self)
self.area:remove_card(self)
return
end
end
end
return old_secondary(self)
end
end```
I hope this is what you meant. Sorry, I am unfamiliar with code blocks in discord
yeah yeah, you can add ```lua in the top one so it has highlighting
ahhh okay
was this ai generated
well of couse its not going to work if half the things in your code are nonsense lol
I guess that's why I needed some pointers. Trying to figure out what went wrong and half the stuff im googling doesnt matter lol
ive never seen this type of code in balatro before
oh god
i would personally recommend starting with easier stuff first, the first part of the ability doesnt seem that hard but eben i wouldnt know straight away how to do it without looking into the code a bit first
for the right click in JokerDisplay i hook Controller:queue_R_cursor_press, the idea would be to check what is hovered there (G.CONTROLLER.hovering.target) and remove the joker from the shop area similarly to how the code you have does it (but i believe you would need to destroy the shop ui)
i put in_pool = function() return false at the end of my joker's code but it still shows up in the shop D:
can i see the full code
Okay I gotcha. I'll just have to put it on the back burner for now. I made a few jokers before but those were pretty simple. xMult and whatever. I was able to piece together a joker that destroys cards but thats about as complicated as I got with it
Thank you @red flower for helping me out. I'll have to come back to this idea
are you using deck of equilibrium at any chance?
no just regular red deck
i think it'd be
return false
end,``` near the start of the joker's code
after the loc txt and config and unlock and allthat
ok that seems to have worked
how do i also make it so that
a joker doesnt spawn
if you have another specific joker
already
return not next(SMODS.find_card("j_modprefix_otherjokerkey"))
do i put this after the calculate functions or before?
doesnt matter
as long as you keep it in a tabl
keep it in a talbe
does this take showman into account or does showman bypass this
instead of the return false
if you return this from in_pool 
if in_pool returns false the joker cant show up, if it returns true it can as long as you dont have a copy or you have showman
...so i don't know why, but i had it in my had that if you have in_pool return false, then it's treated the same as when you already have the joker
mostly because i was thinking of my joker upgrading consumable and how if you use it to turn a joker into its upgraded version, you can encounter the unupgraded version in later shops
How can I check which stakes are applied?
G.GAME.applied_stakes
thx
wait it's numbers? urgh (i have an additional modded stake on top of gold stake, hence the 9th)
just do G.P_CENTER_POOLS.Stake[number]
yeah i just wanted an easy way to get if gold stake is applied for example, but ig i have to iterate over all applied stakes and check for each of them if it's gold
im pretty sure gold always has the same number
how do i make it so that, before the hand scores, certain suit cards turn into another suit
that was an example, technically i want to check for black, orange or gold (aka if eternal, perishable and rental jokers can appear)
isnt it easier to check if those can appear? or do you specifically need the stakes?
i just need the sticker
i guess there's a flag that sets if those can appear? that'd make sense now that i think about it
G.GAME.modifiers.enable_eternals_in_shop
G.GAME.modifiers.enable_perishables_in_shop
G.GAME.modifiers.enable_rentals_in_shop
if context.before and context.cardarea == G.jokers then
-- turn cards to club
local clubs_trigg = false
for _, v in pairs(context.scoring_hand) do
if not (v:is_suit("Clubs")) then
clubs_trigg = true
local rank = v:get_id()
if rank > 9 then
if rank == 10 then rank = "T" end
if rank == 11 then rank = "J" end
if rank == 12 then rank = "Q" end
if rank == 13 then rank = "K" end
if rank == 14 then rank = "A" end
end
v:set_base(G.P_CARDS["C_"..rank])
end
end
if clubs_trigg then
card_eval_status_text((context.blueprint_card or card), 'extra', nil, nil, nil, {message = localize('maelmc_clubs')})
end
end
I did this to turn cards to clubs, checking if they aren't already clubs beforehand
thx
for the effect im trying to do, im trying to turn clubs and spades into hearts
then check for that
if context.before then
for k, v in pairs(context.full_hand) do
if v.base.suit == 'Clubs' or v.base.suit == 'Spades' then
SMODS.change_base(v, 'Hearts')
end
end
end
oh, of course there's a smods function for it lol
You should be checking v.base.suit ~= 'Clubs' and should be returning a message instead of using card_eval_status_text
thank you!
how can i make a SMODS.Challenge where you die in game you die in real life ?
local current_tier = next(SMODS.get_enhancements(G.hand.highlighted[i])) or ""
would return the enhancement right
SMODS.kill(G.GAME.player)
its not guaranteed to return the "main" one
it could be a quantum
how would i grab the main one then? G.hand.highlighted[i].config.center.key?
yes
ohhhhh okay
yeah i see it in the lsp i dont thunk it was in the docs
my b
how do i check if the card's usual sprite isn't being used
i can't use card.discovered bc if i do
if card.children.center.atlas == G.ASSET_ATLAS['modprefix_atlaskey']?
nope, even undiscovered cards still have their usual atlas stored in the center like that
i actually need to figure this out too for high roller
i've been given a solution on the hotpot server
function slimeutils.card_obscured(card)
return not card.config.center.discovered and (card.ability.consumeable or card.config.center.unlocked) and not card.bypass_discovery_center
end```
and i put it in this function
actually i might be stupid
but yea thanks for throwing that over to me
can someone help me figure out why my info_queue is just not working?
the code:
-- The Inverted Magician
-- Chance to destroy or add foil to 1 selected card
SMODS.Consumable
{
key = 'inverted_magician',
set = 'Tarot',
atlas = 'inverted-arcana-tarots',
pos = {x=1, y=0},
config = {
max_highlighted = 1,
remove_card = true,
mod_conv = 'e_foil',
extra = {
odds = 3,
},
},
loc_vars = function(self, info_queue, card)
info_queue[#info_queue + 1] = G.P_CENTERS.e_foil
local numerator, denominator = SMODS.get_probability_vars(card, 1, card.ability.extra.odds, self.key)
return {
vars = {
numerator,
denominator,
card.ability.max_highlighted,
localize{type = 'name_text', set = 'Edition', key = card.ability.mod_conv}
}
}
end,
use = function(self, card, area, copier)
use_inverted_tarot(self, card, area, copier)
end,
}```
the result: the info_queue flyout just isn't there?
same is true for the tarot cards that should be displaying enhancements and seals. just no flyout at all, no crash
this should work to stop those jokers from appearing, right?
yes
is there an easy way to add temporary handsize but for the next round
or do i have to save it and apply it on shop start
ive been having trouble with making an enhancement, im trying to make it so it doesnt take up space in the hand (by having it increase hand size by 1 when held in hand) but theres two exceptions ive found where i cant get that to work the way it should (blind is defeated -> doesnt decrease hand size properly even when i use context.blind_defeated and then switching off of enhancement -> doesnt decrease hand size properly because by the time context.setting_ability is called the enhancement is no longer running the code)
i know using the negative edition would work but its important for this enhancement that it be an enhancement, i could post the code here but id worry about it taking up a bunch of space (although its not SUPER long) so if i should post it just lemme know and i will, but i was wondering if anyone had any advice on how to go about handling this
...how did you implement juggle tag?
you can add card_limit = 1 to the config
i tried that but then it crashed
what was the crash
hang on ill do it again rq so i can post it
do i have to return it in loc_vars btw i dont remember if i gotta do that
no, in config
alr yaya i threw it in config i was just wondering if i had to put it through loc_vars too
no
weird
it hasnt crashed
and it works
okay wow idk what the problem was then but 😭 if it works it works
thanks !
So both reroll surplus and reroll glut lower the reroll price by $2, making it only $1 initially
Naicigam also lowers the reroll price by $2, so all them together make 5-6, making the price say $-1
Is it possible to make the reroll price floor at $0 without possibly breaking anything
Also it gets worse when there are multiple naicigams, is it possible to make an effect non-stackable
fun bug
Boobs
boob joker
how would i go about incrementing a joker's chips/mult/whatever when a joker of a specific rarity is purchased?
which part are you having trouble with? scaling, detecting if a joker is bought or checking its rarity?
if context.buying_card and context.card:is_rarity('modprefix_key') then
SMODS.scale_card(card, {
ref_table = card.ability.extra,
ref_value = 'value',
scalar_value = 'value_mod',
no_message = true
})
return {message = localize('k_upgrade_ex')}
end
mainly the last one
i have the first and im pretty sure i know how to implement the second
oh ok
i didnt realize there was a context for rarity
thats nice
ty
imgui-love works with balatros love version raaaahhhhhhh 
it works now, although im realizing it doesnt increment when i take a joker from a booster pack
would there be a way to include that as well
You’d use context.card_added and context.card.ability.set == ‘Joker’ instead of context.buying_card
ah ok
No, that's if a joker is added to the joker slots in any way.
honestly i dont know
are there other scenarios for getting a joker into your slots besides shop and booster pack
probably
yeah
top-up tag
i guess having it be added in any way works i would just have to reword the current description which says "when a common joker is purchased"
“When a common joker is acquired” or smthn like that
yeah
bonus question regarding this
is there a difference between = and == in lua
or can i just use whatever
Yeah, = is for setting values and == is for conditionals
context.card.ability.set didnt work fsr so i went back to context.card:is_rarity and that did the trick
how do i convert this to work with SMODS.scale_card 
You should probably have both the set check and the rarity check, as card_added will be run for cards of any type, including cards that may not have a rarity
would cards with no rarity still trigger the joker with the rarity check?
im down to add the set check i just dont really understand what it is i suppose
I’m honestly not 100% sure how is_rarity works with non-jokers nor do I know if there’s a fallback, but if there is I’d assume the fallback is 1. If there’s not a fallback I’d bet it crashes lol
The set check just checks if the card is a joker
No, it returns false if the card is not a joker.
A boolean was the last thing I would have expected
if context.card_added and context.card.ability.set == "Joker" and context.card:is_rarity("Common") then
so like this?
Yep that should work
cool
Why would it return anything other than a boolean?
i've got a bit of the functionality of the baladev mod done :D
definitely needs some polish
I was under the impression is_rarity returned ints for vanilla rarities
Clearly not
it's is_rarity, not get_rarity
ah hang on
sorry to keep asking questions about this but how to i change the message from the default Upgrade to displaying the Chips increase
i tried adapting the code from flash card but it didnt seem to work
Are you using the scale card function?
i am yeah
Ok gotcha
I believe what you wanna do here is add a message_key field to your function call and have it be ‘a_chips’
what exactly do you mean by the function call?
apologies for the confusion im just very new to programming so im not familiar with the terminology
Nah all good, welcome to coding lmao
Basically when you’re using a function, it’s called “calling” the function
oh no no i get that, i was just wondering which function you were referring to
cus i have loc_vars, calculate, and the whole if/then statement
so i wasnt really sure where to put the message key
Wait are you or are you not using SMODS.scale_card?
rld
I’m confused now lol
ye i am
Ok then I mean in that
ah ok
Here’s an example of what I mean
it might be just "+20", but that's consistent with vanilla I think
if it were mult it'd definitely be "+20 Mult"
interesting
yeah it is just +20
but if thats how it looks in vanilla then its probably fine?
If you're using the code I gave you, then you would change the message you're returning.
yea check uhh wee joker I think
oh weird
Tf is wee doin’ 😭
That’s goofy
But yeah only numbers showing is (usually) consistant with vanilla
No, all chip scaling jokers use the Upgrade! message.
good to know
i'm pretty sure most jokers that scale during the hand do "Upgrade!"
is there a way to hook or wrap Card:shatter()? I want to keep a tally of how many glass cards break as a global
Yes, you can hook any function.
how do i do it and still let the original function though? it doesn't have any args i can pass
local oldshatter = Card.shatter
function Card:shatter()
if SMODS.has_enhancement(self, 'm_glass') then
G.GAME.modprefix_variable = G.GAME.modprefix_variable+1
end
return oldshatter(self)
end
ohhh, you return the original passing self. thanks
stupid question, how do i declare and initialize a global in G.GAME?
local igo = Game.init_game_object
function Game:init_game_object()
local ret = igo(self)
ret.modprefix_variable = 0
return ret
end
thank!
Anyone know if there is a context for last hand drawn?
I know DNA uses context.first_hand_drawn, but I was wondering if there was a last hand drawn
No, there isn't.
Is there a way to hook it or smth any way for me to change this code so it works as the last hand?
-- RNA
SMODS.Joker {
key = "rna",
blueprint_compat = true,
rarity = 2,
cost = 6,
pos = { x = 0, y = 0 },
loc_txt = {
name = "RNA",
text = {
"If {C:attention}last hand{} of round",
"has only {C:attention}1{} card, add a",
"permanent copy to deck",
"and draw it to hand",
}
},
atlas = "rna_atlas",
calculate = function(self, card, context)
-- Juice effect like DNA
if context.first_hand_drawn and not context.blueprint then
local eval = function()
return G.GAME.current_round.hands_played == 0 and not G.RESET_JIGGLES
end
juice_card_until(card, eval, true)
end
-- Copy condition
if context.before
and G.GAME.current_round.hands_played == 0
and #context.full_hand == 1 then
local card_copied = copy_card(context.full_hand[1])
-- Add ONLY to hand
G.hand:emplace(card_copied)
card_copied.states.visible = nil
G.E_MANAGER:add_event(Event({
func = function()
card_copied:start_materialize()
return true
end
}))
return {
message = "Copied!",
colour = G.C.CHIPS
}
end
end
}
instead of hands_played you can check that the current remaining hands is zero. to do the wiggle, you could use context.after and just check if hands remaining is zero and have it stop when playing another hand
there is a general hand_drawn context, use that and do any additional checks you may need (such as number of hands left)
if context.hand_drawn and G.GAME.current_round.hands_left <= 1 then
if I extend SMODS.Center will my new card type automaticly go into the other section of the collect or do I have to patch/hook something
Idk how it exactly works but you do have to create the collection page yourself yes
any mods I could look into for details, I tried card sleeves but I couldn't make anything out
Idk
Paperback i guess? That isnt for a center type but it is a collection page with cards
Small question: how can I set my mod icon (the one that appears in the mods section that looks like a tag) to a custom icon I made?
Should I make an atlas for it?
create an atlas with the key modicon
add an atlas with the key modicon
like this?
Yea
why does this juice twice?
For JokerDisplay, is there a way to make the tooltip disappear entirely when a condition is not met, instead of only changing the values?
i'm struggling to come up with a way of doing this, but i'm gonna rubber duck and see if it helps
if you have any suggestions, feel free
i'm working on a necessary update to Flipbook that will allow individual cards to show different animations
(as before, cards could only animate their Centers, meaning if one card wanted to do an animation but another didn't, they'd clash)
it's therefore necessary to change how the center DrawStep works
but i'm not sure what the best approach would be
i'm gonna have each animated card have a flipbook_pos
but, should i patch the DrawStep, or take ownership of it, or something else? and how would i change the pos that a card is rendering with?
actually i may not even need to patch the DrawStep if i'm clever
okay yay the rubber ducking worked ^u^ better question
how do i change the pos that card.children.center renders with?
i'd previously just been changing the pos of the centers in G.P_CENTERS
my current solution is nowhere close to optimal, but it works
utilizing empty strings to get the desired effect is 
I believe that was my first instinct, but it doesn't work if it's Xmult, because the red outline is still there
use style_function and set the box's colour to G.C.CLEAR
Is there a way to automatically give a joker the highest stake sticker?
start a run with the highest stake difficulty, spawn the desire joker in, and call set_joker_win()
card.children.center:set_sprite_pos
btw i would recommend asking jokerdisplay questions in its thread but what huy said is what i do
AAA I DIDN'T EXPECT THAT TO ACTUALLY WORK WHAT???
[these cards are at different points in their animations]
[in the old version, they would've been synced]
another example, look at the Visionary's cross
okay a more clear example :3 these are the same card
if i have two Hint Coins, their events will play immediately, one after the other. how can i get their events to wait for the other Jokers to return values?
if context.before and G.GAME.current_round.hands_played == 1 then
G.E_MANAGER:add_event(Event({
func = function()
if not context.blueprint then
play_sound("phanta_hintcoin", 1, 0.9)
card:flipbook_set_anim_state("collect")
end
return true
end
}))
card.ability.extra.given = true
return { dollars = card.ability.extra.money }
end```
i'd try returning extra with a func, but the func triggers after the message, which i don't want
also i realise i put a context in an event, i've fixed that now
do you mean it goes event > event > message > message?
hmm seeing the code it seems like it shouldnt
i'll test it more in a mo, but i found a crash to fix ^^;;;;
testing similar code it goes event > return > event > return like it should
if the things inside the event also add another event then it would make sense that it does return > return > event > event (since the events will be adding another event to the queue for later)
but event > event > return > return would be strange
hmm i see
okay i think i understand the crash, lemme fix that then test
of course, this crash could've been avoided if i wrote better code :3
weird, it looks like it's working now
;u;
sorry to bother
hi! how can i detect if the player owns a specific joker from the vanilla game?
ty!
Wiki has them https://balatrowiki.org/w/Booster_Packs
Thanks!
in calculate, how can i detect a steel/gold card trigger and do something in response?
like i was looking at vanillaremade's mime implementation, but i'm wondering if i could also do some kinda trigger_obj stuff
i have accidentally removed the hologram's face and idk how to not do that (i'm using carrotton's dark pack as a base for my pack incase that helps)
also pasting fully opaque jimbo over the hologram's jimbo vaporizes the entire hologram jimbo i figured out earlier
How do you add extra modifiers to challenges?
Like banning modded items that would break these challenges?
alr i'm having a crash because of this line:
SMODS.create_card{key = "fixed", set = Joker, skip_materialize = true, no_edition = true}
isn't this how SMODS.create_card is supposed to work?
-# the crashlog says that "center" is a nil value
the key is missing the prefixes
switched to SMODS.create_card{key = "j_fixed", skip_materialize = true, no_edition = true}, still crashes for some reason
ah i'm dum ty
How can I add a custom joker card to the title screen like most ppl in their mods do?
note: I said "add", not "replace the ace card"
jokers not doing joker things even if i specify their set and area to be jokers?
SMODS.create_card{set = Joker, area = G.jokers, key = "j_cash_out_fixed", skip_materialize = true, no_edition = true}
add_card instead of create_card
i can't read my bad
alr i've tried to understand myself using the documentation but i can't figure it out anymore, this crashes when context.post_joker fires
if context.post_joker then
if next(SMODS.find_card("j_half")) then
--destroy "j_half" and "j_half_2"
self.remove_from_deck()
local half_cards = SMODS.find_card("j_half")
local target = half_cards[1]
target.remove_from_deck()
--create "j_fixed"
SMODS.add_card{set = Joker, area = G.jokers, key = "j_cash_out_fixed", skip_materialize = true, no_edition = true}
end
end
its target:remove_from_deck()
and same for self
also remove_from_deck isnt how you destroy a card to begin with
if thats what youre trying to do
yea you should use SMODS.destroy_cards(card) instead
how do I put credits in my mod?
depends on what type of credits you're taking about
...type of credits?
anyways I what I wanna do is I wanna add a section in the info of my mod that is credits and put there the names who helped me in making my mod!
you could have been talking about putting credits on cards or having them somewhere else, there's no api for adding a "credits menu" per se but take a look at this:
https://github.com/Steamodded/smods/wiki/The-Mod-Object#modextra_tabs
this is mine
aight thanks!
I'm still gonna try to make my own
ok so I was normally trying my mod and then this happened, not sure why but it never happened before.
the crash showed when I clicked on next round
is there a way I can fix this?
You would have to patch SMODS.score_card
i ended up just integrating and tweaking the mime condition to my joker
No, you shouldn't be using context.repetition for non-retrigger effects.
well testing didn't really show any issues outside of juices sometimes just straight up not happening
and i wouldn't know what i should patch into score_card
given that all i'm doing is grabbing the values the triggered card gives to store in the joker, it should be fine
whats the full og
log
why can't you use context.individual?
i did initially test context.individual and found that it didn't work for whatever reason
i guess i can try it again now that i've refined all the involved conditions
do you have a custom tag?
yeah
check if the atlas is correct for those
the error would suggest something has something like atlas = false
tag_SM_scienceful_tag this one
huh... there wasn't an atlas for the custom tags and I swear I thought I added one in the atlas file...
well, that explains the error
yeah. if i don't do it in context.repetition, it doesn't capture the xmult from steel cards or $ from gold cards 🤷♀️
Yes, context.individual doesn't have context.card_effects
...right. that was leftover from when i was using context.repetition. what should i check for instead
crazy
crazy
something im trying to do rn is make a joker that copies the edition of the joker to the right AND copies the ability of a randomly selected joker, ive managed to fairly easily get the edition selection and random selection down and the jokers stored into their respective values, but i cant seem to get it to work for some reason. the first two of these screenshots make the joker do basically nothing while the third makes it copy the joker ability, but not the edition. with all three, the correct things are printed from the three print functions within the first if statement, but printed far too early. is there something about the pre_joker and post_joker contexts that im missing?
pre_joker and post_joker are not sent to jokers iirc
aw man
hmm but if theyre printed then maybe they are?
weirdly its printed like right when the hand is played
yeah thats normal
but that also seems to happen if i use the context of joker_main so idk whats up with that
ohhh that makes sense
i see
anyway, another thing is that you shoudnt save a card to card.ability
it is not going to work on reload most likely unless you do custom loading
aw man ive been doing that a lot 😭
ah i see the issue
return SMODS.merge_effects{ return_table or {}, ret or {} } should work
you are basically merging the tables incorrectly
edit for nil checking
can i see the code now
the prints work, right?
yup
this will only return if it's copying something
you should put the bottom return outside the condition unless thats what you want
it is copying a joker at least but i see how that could be a problem later down the line
idk why it isnt working then lol
nice
i just had to switch it to joker_main again
does the order of the returned table matter? like if it returns { return_table, ret } does that make return table trigger before ret while { ret, return_table } makes ret trigger first?
okay cool so for polychrome i can switch the order n stuff
sweet ! everything works now
thanks for the help ! and by the way where should i store the cards so that i dont have to keep using the ability table thing
if the cards are still in the joker slots you can put a flag in them
like card.ability.modprefix_flagname = true
when are you getting the jokers?
whenever this thing goes off
so at the end of the round, when the copied joker is sold, or when there isnt a joker being copied
ah ok then what i said
so wait is that something i have to put in separate jokers ? because this is meant to be a blueprint type thing that just works for
any joker
it just needs to save the joker its currently copying to a variable so that it stays consistent n all that
(this is the code i use to get a joker)
i mean like
local random_joker = pseudorandom_element(list, "seed")
if random_joker then random_joker.ability.modprefix_copy = true end
-- then you loop through G.jokers when you need to get the joker
it is a bit more complicated if you need to consider multiple copies of the same effect
ohhh i see
hi N`
hello
Its been a while since I've actually been here and have done stuff. I actually posted the mod I have been working on, although we aint dropping mod yet. Just posting lol
Can anybody tell me which part of the code is responsible for dropping the shop menu when using a card plz
it's just that? huh, ok thx
i made this function in my joker but for some reason ive tried like 10 different ways to access it and none of them have worked, whats the correct way to access this
i know this is kind of a stupid question but 😭
card.config.center.find_copy()
?
ohh i was forgetting the config.center
my bad im pretty new to this
thanks !
and everything works now too !
dont worry most people wouldnt even know lol
fair lol
okay so i've got a really strange bug that i can't find the cause of
lots of code though, so if anyone wants to help, i'll DM you the code i have
(actually it'd probably be easier for me to stream it)
(would be at least somewhat good if this server had VCs)
it's so annoying when you code something for ages and it doesn't work right :(
I wanna stay up all night fixing it, but I have to go to bed
grr
i would try to help but the only thing i know about lua is that returns are somwhat important
oop did not mean to ping
how could I detect when a card is destroyed and save it's stats?
don't give me the answer just help me figure it out
Playing card or Joker-type?
playing cards
Jokers would also be a cool adition but prob not for now
I just added purple guy to my stuff and it would be a great combo for another card to have that ability
here's the idea I had:
Purple guy destroys 3 cards every played hand. each 19 cards destroyed gives him +87 extra chips
My other card is Greed
For each card destroyed, you get them back but foil (Or smth) After every boss blind
I'm rather new to modding balatro, so thank you for your help!
Keep that wiki handy whilst devving. ✌️
thanks!
How to I give cards as well?
trying and failing to replace green joker's name and description, what am i doing wrong (five ending brackets condensed for brevity)
return {
descriptions = {
Joker = {
j_green_joker = {
name = "\"Green\" Joker",
text = {
"i probably picked a bad palette",
"{C:inactive}(Currently {C:mult}+#3#{C:inactive} Mult)",
}}}}}
Hey guys. Do you know if the gate for a purple seal would be:
seal_gate = 'purple'
Also, how do you signal you want the gate to be for any seal?
How would I go about manipulating the score requirement of a boss blind?
Yes, it wouldn't, seal_gate doesn't exist.
I'm assuming it's silently failing? In that case my guess would be that your localization file isn't loading at all
were there new smods functions to change hand count and hand size? i forget
G.hand:change_size(int) for handsize, not sure what you mean by count tho
I don't think smods has anything for that? Unless you meant the play/discard limits
Oh like the amount of hands you have
yes
that would be ease_hands_played(int) iirc
and then you also have to change the round_resets value if you wanna keep that number permanent
ok so i'm just thinking of the play/discard limit funcs, thanks
oh, okay, thanks.
Do you know if there is any way of making a joker only show up if there is a seal in deck?
You can add an in_pool function to your joker
Here's an example of that which searches for Gold Cards
Just add it to your Joker like you would calculate and whatnot
looking back at my code, i'm sure there's a way better way to do this using SMODS.add_card, no? like i could just get the key and then put that in a table in add card, and specify negative edition.
actually nvm, that wouldn't be faithful to the joker description text i wrote, now that i think
Awesome, thanks. Do I just replace has_enhancement for seal?
basically yeah
Thanks. 
You'd probably want to check for v:get_seal(), no has_seal function. 🙃
Does anybody know what function in the base game creates the Joker collection menu? I want to make a UI for my mod that looks exactly like the collection menu as a pop-up in-game that has a custom set of cards the player can choose from to add to their run
i think it's soomething like "create ui collection box"
I found create_UIBox_your_collection_jokers() but all it does is add the first page of jokers at the bottom of the screen
I'm pretty sure aij has done the thing your trying to make.
I see, makes sense. I had seen that too, around.
So, if v:get_seal() == 'purple' then
Also, do you know what v stands for?
would you be able to point me in the right direction to find that then?
One example of that in All in Jest is the Ignoramus Gold Tag.
the v is from for k,v in pairs(G.playing_cards)
k is the table index or key, v is the value
G.playing_cards is numerically indexed iirc so "properly" it would be for i,v in ipairs(G.playing_cards) but the only difference in this context is that pairs doesn't respect order
(the variables k,v or i,v can be named whatever you want; those are just the conventional "defaults" when you don't have a specific thing you want to call them)
uuu, thanks. Pretty interesting.
I'm starting to see the downsides of not spending the time learning lua specifically, haha.
It works for the stuff I'm making though.
No, it would be 'Purple'
my patch is no longer changing this cycler colour to blue. the lovely console isn't saying that it didn't result in any matches and the lua dump shows that the patch took?
what changed
when making new stickers or taking ownership of existing stickers, should_apply seems to ignore all the normal restrictions the sticker has like needing to be enabled by stake or only appearing on jokers. is there a way to make it not ignore those restrictions? or is there an easier way to make two stickers not be compatible?
return SMODS.Sticker.should_apply(self, card, center, area, bypass_roll) and condition
Also all vanilla stickers don't use should_apply
okay, so i could use and instead of or to add additional restrictions while keeping the normal ones, yeah?
return condition1 and condition2 or condition3, ye.
does this mean if i do take_ownership of the vanilla stickers i can't change when they apply or what they're compatible with?
No, you can, it's just that the code for adding vanilla stickers is hardcoded into create_card
so how do i change what they're compatible with?
In your sticker you would have to make it not able to apply if the card has the sticker you want your sticker to not be compatible with.
im trying to do that with this, but it's not working
should_apply = function(self, card, center, area, bypass_roll)
return SMODS.Sticker.should_apply(self, card, center, area, bypass_roll) and (not card.ability.perishable and not card.ability.rental)
end,
i also want to make rental not appear with eternal
ehhhhh
is there a function that formats text with formatting ("{C:red}+4 {}Mult") into corresponding UIBox elements, for use outside Joker descriptions?
SMODS.localize_box
despite the name it localizes a line
oh and you need loc_parse_string too
tried looking in source and I don't understand how to use it, can't find any docs on it too
SMODS.localize_box(loc_parse_string("{C:red}+4 {}Mult")) should work as is, i think
it returns a list of nodes so you would need to do like {n=G.UIT.R, config={align = "cm", padding = 0.03}, nodes=localize_box_return}
works, but args needs to be provided, i.e. SMODS.localize_box(loc_parse_string("{C:red}+4 {}Mult"), {})
So for clarification it only goes through one line at a time?
can someone help me understand why this code doesn't prevent the sticker from being applied to jokers that have rental or perishable?
cough
is this in the shop or applying it manually?
SMODS.has_enhancement(card, "key")
in shop. like how the vanilla stickers get applied
Vanilla stickers are added after modded stickers are applied.
the problem is that vanilla stickers are applied after yes
its realy hard to make them incompat, you would need patches i think
hard with the api i mean
i just have to patch create_card with lovely then?
i think so yeah
does rate work on the vanilla stickers ?
only if you re-add their should_apply functions, else they're hardcoded
okay, ill just have to do it in lovely or hook create_card and do the stickers myself. thanks
How would I prevent a joker from being removed, aside from selling it?
Thanks. I actually found a great example of it.
Pretty sure I know how to do it now.
how do i use a sticker's apply method?
card:add_sticker('modprefix_key', true)
Was trying out some UI stuff but for some reason there's always those white borders in the angles.
how do I remove them?
you used the template, which doesn't have rounded corners
then which one uses the rounded corners?
or how should I modify it to have rounded corners?
uh, hello?
bump
the r field
the "r" field specifies how much rounded the corners should be?
how do i set the text of the badge?
modprefix_key = 'Label' in Localization > misc > labels
yea, it says default is 0.1
I keep changing the value but the white corners still shows up like nothing changed
And I if I remove it, the white corners disappear but the box doesn't have rounded corners
wait
huh
the template contains 2 root nodes

why
at this point just take a look at https://github.com/Steamodded/smods/wiki/UI-Guide
that's.... where I was looking while I was making my custom window...
I suggest using it to understand the core components
that's.... what I was doing....
you can copy Balatro's existing UI elements tho
it's better to start with a well-made template
go to Mods/lovely/dump/functions/UI_definitions.lua
wait where's that
start from the Mods folder
oh true
I'm not really a UI wizard myself tho
take a look at this half-ass save states UI I modified from challenge list
I had no idea what to put in the center so I just copied the continue screen's deck info 😭
im reading up on how to do enhancements and im a little confused on how to make a tarot give an enhancement
-- The Hierophant
SMODS.Consumable {
key = 'heirophant',
set = 'vremade_Tarot',
pos = { x = 5, y = 0 },
config = { max_highlighted = 2, mod_conv = 'm_vremade_bonus' },
loc_vars = function(self, info_queue, card)
info_queue[#info_queue + 1] = G.P_CENTERS[card.ability.mod_conv]
return { vars = { card.ability.max_highlighted, localize { type = 'name_text', set = 'Enhanced', key = card.ability.mod_conv } } }
end,
this is vanilla remade hierophant but what does mod_conv stand for?
mod_conv is a variable that gets processed by the game automatically to apply the enhancement listed. in this example it will be applying bonus. if you change that key to a different enhancement's key, it will give that enhancement instead
so target:destroy_cards(card, nil, nil, true), right?
still crashes because of this line..
target:SMODS.destroy_cards(card, nil, nil, true) doesn't work either
@dreamy thunder
I'm trying to make a credits UI window but for some reason when I make a node for the black window, these white corners always show up...
how can I remove them and make the black window like the other windows (with the dark shade underneath)?
Gimme a sec
can you try setting the root's colour to G.C.CLEAR?
in it's config
OH MY GOD THANK YOU SO MUCH!
Btw If I wanna put the slightly visible shadow of the child node does that mean I must set the values of the root similar to its child but with the colour black?... or dark? I forgot which one was for the darker black
iirc there is a shadow boolean that can also be set in the config but idk if thats it
you should also be able to build your UI in root
oh, I tried it like I said and... well it works as intended
instead of making another seperate black box
oh I see
maybe that might be it cuz i honstly dont know 😔
this is what i did with the root of my config ui
-# tho i must mention you don't need the G.UIT.R part here
i think it's only for hovering nodes
........wrong channel dude
...
of course he deleted it
this has a shadow for me
(:
just don't post unrelated stuff to the wrong channel next time, ok?
tried it rn and... it works
I guess I can build my UI in the root then
thx for the help Revo!
No worries
does anyone know how i could make a config toggle that adds or removes content (blinds, jokers, etc.)?
does anyone know how i can still run calculate on a debuffed joker
have the content in question check the config value as part of its in_pool function
(or for consistency, copy the relevant config into G.GAME on game start and have the content check the copied value)
hook or patch Card:can_calculate to account for whatever conditions you have
thank you
yw
for Voucher requires, can i set a global variable?
as in
SMODS.Voucher {
key = "peltmarket",
atlas = 'inscryptionVouchers', pos = { x = 0, y = 1 } ,
requires = { 'v_felijo_beartrap', G.GAME.felijo_pelts_enabled}, -- HERE
cost = 10,
config = {},
loc_vars = function (self, info_queue, card)
return {}
end,
redeem = function (self, card)
G.GAME.felijo_pelts_sale = true
end,
unredeem = function (self, card)
G.GAME.felijo_pelts_sale = false
end,
}
i don't believe that would work, but you can define an in_pool function
right, that would definitely fail, because it would assign the current value of G.GAME.felijo_pelts_enabled (probably nil) to requires[2] and then never look at it again after the voucher was initialized
that would happen if G.GAME wasn't a table when the voucher was initialized. which doesn't surprise me
how do i check if a voucher has been redeemed? i can't find it in the VR wiki FAQ
you can use SMODS.find_card on vouchers
how do i add custom extra info boxes to a joker like white stake in this case? (idk what its called so i can look it up in the docs >.<)
info queue
that would be on an area like G.jokers no?
SMODS.find_card searches all player-owned areas iirc
it definitely searches the redeemed voucher area, i know this because i use it in one of mine
i dont even remember such an area
i don't remember what it's called, but redeemed vouchers are stored there so they can use their calculate functions if they have one
so would this be right then?
dlc_toggle is probably the wrong name for the value
i mean, it's the name i gave the toggle in my config file
yes, but configs aren't stored as naked globals
oh yeah, true
you want SMODS.Mods[your mod id].config.dlc_toggle
thx!!
and then, this parts optional but would there also be a way to make it not appear in the collection if toggled off or does in_pool already do that?
currently there's not an elegant way to do that
smods could update how no_collection works to take a function though
that'd be nice
shame i'm not experienced enough to add the functionality myself lol
that said, if this option requires a restart anyway for some reason, then you could just add no_collection = not SMODS.current_mod.config.dlc_toggle
this won't work very well if the option is intended to be toggleable without a restart
?
info_queue messages
in your loc_vars function, append to info_queue
i'm still not 100% sure how it works but i know you can append a center directly
e.g:
info_queue[#info_queue+1] = [G placement of thing here]
if you want arbitrary text, you can put a description in the localization at descriptions.Other[key] (in the form key = {name = "string", text = {"table of strings", "each line is another string"}}, just like a joker desc) and then append {set = "Other", key = key}
(if you want to be needlessly extra, you can lovely patch in handling for a custom set like i did. but this isn't really necessary since you can put it in Other)
I keep seeing stuff abt lovely patches, but that always seems so complicated and confusing ngl
Hooks i can understand, patches i dont at all
patches are just
hey game, look for this bit of code, insert new code before/replacing/after it
the syntax is a little strange but in practice they’re fairly straightforward
lovely patches just modify the game code directly
this is sometimes more elegant than a hook, e.g. if you just want to do one small thing in the middle of a larger function
that’s pretty much it yeah
Damn, i been confused for nothing then lol
may i seez how you did it :3 i need it to use info from the joker so it cant just be static text
looking for the key in G.GAME.used_vouchers should work iirc?
ah, that won't require lovely patching
you include vars in the table for that
how do you make a Joker do something every second
patch can reach places a normal hook can't, such as in the middle of an event
use an update function (runs every frame) and count how much time has passed by summing up dt
(affected by game speed, there's a way to get real dt that I can't name of the top of my head, use that if you don't want that)
i have such paranoia with adding update functions for fear of bad performance
even though it’s literally fine
Wouldn't it just be dividing by game speed
https://github.com/wingedcatgirl/Bibliography/blob/main/jokers/hugh.lua#L46 i passed these vars directly because i don't expect them to ever change in this context. but you could just as easily pass card.ability.extra.whatever
it's G.real_dt
close enough
thx :3
does the card being sold count as a destruction for context.joker_type_destroyed
How do you make a variable change its values live when hovering over a description
no, afaik
i checked it doesnt
how do i trigger this after the card has been sold? so i can properly enforce the joker limit
(card materializes before card gets sold so if there was already 5 jokers and i enforced a check then it can't make the new joker)
G.E_MANAGER:add_event(Event({
delay = 0.4,
trigger = 'after',
func = function()
ouroboros:start_materialize()
return true
end
}))
have you tried another event
How do I change the text background (like how it works when you do X: in localization)
what do you mean
event inside the event i assume?
like a condition event?
Nvm I figured it out
event inside an event
i just made it so the initial card doesnt take space instead
I'm too actually, but then I remind myself every time that most of frame time is spended by UI movement and drawing a frame, so any calculations you do is not impactful in comparision to mentioned things and spamming update funtions is kinda fine
it's not bad in isolation, what makes it bad is running expensive calculations every frame
like how Cloud Nine works in vanilla, you shouldn't be doing that all over the place
grr! i'm getting this again
is Phanta too big now 😭
or is my computer failing
probably the latter
reboot time
download more ram
(i suspect it's failing, as it randomly changed to the lowest resoution earlier for no reason with no input)
and then discord crashed
okay i'm gonna commit my changes first, juuuuuuust in case
this'll spoil some things i did for Cold Beans, but it's coming out this week anyway so whatevs
anyone got the documentation on the arguments that SMODS.add_card() supports?
how do you animate a card moving to a specific screen location
what do you want to accomplish?
hey @red flower
So I tried out the code you sent me for the credits and I see that it looks way more efficient than normally making every single G.UIT.T
But I was wondering if it was possible to add a node before the modNodes
Tried like this but sadly it doesn't work
a card visually sliding in from the right
ah, you should draw from G.discard in that case
help
why is the card not staying in its area and why aren't my patches taking
well no i want it to stay in its area
have you played cloverpit
discard
okay well my patch is working, it's just not... working?
oh like so you mean you want to slide a card in from G.discard
yeah
what happens after?
without actually moving it
ohhh so you're adding a card to G.play to score
and then returning it
like, When hand scores, a previously discarded card counts in scoring
dam
bump.
adding an emplace call just makes the card vanish
modNodes is a list of nodes, you need to either wrap it in another node or you can table.insert(modNodes, 1, [your nodes]) and use the original code
how do you do this custom cardarea stuff n 
wait, by wrapping it in another node does that mean that I should make another node and in their children nodes add the modNodes list?
yes
I tried like this but it doesn't show up
(at least it doesn't crash now)
it shouldnt be a text node but also it shoud be nodes = modNodes like in the code i sent
what type of node should it be?
row or column
it works now, thank you so much!
how would i go about making a deck that doesn't allow certain booster packs to appear? say i want to remove all buffoon packs from appearing like in jokerless? (nvm i figured it out)
how do i make a 100% fake card thats just for visuals
ie creating or destroying it wont trigger anything
bump. patches are working now, but the thing with the card just existing and not staying in its cardarea without the emplace call or disappearing with it is still happening
and it's still not unlocking