#💻・modding-dev
1 messages · Page 672 of 1
Well no you can just use the generate_ui function
But that requires pretty intricate knowledge of how card ui is structured iirc
so i'd need to hook generate_ui?
No just a generate_ui function in the definition
ah ok
bc i'm trying to add the animated tenna text to a joker
yep
when something like this happens the error is the second return value, so you might want your loader to catch that so you know what went wrong
that'd be so funny lol dnsfjk, idk how I'd do it myself as I'm not too experience in stuff, but good luck!
ohh?
assuming your talking to me lol, sorry if this was a wrong assumption, but this is good info if so, thank you! <3
Yeah
Make sure you put the function call outside the assert though
So you have assert(SMODS.load_file(...))()
mmm I see, thank you! I did make that mistake just now lol
just curious, but what is "assert"? like, what is it doing? Just curious! Want to know more so I can hopefully be a better coder in the future <3
what's the code to check if a specific voucher has been purchased during that run?
trying to make a consumeable with an in_pool function that only returns true with that voucher
-# dont question why im doing it this way, i've scuffed my code in ways i dont want to fix right now
#SMODS.find_card('voucher_key')>0
assert(value, error) will error with error if value is false or nil, otherwise it returns value.
SMODS.load_file returns a function (holding the loaded file date) as the first value and an error (if applicable) as the second, which is the perfect format for assert
G.GAME.used_vouchers["voucher_key"]
oooo, yeah, ok, that is quite helpful! good to know!
it does yea
speaking of, another code question rq, when and when not should I put a , after an end? I'm only asking because one one side, if I do include one on a specific line, it causes an error telling me to remove it, and if I don't, an error is also caused but instead for the reason of my jokers that belong to the custom rarity "attempting to get inserted into an empty pool", whatever that means?
Commas are used to seperate values in tables and function calls, so it should only be after the end of a function defined inside of a table/function call
Inserting into an empty pool just means the rarity/consumable type set on the object doesnt exist
Make sure you put the mod prefix behind your rarity key in the joker definitions
oooohhhh, that might be it actually, thank you, I didn't think I needed to do that if it was a joker from the same mod that the rarity came from, thank you! Guess that's what happens when you take as long a break as I have from balatro modding lol sdfnjk
Thanks for all the help Eris! 😊
when creating a card with Card(), how can i change the size of the card?
i dont think i wrote the key right, it does need the mod prefix, right?
you forgot the v prefix for vouchers
what's wrong with this AnimatedSprite(0,0,0.5,0.5,G.ANIMATION_ATLAS.elle_tenna_its_tv_time,0)
aahhh okay, i had a feeling but i wanted to be sure
wait does it need to be a table maybe
am i have stupid
also, in in_pool, how can i get the key of the card?
wdym
eris do u know what i'm doing wrong 😭
I dont...
oh i think it's to do with my object node
i'll just uhhh
local cardpopup_ref = G.UIDEF.card_h_popup
function G.UIDEF.card_h_popup(card)
local ret_val = cardpopup_ref(card)
local obj = card.config.center
if obj and obj.key == "j_elle_tenna" and obj.discovered then
local tvtime_sprite = SMODS.create_sprite(0,0,.5,.5, "elle_tenna_its_tv_time", {x=0,y=0})
local title = {
n = G.UIT.O,
config = { object = obj }
}
ret_val.nodes[1] = title
end
return ret_val
end```
if there's one thing i've learnt from my own fuck ups, it's that if the error code references files outside your mod, the entire block you added is likely screwed lol
okay, what obvious mistake did I make this time lmao nsdkfj heh sndfk
bump
or more generally, how do you change the size of a card?
the 3rd and 4th arguments are width and height
if you set them to G.CARD_W*.75, G.CARD_H*.75 then they'll be 0.75x the normal size
thankuthanku
yw
i dont see anything wrong, it might be earlier
what does this crash tend to mean ;u;
Oops! The game crashed:
game.lua:2831: bad argument #1 to 'push' (boolean, number, string, love type, or table expected)
i may be blind i was putting the wrong object in the node
something to do with saving it seems
you are saving a function in an object
o ^^
happens to the best of us
i have this, is this the problem? i have another joker doing something similar, and also not crashing
local main_menu_ref = Game.main_menu
Game.main_menu = function(change_context)
local ret = main_menu_ref(change_context)
for k, v in pairs(G.P_CENTERS) do
v.in_pool = v.in_pool or function()
return true
end
local in_pool_ref = v.in_pool
v.in_pool = function()
if not G.jokers then return in_pool_ref() end
for _, vv in ipairs(G.jokers.cards) do
if vv.config.center.key == "j_phanta_cataclysm" then
if vv.ability.extra and (vv.ability.extra.card1 == v.key or vv.ability.extra.card2 == v.key) then
return false
end
end
end
return in_pool_ref()
end
end
return ret
end
fyi this hooks the function once every time you go to the main menu
You should also probably just hook SMODS.add_to_pool for this
oh 🥀
🎉 I found it!
issue was an accidental leftover of one half of a { } bracket, leading to the return of the loc ending early :3
how do i fix the positioning
so like so?
local smodsatpref = SMODS.add_to_pool
function SMODS.add_to_pool(prototype_obj, args)
if not G.jokers then return smodsatpref(prototype_obj, args) end
for _, v in ipairs(G.jokers.cards) do
if v.config.center.key == "j_phanta_cataclysm" then
if v.ability.extra and (v.ability.extra.card1 == prototype_obj.key or v.ability.extra.card2 == prototype_obj.key) then
return false
end
end
end
return smodsatpref(prototype_obj, args)
end
i Think so
local tvtime_sprite = SMODS.create_sprite(0,0,1,1, "elle_tenna_its_tv_time", {x=0,y=0})
local title = {
n = G.UIT.R,
config = { align = 'cm', padding = -0.1, no_fill = true },
nodes = {
{
n = G.UIT.O,
config = { object = tvtime_sprite }
}
}
}```
i assume this is 0-width
in that case, try setting minw
ty
npnp
nope :p
i've tried it on both
made for each other!
true!
except mine was because i misplaced a UIT.B


pics like these are why i love programming
you will never see anything quite as broken as this in any other profession lmao
i believe you're looking for card.states.drag.can -> bool
ohhh no, it's to toggle if the card is draggable
ohh thats also useful i guess
what are you trying to use this for exactly? maybe there's something else that'd fit
aahhhh
well ima be honest, im not sure if that's even possible .w.
when its being dragged around just in general?
check G.CONTROLLER.dragging.target
Or when it starts/stops being dragged
That probably isnt a good idea for something thats constantly happening
you just calculate context and return drag target and a bool
okay but when are you going to calculate that context
if the drag_target = card
Yeah but
and on card:drag
context is used more for like blocks of the game
think of it like DnD initiative kinda
not a good idea to make a context for dragging a card
If you just want to check if the card is being dragged all the time you should just check that in update
Probably
doesnt update just send something every tick
yeah, so not what you want context for then, that's an update job
i just want it to gain something when the card is being dragged around
i mean it could be a context on drag/stop drag
Okay but like. Constantly? Or when it stops/starts being dragged?
what do you mean
idk what else im meant to say
also what do you mean by "gain something"
Like scaling or?
does it only check when the card has been picked up and dropped or does it check for it being dragged every tick?
scaling or not
how would you word the effect
fuck i dont even know yet i just know it has something to do with dragging because i'm turning the drag tool from roblox into a joker lol
Oh
how do i change the framerate of animated sprites
well the options are probably do a context on drag/stop_drag or check G.CONTROLLER.dragging.target in update imo
ok
Well if you want it to gain something constantly over time while its being dragged just check if its being dragged in update and then increment whatever value by the value/second multiplied by dt
I think
nvmd i think i found it
this has no effect, am I using the wrong key?
SMODS.Rarity:take_ownership('Legendary', { badge_colour = HEX('ffffff'), }, true )
im assuming the badge colour wont be set properly since vanilla rarity colours are set differently from smods ones
You should change G.C.RARITY[4] instead
not actually trying to set badge color, just using it to see if I got the right key. But should take ownership not be used for rarities?
Not sure, depends on the goal i think
making a joker that makes legendaries appear in shop/anywhere. Was trying to implement it by modifying legendary's get_weight function
true
looked a bit at jest's fabled deck, though that seems to have scaling chances the longer you go without seeing a legendary, was thinking it should be simpler to just change it to a flat chance
yeah alright, guess theres no simpler way
how do i make a card's calculate acknowledge values that changed during the scoring animation
You can't, because calculations happen before the animation.
how do you get a joker's rarity from a custom pool, like the Food pool when doing SMODS.Create_Card?
i tried doing
SMODS.add_card {
set = 'Food',
rarity = 'Uncommon',
key_append = 'food_uncommon_joker_spawn'
}
but this lets any rarity of food joker spawn, not just uncommon
you would need to set up rarities in the ObjectType
local jokers = {}
for k, v in pairs(get_current_pool('Food')) do
if G.P_CENTERS[v] then
if G.P_CENTERS[v].set == 'Joker' and Card.is_rarity({ability = {set = 'Joker'}, config = {center = G.P_CENTERS[v]}}, 'Uncommon') then
table.insert(jokers, G.P_CENTERS[v].key)
end
end
end
local key = pseudorandom_element(jokers, 'seed')
SMODS.add_card({key = key})
looks like it's working! thank you
i had an idea for an effect that would guarantee the appearance of a soul in the next opened spectral or arcana pack, but i'm not sure how that could be implemented
Hook create_card
if condition and (set equals tarot or set equals spectral) and soulable equals true then forced key equals soul, return create card ref
with possibly some other necessary tweaks
i did have an existing create_card hook. so like this?
(i return RV later)
you would want to check that soulable is true, otherwise this could apply to e.g. shop cards or purple seal cards
No, it would be: if next(SMODS.find_card('j_modprefix_key')) and soulable and (_type == 'Tarot' or _type == 'Spectral' or _type == 'Tarot_Planet')
i'd like to localise a table of formatted text, and put it in my UI. how do i do that?
i can't recall exactly what i knew about this when i originally implemented it, but i use it in a dummy center i set up to be attached to info_queue to create dynamic tooltip text
basically what i do here is i put set myText here to some kind of formatted text like
{
'This {C:joker}Joker{} gains',
'{X:mult}X#1#{} Mult for every',
'repetition of the past two weeks',
'{C:inactive}(Currently {X:mult}X#2#{C:inactive})'
}
and the loop in that will iterate through that table and parse each individual string into UI text to look how you'd expect it to
good enough
so localize_box takes individual string values, but you can make a helper function that operates like that to parse a formatted table, something like
localize_table = function(formattedTable)
local nodesRet = {}
for _, str in ipairs(formattedTable) do
nodesRet[#nodesRet + 1] = {{
n = G.UIT.R,
config = { align = 'cm', padding = 0.03 },
nodes = SMODS.localize_box(loc_parse_string(str), { scale = 1.0 })
}}
end
return {{ n = G.UIT.C, config = { align = 'cm', padding = 0.03 }, nodes = nodesRet }}
end
but i'm not that good at UI code so 
you do need to double nest UI nodes like that, but i forget the exact structuring
parse_lines = function(lines, args, config)
local result_nodes = {}
if lines then
for _, line in ipairs(lines) do
local localized = SMODS.localize_box(type(line) == "string" and loc_parse_string(line) or line, args)
table.insert(result_nodes, {
n = G.UIT.R,
config = { align = args.align, minh = args.minh },
nodes = localized,
})
end
end
return {
n = G.UIT.C,
config = config,
nodes = result_nodes,
}
end
i see 
awesomes ^u^ thanks!

so i'm getting this crash
what the fuck is cultural bean
(don't ask :3)
what the fuck is cultural bean
i don't know 😭
holy bad practice speedrun
anyway
oh my god
also wtf is bizarrtro and why is it under lovely mods
@near coral
@near coral
well yeah
anyway
team_things is
{
[1] = {
"this is test text",
"absolute {C:attention}lol{}"
},
[2] = {
"{S:2}and more{}"
}
}```
Nope, you need handle multiboxes manually too

i'll just do it manually ;u;
okay i haven't done this right, i'm getting the same crash
local localize_table = function(table_thing, args, config)
local t = {}
if table_thing then
for _, line in ipairs(table_thing) do
local localised = SMODS.localize_box(type(table_thing) == "string" and loc_parse_string(line) or table_thing, args)
table.insert(t, {
n = G.UIT.R,
config = { align = args.align, minh = args.minh },
nodes = localised,
})
end
end
return { n = G.UIT.R, config = config, nodes = t }
end
ColdBeans.make_me_a_credits_page_please = function(team)
local team_things = G.localization.cbean_credits[team or 1]
local t = localize_table(team_things)
return {
n = G.UIT.C,
config = { minw = 11, colour = G.C.CLEAR, align = "cm", id = "cbean_credits_page" },
nodes = t
}
end
also i'm gonna expunge the previous things to avoid leaks
if you're passing this then it will not work, again, need to handle multiboxes too
i don't know what you mean by that 😭
you really dont know what is multibox?
like i know a multibox is when a joker has mutliple ability texts in one
but like. i don't have multiple of those
it's being indexed into
you do there
yeah but that's being indexed into
SMODS.Joker{
calculate = function(self,card,context)
if not context.blueprint then
if context.setting_blind and card.ability.extra.stored_joker == nil then
local other_joker = nil
for i = 1, #G.jokers.cards do
if G.jokers.cards[i] == card then other_joker = G.jokers.cards[i + 1] end
end
if other_joker then
card.ability.extra.stored_joker = other_joker
SMODS.destroy_cards(other_joker)
return {
message = localize('k_eaten_ex')
}
end
end
-- BUG: When reloading a run, the stored joker becomes MANUAL REPLACE instead.
if context.end_of_round and context.main_eval and context.game_over == false and card.ability.extra.stored_joker then
local edition = SMODS.poll_edition{ key = "gl_litabelle", guaranteed = true}
if edition == 'e_negative' or #G.jokers.cards + G.GAME.joker_buffer <= G.jokers.config.card_limit then
local copied_joker = copy_card(card.ability.extra.stored_joker)
copied_joker:set_edition(edition, true)
G.jokers:emplace(copied_joker)
copied_joker:start_materialize()
copied_joker:add_to_deck()
card.ability.extra.stored_joker = nil
return {
message = localize('gl_litabelle')
}
else
return {
message = localize('k_no_room_ex')
}
end
end
end
end,
}```
If I reload a run while a joker is stored, it becomes MANUAL_REPLACE instead, anyone know how to fix it?
- you're edited localize_table, it should return C, not R, otherwise text lines will be in one line
- 3rd to last line should be { t }
i have something like this in my mod and i just move the joker to a hidden cardarea
else you would need to hook card:save and load
and do stuff
In other words,
local localize_table = function(table_thing, args, config)
local t = {}
if table_thing then
for _, line in ipairs(table_thing) do
local localised = SMODS.localize_box(type(table_thing) == "string" and loc_parse_string(line) or table_thing, args)
table.insert(t, {
n = G.UIT.R,
config = { align = args.align, minh = args.minh },
nodes = localised,
})
end
end
return { n = G.UIT.C, config = config, nodes = t }
end
ColdBeans.make_me_a_credits_page_please = function(team)
local team_things = G.localization.cbean_credits[team or 1]
local t = localize_table(team_things, { default_col = G.C.UI.TEXT_LIGHT, align = "cm" })
return {
n = G.UIT.C,
config = { minw = 11, colour = G.C.CLEAR, align = "cm", id = "cbean_credits_page" },
nodes = { t }
}
end
Oooo how do u do that?
i assume this line in SMODS.localize_box is to blame
for _, subpart in ipairs(part.strings) do
the crash log says part is a string
wait wtf you did
this and then i remove the joker from G.jokers and move it to here and the same the other way around, this is a common effect in my mod so i use mod calculate to bring the joker back
local localize_table = function(table_thing, args, config)
local t = {}
if table_thing then
for _, line in ipairs(table_thing) do
local localised = SMODS.localize_box(type(line) == "string" and loc_parse_string(line) or line, args)
table.insert(t, {
n = G.UIT.R,
config = { align = args.align, minh = args.minh },
nodes = localised,
})
end
end
return { n = G.UIT.C, config = config, nodes = t }
end
yeah i have that
your one have issues, replace with this one
is table_thing array of strings?

it expects { "a", "b" }, not { [1] = { "a", "b" } }
give me one second to calm down myself
alrighty
sorry, not in the best mood today, i'm back
allg!
I'll do the thing, give me a minute
if i wanted to make a joker have double sell value how would i do that?
like
the multiplier stacks on modifiers too like polychrome and gift and such
you (probably) can do card.ability.extra_value = card.sell_cost
else you would have to hook card:set_cost and change card.sell_cost after it runs
and this stays up to date?
i mean
does it update
idk whats your problem all works fine for me
it wouldnt update actually
so the second option
not working for me strangely
local localize_table = function(table_thing, args, config)
local t = {}
if table_thing then
for _, line in ipairs(table_thing) do
local localised = SMODS.localize_box(type(table_thing) == "string" and loc_parse_string(line) or table_thing, args)
table.insert(t, {
n = G.UIT.R,
config = { align = args.align, minh = args.minh },
nodes = localised,
})
end
end
return { n = G.UIT.C, config = config, nodes = t }
end
ColdBeans.make_me_a_credits_page_please = function(team)
local team_things = G.localization.cbean_credits[team or 1]
local t = localize_table({
"this is test text",
"absolute {C:attention}lol{}"
}, { default_col = G.C.UI.TEXT_LIGHT, align = "cm" })
return {
n = G.UIT.C,
config = { minw = 11, colour = G.C.CLEAR, align = "cm", id = "cbean_credits_page" },
nodes = { t }
}
end```
pleaase copy this and replace your own
I know reading is hard
Sorry, just a bit sad because all of this
apology accepted ^u^
You're smart ghost and I have some expectation on you
i'm smart in some areas, but i also lack common sense 😭
mm, it's still crashing for some reason
Maybe that's my issue, have expectations in a first place
local localize_table = function(table_thing, args, config)
local t = {}
if table_thing then
for _, line in ipairs(table_thing) do
local localised = SMODS.localize_box(type(table_thing) == "string" and loc_parse_string(line) or table_thing, args)
table.insert(t, {
n = G.UIT.R,
config = { align = args.align, minh = args.minh },
nodes = localised,
})
end
end
return { n = G.UIT.C, config = config, nodes = t }
end
ColdBeans.make_me_a_credits_page_please = function(team)
local team_things = G.localization.cbean_credits[team or 1]
local t = localize_table(team_things, { default_col = G.C.UI.TEXT_LIGHT, align = "cm" })
return {
n = G.UIT.C,
config = { minw = 11, colour = G.C.CLEAR, align = "cm", id = "cbean_credits_page" },
nodes = { t }
}
end```
no, try again
copying in discord sometimes sucks
i told windows to paste 😭
I can just paste code which will work but I want do that in hard way in hope that you'll learn some stuff
that's okay
no problem salty ghosh
Be more careful while you're doing things and your life will be much easier
I'm rechecking my code multiple times even if it's working just to make sure I'm sane
It's annoying but helps improve a code and make less mistakes
Anyone know how to add restrictions to a challenge rather than using take ownership?
That worked, thx
is it not in the challenge docs?
or what do you mean
ah for a vanilla one?
wdym rather than using take ownership? that's just generally how you modify vanilla objects
of course you could instead patch the code where the original challenge is created, but I doubt that's what you want and there's hardly ever a point in that
ye
To avoid conflict with other mods
that's something take_ownership, despite its name, is very good at
Oh ok
it's a pretty bad name for what it does actually, and that's completely my fault
Do I need to include vanilla stuff or nah?
all g
-# tbh there should probably be some sort of parameter for smods objects to ban them from existing challenges
Bruh xD
Also fsr I get this crash when loading restrictions
Oh wait
nvm I just realised one of the jokers was outdated
Like a key was wrong
other properties? no. in this case though if there's other restrictions it doesn't merge the tables, so you'd have to take care of that, i.e., get the pre-existing table and insert what you need into it
Ah oki
what do i need to do to force a showdown blind on a certain ante?
take_ownership rename update when 
is there a game state for just normal play during a blind? i have a sticker i want to apply to consumeables only if they're spawned during the blind
try G.STATE.SELECTING_HAND
but if you mean during scoring, you could also try G.STATE.HAND_PLAYED
If you just want during the blind in general you should check SMODS.is_active_blind("blind_key")
will G.STATE.SELECTING_HAND be true while an emperor or high priestess is resolving or when a purple seal is being resolved?
i'm not sure - eris's solution might cover that
Those all happen in different states afaik
can i do it without a key if i just want to know if any blind is active?
No
maybe if G.GAME.blind would work?
You should check G.GAME.blind.in_blind then
okay, ill start there and see if i can get it working
sweet, if G.GAME.blind and G.GAME.blind.in_blind works
got a few errors and idk how to fix em
you know how it is
idk why reroll surplus isnt working
back.lua:207: attempt to index local 'self' (a nil value)
Additional Context:
Balatro Version: 1.0.1o-FULL
Modded Version: 1.0.0~BETA-1501a-STEAMODDED
LÖVE Version: 11.5.0
Lovely Version: 0.9.0
Platform: Windows
Steamodded Mods:
1: Hatchet by Plasma [ID: hatchet, Version: 1.6.1]
2: DebugPlus by WilsontheWolf [ID: DebugPlus, Version: 1.5.1, Uses Lovely]
3: Deltarune Deck by nolo33lp [ID: DeltaruneDeck]
Lovely Mods:
1: BMM-Compat
Stack Traceback
===============
(3) LÖVE metamethod at file 'boot.lua:352'
Local variables:
errhand = Lua function '(LÖVE Function)' (defined at line 605 of chunk [lovely debugplus.console "debugplus/console.lua"])
handler = Lua function '(LÖVE Function)' (defined at line 605 of chunk [lovely debugplus.console "debugplus/console.lua"])
(4) Lua field 'apply_to_run' at file 'back.lua:207'
Local variables:
self = nil
(*temporary) = table: 0x2ba1d498 {order:7, _d:false, set:Voucher, key:v_reroll_surplus, _saved_d_u:true, available:true, discovered:true, alerted:true, pos:table: 0x2ba1d648, unlocked:true (more...)}
(*temporary) = string: "v_reroll_surplus"
(*temporary) = nil
(*temporary) = nil
(*temporary) = nil
(*temporary) = nil
(*temporary) = nil
(*temporary) = nil
(*temporary) = nil
(*temporary) = nil
(*temporary) = nil
(*temporary) = string: "attempt to index local 'self' (a nil value)"
(5) Lua field 'func' at file 'src/backs.lua:105' (from mod with id hatchet)
(6) Lua method 'handle' at file 'engine/event.lua:96'
Local variables:
self = table: 0x2b331278 {start_timer:true, timer:TOTAL, blockable:true, trigger:immediate, func:function: 0x2b3acb80, delay:0, complete:false, time:15.581820763419, blocking:true (more...)}
_results = table: 0x2bd71b88 {blocking:true, pause_skip:false, time_done:false, completed:false}
(7) Lua method 'update' at file 'engine/event.lua:184'
Local variables:
self = table: 0x2ba81778 {queues:table: 0x2ba817a0, queue_last_processed:11.633333333333, append_count:0, append_queue:base, queue_dt:0.016666666666667, queue_timer:11.75124900084 (more...)}
dt = number: 0.0165
forced = nil
(for generator) = C function: next
(for state) = table: 0x2ba817a0 {unlock:table: 0x2ba81890, other:table: 0x2ba81930, tutorial:table: 0x2ba818e0, base:table: 0x2ba818b8, achievement:table: 0x2ba81908}
(for control) = number: nan
k = string: "base"
v = table: 0x2ba818b8 {1:table: 0x2b331278, 2:table: 0x2b5c80d8, 3:table: 0x2bd28c00, 4:table: 0x2bd11f18, 5:table: 0x2bc81160, 6:table: 0x2bd7b638, 7:table: 0x2b5ef3d8 (more...)}
blocked = boolean: false
i = number: 1
results = table: 0x2bd71b88 {blocking:true, pause_skip:false, time_done:false, completed:false}
(8) Lua upvalue 'gameUpdateRef' at file 'game.lua:2617'
Local variables:
self = table: 0x2b37fc88 {F_GUIDE:false, F_CRASH_REPORTS:false, F_QUIT_BUTTON:true, HUD_tags:table: 0x2bfdcb58, F_ENGLISH_ONLY:false, viewed_stake:1, HUD:table: 0x2bf64d28 (more...)}
dt = number: 0.0165
http_resp = nil
(9) Lua method 'update' at Steamodded file 'src/ui.lua:190'
Local variables:
self = table: 0x2b37fc88 {F_GUIDE:false, F_CRASH_REPORTS:false, F_QUIT_BUTTON:true, HUD_tags:table: 0x2bfdcb58, F_ENGLISH_ONLY:false, viewed_stake:1, HUD:table: 0x2bf64d28 (more...)}
dt = number: 0.0165
(10) Lua field 'update' at file 'main.lua:1074'
Local variables:
dt = number: 0.0165
(11) Lua function '?' at file 'main.lua:1013' (best guess)
(12) global C function 'xpcall'
(13) LÖVE function at file 'boot.lua:377' (best guess)
Local variables:
func = Lua function '?' (defined at line 984 of chunk main.lua)
inerror = boolean: true
deferErrhand = Lua function '(LÖVE Function)' (defined at line 348 of chunk [love "boot.lua"])
earlyinit = Lua function '(LÖVE Function)' (defined at line 355 of chunk [love "boot.lua"])
got this error
-- Pilot Deck
SMODS.Back {
key = 'pilot',
pos = { x = 3, y = 0 },
config = { vouchers = { 'v_reroll_surplus', 'v_clearance_sale' } },
loc_txt = {
name = 'Pilot Deck',
text = {
'Start run with',
'{C:green}#1#{},',
'and {C:attention}#2#{},',
},
},
unlocked = false,
no_collection = false,
atlas = 'CustomDecks',
loc_vars = function(self, info_queue, back)
return {
vars = { localize { type = 'name_text', key = self.config.vouchers[1], set = 'Voucher' },
localize { type = 'name_text', key = self.config.vouchers[2], set = 'Voucher' },
}
}
end,
apply = function(self, back)
for k, v in pairs(self.config.vouchers) do
G.GAME.used_vouchers[v] = true
G.GAME.starting_voucher_count = (G.GAME.starting_voucher_count or 0) + 1
G.E_MANAGER:add_event(Event({
func = function()
back.apply_to_run(nil, G.P_CENTERS[v])
return true
end
}))
end
end,
check_for_unlock = function(self, args)
return args.type == 'win_stake' and get_deck_win_stake() >= 10
end
}``` here's my deck's code
idk what im doing
nvm i figured out the text issue
idk about the apply function thing
should be Card.apply_to_run(nil, G.P_CENTERS[v]) instead
What's the best way to upgrade just the chips/mult of a hand?
How would I use that to upgrade chips or mult alone by a set amount?
something like hands = "High Card", parameters = { "mult" }, func = function(current, base, param) return current + 1 end
that will do mult + 1
What would be a good template for my coder to use to help him use drawstep to have multiple stake stickers on stuff
I have 2 stake sets, one vanilla and one for my mod, I'm intending for the stickers for both to show up measuring your progress on them individually
And yes I have the stakes for my mod not overlapping with vanilla ones
Does anyone know how to get a custom sound to play when a joker is triggered (standard joker_main)? Any one of the main contexts I tried had the sound play at the beginning of the scoring phase, rather than the individual joker getting triggered.
return sound = "..." in your joker_main effect
if you run play_sound it will run as soon as the code is ran, and Joker effects are all calculated right after your hand is played
This is what I got so far:
SMODS.Joker {
key = "rotated_hamsa",
loc_txt = {
name = 'Rotated Hamsa',
text = {
"{C:mult}+#1#{} Mult on {C:attention}final hand{} of the round"
}
},
blueprint_compat = true,
rarity = 1,
cost = 4,
pos = { x = 4, y = 0 },
config = { extra = { mult = 30 } },
atlas = 'ModdedVanilla',
loc_vars = function(self, info_queue, card)
return {vars = { card.ability.extra.mult }}
end,
calculate = function(self, card, context)
if context.joker_main and G.GAME.current_round.hands_left == 0 then
-- play_sound('cloverpit_hamsa')
return {
mult = card.ability.extra.mult,
sound = 'cloverpit_hamsa'
}
end
end
}
The sound doesn't play at all via this method?
Can I do an optional dependency in the code or
i might have gotgten it wrong but i thought it was just returning sound
It should be the id not the name
Really??
I've been using the name for like half of my dependencies
e.g.
unless the id is literally capitalized like that in steamodded and lovely
Yes, they are like that.
Hmm, after some testing, it seems the animations are a little bit broken? The numbers just zero out when the animation plays.
is this how you do the boolean display on a joker?
you don't need to put it in update
loc_vars is ran every time the description is shown to the player
just put the code there
better yet, you could just do card.ability.extra.deathdefiance and "Active" or "Inactive"
its a property of how lua logic works, if you put something like true and 1 or 2 it will always return 1
it's basically equivalent to a ternary statement in any other language
i never used the feature myaelf but you can report it as an issue to smods
x and y or z can be summerized as shorthand for if x then y else z, but it also immediately returns the value rather than needing to use a variable
looks right, assuming youre using #1# as your var for activity
yes
0/3 will be #2#/#3#
now to add the counter.
can you set scalar_value to a number instead of a variable
i had this convo the other day with eremel and reminded me about the existence of the operation arg - it's a little roundabout but here's that discussion if it helps your issue #1209564621644505158 message
but basically for scale_card you need to always pass in a way to get your multiplier variable in case something else wants to manipulate it permanently. if you don't want that, you're supposed to pass in a block_overrides table as part of your args table for every scale_card call where you don't want those changes made, where value = true prevents the value from being substituted just for that operation and scalar = true will prevent your scalar value from being permanently manipulated
and in cases where you absolutely need to use a number that can't be reasonably kept and accessed from the config value, you specify an operation function that does the operation you need to do
it could use more documentation tbh
Figured this out, writing it here for future reference. Needed to wrap the sound in a function in the event manager:
if context.joker_main and G.GAME.current_round.hands_left == 0 then
if context.cardarea == G.jokers then
G.E_MANAGER:add_event(Event({
func = function()
play_sound('cloverpit_hamsa')
return true
end
}))
end
No, you also need to put it in a func in the return.
Hey folks, I'm testing out UIs (and the infinite parentheses my editor is not set up to indent correctly) and I'm making a tooltip. I used a newline character here because I'm not familiar with what's correct, and I was wondering if there's a way to resize this toolbox? I know in joker descriptions you can use [1] = and such but it didn't seem to take this time
well how are you currently defining its size
calculate = function(self, card, context)
if not card.ability.extra.deathdefiance == true and card.ability.immutable.counter <= 3 then
if context.before and next(context.poker_hands["Flush"]) and not context.blueprint then
SMODS.scale_card(card, {
ref_table = card.ability.immutable,
ref_value = "counter",
scalar_value = "addition",
scaling_message = {
message = card.ability.immutable.counter .. "/" .. card.ability.immutable.goal,
colour = G.C.DARK_EDITION
}})
else
card.ability.immutable.counter = 0
SMODS.calculate_effect({message = "Reset!", colour = G.C.DARK_EDITION}, card)
end
end
if context.end_of_round and context.main_eval and (context.game_over and card.ability.extra.deathdefiance == true) or context.forcetrigger then
G.E_MANAGER:add_event(Event({
func = function()
G.hand_text_area.blind_chips:juice_up()
G.hand_text_area.game_chips:juice_up()
play_sound('tarot1')
return true
end
}))
SMODS.calculate_effect ({
message = ZagreusTalk[math.random(#ZagreusTalk)],
saved = "Death Defied!",
colour = G.C.DARK_EDITION,
card = card
})
card.ability.extra.deathdefiance = false
SMODS.calculate_effect({message = "Reset!", colour = G.C.DARK_EDITION}, card)
end
end```
am i doing this right
I'm not familiar with how to do so with UI text so like this ```
n = G.UIT.C, config = {minw=3, minh=2, colour = G.C.MONEY, padding = 0.15,
tooltip = {
text = {"The {E:1,C:legendary}Hellscape{}...\nHow far will YOU fall~?" },
I imagine the tooltip UI uses the same node logic, but I don't know how I would access that
Right below the root, sure
-- Root node, needed in all UI
n = G.UIT.ROOT,
-- The config which details how the node will look
config = { r = 0.25, align = "cm", padding = 0.8, colour = G.C.BLACK, minw = 8, minh = 6, juice = true},
-- and repeat with more nodes in nodes={}
nodes = {
-- {
-- n = G.UIT.R, config = { r = 0.25, padding = 0.2, colour = G.C.PURPLE, w = 3, h = 1,
-- tooltip = { text = {"The {E:1,C:legendary}Hellscape~{}...\nHow far will YOU fall~?" } },
-- },
{
n = G.UIT.C, config = {minw=4, minh=4, colour = G.C.MONEY, padding = 0.15},
nodes = {
{n = G.UIT.R, config = {minw=2, minh=2, colour = G.C.RED, padding = 0.15},
nodes = {
{n = G.UIT.C, config = {minw=1, minh=1, colour = G.C.BLUE, padding = 0.15}},
{n = G.UIT.C, config = {minw=1, minh=1, colour = G.C.BLUE, padding = 0.15}}
}},
{n = G.UIT.R, config = {minw=2, minh=1, colour = G.C.RED, padding = 0.15}, nodes = {
{n = G.UIT.C, config = {minw=1, minh=1, colour = G.C.BLUE, padding = 0.15}},
{n = G.UIT.C, config = {minw=1, minh=1, colour = G.C.BLUE, padding = 0.15}}
}
}
}
},
{
n = G.UIT.C, config = {minw=3, minh=2, colour = G.C.MONEY, padding = 0.15,
tooltip = {
text = {"The {E:1,C:legendary}Hellscape{}...\nHow far will YOU fall~?" },
}}
}
},
}```
Most of it is just the tutorial UI code
I hate how it comes out on Discord if you don't remove the starting spaces
i see.
if you can get the variable that goes into, you could try changing
var[1].config.minh
The variable being the "tooltip box" or whatever you wanna call it
I'll certainly look about but I'm not hopeful
How would I check if a playing card is retriggered?
loc_vars = function(self, info_queue, card)
local m_end = {}
if G.gl_litabelleArea.cards[1] then
local stored_card = G.gl_litabelleArea.cards[1]
local joker_name = localize{
type = 'name_text',
set = stored_card.config.center.set,
key = stored_card.config.center.key,
}
localize{
type = 'other',
key = 'gl_litabelle_contains',
nodes = m_end,
vars = {joker_name}
}
info_queue[#info_queue + 1] = stored_card.config.center
end
return { vars = {card.ability.extra.dollars}, main_end = m_end[1]}
end```
The info queue displays the joker's base values, even tho they scale. (Second image is after litabelle spits Mossibug back out)
Anyone know how to fix this?
local center = G.P_CENTERS[stored_card.config.center.key]
local other_center = SMODS.shallow_copy(center)
other_center.loc_vars = function(self, info_queue, uncard) return center.loc_vars(self, info_queue, stored_card) end
table.insert(info_queue, other_center)
thx
wait how you got that is the beans out
anyone know how to get dynatext working or how it works
anyone know any fixed for gmatch
edit: i misspelled arena as areana
How do you make jokers display a message through G.E_MANAGER:add_event?
Or without return functions?
SMODS.calculate_effect({message = 'message', instant = true}, card) and put delay(0.9375) after the event.
thx
i'm trying to make an edition that has a chance to give a permanent extra hand when a blind is defeated, but it also counts all held cards and gives one hand for each of them
how can i prevent it from checking any cards outside the one with the edition?
i think you can do context.individual
but i'm not 100% sure since i've not done edition stuff before
if (context.playing_card_end_of_round and context.other_card == card and context.cardarea == G.hand) or (context.end_of_round and context.main_eval)
or do that
i'll try both options for the sake of it
very well :)
it works! :D
tyy
What kind of mod are you making?
i'm basically trying to translate all of Cult of the Lamb into Balatro (dlc included)
both games are probably my favourite roguelikes i've ever played so wanna see how well they'd mix :3
Oooooh that's really cool! Do you have intentions of a public release once you're done?
technically, it's already public!
but it's in hella early stages so i want to flesh it out just a little more before i send a link here
I see! I could do some bugtesting sometime, I'm always looking for new experiences
(I should emphasize, I am NOT soliciting you here. I'd do it for free because I like seeing modders do their stuff)
lol i didnt take it that way dw X3
but i'd really appreciate it! the more hands i have to spot problems the better
i'm also tryna find someone to help with edition shaders because that is a language i do not understand .w.
If I knew coding I'd gladly help. I'm actually aiming to learn coding myself so I can make my own mods one day
well you're in the right place, that's for sure
whenever you feel ready to try, your best resource is the Steammodded wiki and VanillaRemade for how base game stuff works
but the best advice i could give is to just jump in and learn
unironically, the best way to learn to code is trial by fire. it's gonna be funny, it's gonna be messy, and you're gonna learn that this game can break in ways you never thought possible lmao
Good to know! I'd be happy if I could even get one card working lol
the easiest cards to make have to be Jokers, so that's a good place to start :3
if i wasn't busy making
today i'd help but i could totally give it a shot in a few days once i've done that
take your time, Elle, your personal projects come first lol
Trying to make a card similar to Hallucination, but it creates a copy of a random consumable in a pack instead of a random Tarot card in general, but I can't seem to target any cards in a pack to check if they are consumables/a card to copy. I think G.pack_cards is not being added to when I do check for that area, but I'm not sure how to go about making it work.
calculate = function(self, card, context)
if context.open_booster and #G.consumeables.cards + G.GAME.consumeable_buffer < G.consumeables.config.card_limit then
local pack_cards = {}
for i = 1, #G.pack_cards do
if G.pack_cards[i].ability.consumeable then
pack_cards[#pack_cards+1] = G.pack_cards[i]
end
end
if SMODS.pseudorandom_probability(card, 'test' .. G.GAME.round_resets.ante, 1, card.ability.extra.odds) and #pack_cards >= 1 then
G.GAME.consumeable_buffer = G.GAME.consumeable_buffer + 1
local chosen_card = psuedorandom_element(pack_cards, 'test')
G.E_MANAGER:add_event(Event({
trigger = 'before',
delay = 0.0,
func = (function()
SMODS.add_card {
key = chosen_card.key
}
G.GAME.consumeable_buffer = 0
return true
end)
}))
return {
message = localize('k_plus_tarot'),
colour = G.C.PURPLE,
}
end
end
end
The issue is
for i = 1, #G.pack_cards do
You also have a typo in pseudorandom
G.pack_cards does not exist immediately when the context is run iirc, you should put everything inside of the event
There's a command to specify a specific card pack under g.pack_cards
Yeah this, Eris got it right here. I'm VERY much a coding novice
and the cards are stored in G.pack_cards.cards
With some other issues ironed out, seems to be working as intended (at least for now)
tyty
I guess a quick follow-up is if I want to prevent copying of hidden consumables like Soul and Black Hole, would I just check something like if not card.hidden?
looking for programmers for a complete overhaul mod, if anyone has enough freetime and experience
what context do you use to check if a joker has been spawned in a shop, like when you enter a shop or just rerolled
#1477838185919807620 &
https://docs.google.com/spreadsheets/d/1IZmxSAYg3A7PUdec30P2DpuMGmbayVBILYA1o9Jb6K0/edit?usp=sharing
i tried my best to organize the sheet lmao
does balatro/smods have a way to handle keybinds?
or do i have to hook love.keypressed?
SMODS.Keybind
ty
how to check for if sold joker is a food joker? (i have spectrallib, food pool should be fine)
bump
if context.create_shop_card and context.set == "Joker" then
how to check for first drawn cards
because cards dont calculate in the shop
context.first_hand_drawn?
first drawn cards become electric
and context.hand_drawn is the cards that were drawn
so if context first hand drawn and context hand drawn then set_abilityblablabla
or do i have to check for individual and g.hand or something
also checks if current hand doesn't contain an enhancement already
hook SMODS.create_card I suppose
local smods_cc = SMODS.create_card
function SMODS.create_card(args)
local card = smods_cc(args)
if card.config.center_key == "j_modprefix_key" and args.key_append == "sho" then
-- do stuff
end
return card
end
is sho an internal balatro key or is that custom define
internal for shop items
oh shit didnt know that
pog
where do i put that in terms of layout
like is that in set_ability or as a block after calculate
when developing mods (chances are if you ask for something you're definitely not using JokerForge), it's recommended to take a look at Balatro's source code
it's simply a hook
my code template is pretty much complete, you can put it anywhere
ok im asking a lot of nitpick clarificatyions questions here
would card.ability.extra exist for this hook
like im not fully sure what order things happen in
vanilla doesn't use the smods function
I based my words using this dump right here
im just asking for any approach that works tbh
i dont have that on the one in my phone but it's a couple of months outdated so idk
i dont really care for cleaness or efficiency
i would rather be undertale than heartbound if that make sense
ah ok it got added with the new context
I'm a walking turdbrainlua if context.first_hand_drawn and context.hand_drawn and not context.blueprint then if context.other_card and context.cardarea == G.hand and context.other_card.config.center.key == 'c_base' then context.other_card:set_ability('m_busterb_electric', nil, true) end end
idea: inject_card should work on undiscovered sprites so you can have custom sizes the same way you can have custom sizes for actual cards
can you not just set a display size on the undiscovered sprite
Inject card also wouldnt really make sense because unlike an object type you arent injecting objects into it
i mean, it didnt say so on the wiki, so i kinda assumed not
i mean, fair, but i dont really know a way for this to work otherwise
yeah lol
i made an attempt at displaying a sprite in my UI, but it's not working:
local team_atlas = "cbean_"..G.localization.cbean_credits[team or 1].atlas
G.CBEAN_TEAM_LOGO = Sprite(0, 0, 5, 5 * (G.ASSET_ATLAS[team_atlas].py / G.ASSET_ATLAS[team_atlas].px), G.ASSET_ATLAS[team_atlas], { x = 0, y = 0 })
G.CBEAN_TEAM_LOGO:set_alignment({
major = G.OVERLAY_MENU:get_UIE_by_ID("cbean_credits_page"),
type = 'cm',
bond = 'Strong',
offset = { x = 0, y = 0 }
})```
what's the proper way of doing this :3?
i'm putting each row into an table called t
iirc you have to construct it yourself
rip
you can do that either with a hardcoded list, or by looping through the Joker pool and checking if a Joker has no mod associated with it
experimenting with G.UIT.O
what's the check for when a discard is used again?
context.pre_discard afaik
tyyy
whats a good way to make a ui element change width/height relative to another ui element, maybe one that isnt contained within the other
the easiest way is just trial and error through tweaking the UI node's config
no better way than that sadly
I'm developing a mod right now, is there a way to check the number of unscored cards in a hand with steammodded or something? I tried checking example mods and other mods but can't find anywhere that has done something similar.
#context.full_hand - #context.scoring_hand?
Seems to work thanks! Thought scoring_hand was the string name of the played hand type, got it confused with another variable!
I seem to have done my consumable wrong
I set it to discovered = true but it's not discovered
And yet it's not
and when i hover over it I get this
heres some relevant code i think? the localization probably isnt needed if i want it to be always discovered but I should probably at least try to fix the error
discovered doesnt go in config
Oh i totalyl misread the text lmao
The error is still present even after unlocking it for some reason
same error?
mhm
hmmmm
_ _
yeah, that'd probably do it lol
ok i'll just add it rq
yeah, just commenting it out or adding one throwaway variable is good to make sure it doesnt crash at least
what's like. the variable for the odds i forget
Like i remember you're ideally supposed to do like the game's base odds and then your own number for like a "1 in 4"
or should I just hardcode 1 in 4
so for the loc_vars you need to first initialise your config odds as local variables, like this:
local numerator, denominator = SMODS.get_probability_vars(card, 1, card.ability.extra.odds, 'prefix_cardname')
then when calling it for the card's actual calculate function do:
SMODS.pseudorandom_probability(card, 'prefix_cardname', 1, card.ability.extra.odds)
the string can be whatever you like, since it's just to initialise a random seed, but it's generally prefered to set it to your mod prefix and the name of the card
ya
this is interesting i've never done it this way lol
how have you been doing it, now im curious .w.
like this?
yes, that's perfect
i've only done random numbers with one other thing hold on lemme find it
_ _
listen this was forever ago
im not saying it’s bad
But im impressed at how you got here
I'm pretty sure I stole most of this from vremade
Last i checked, Vremade does not use GAME.probabilities but hey, what matters is you know the proper way to do it now
¯_(ツ)_/¯
...nope same error
omfg it was cuz of 3xcredits
i had removed the "concept" line
cuz i didnt want it
Well
At least that one problem helped you fix a couple others at the same time
also, @red flower, i do have the feature enabled, ive done a few jokers with it now, but it doesnt work on the edition.
can i see the code with it?
yea sure one sec
lemme grab
-- Edition: Echo (guaranteed retrigger)
return function(REW1RED)
SMODS.Edition({
key = "echo",
loc_txt = {
name = "Echo",
label = "Echo",
text = {
"Retrigger this card"
}
},
shader = "coinflip",
config = {},
discovered = true,
in_shop = true,
weight = 3,
extra_cost = 6,
badge_colour = HEX("FFD700"),
calculate = function(self, card, context)
-- repetition_only = seal pass; repetition = joker/retrigger pass (both can grant edition retrigger)
if context.repetition_only or context.repetition then
return {
message = localize('k_again_ex'),
repetitions = 1,
card = card
}
end
end,
})
end
thats it rn
i reverted to when it did playing cards only
yeah what i wanted to know is how the code looked with retrigger joker check
here's how cryptid does it
https://github.com/SpectralPack/Cryptid/blob/53ca0bd5acfb6a324564aafa533588691f580d0f/items/misc.lua#L1263
is there a way to have the display name be different than the text in the badge
i want to make the badge text an abbreviation
it's a consumable type right? i think the name and the label on the badge are in two different places
it should be in the docs now
i meant for the mod itself
the name is like three characters too long for the badge and it's making me unreasonably annoyed
name and display_name
https://github.com/Steamodded/smods/wiki/Mod-Metadata#metadata
Happens to the best of us sushi
i am just so immensely confused by cryptid twt
because of what it is, cryptid's codebase is. difficult to parse
can anyone like, give a better show of joker retrigger on an edition?
im still lost
what was breaking then when i tried that---
did it crash?
no, it just prevented it from showing up in game, and also stopped my other editions??
then something else was wrong, not the if condition
okay, so like
what do i have to change tho...
cause i want it to actually work, and i have other retrigger stuff that works perfectly
like i said, the condition you have right now is only for playing cards, you need to add the retrigger_joker_check part for jokers
thats, not very helpful
please elaborate twt
what part of what I said is confusing you?
the entire thing
i am a tad slow
this is just the same thing as i said in clams
but thats not the problem here
this is just a problem with whatever you have for file loading
that has the retrigger_joker_check at the bottom, you need that in your edition
but instead of checking context.other_card ~= card you do == because you want it to retrigger itself
my point is
it works
it retriggers jokers on a 1/2 for each
but im getting confused on how to transfer that over
i think im just being dumb tho twt
yes
i told you im dumb twt
do you see how that code you just posted has one with retrigger_joker_check at the bottom?
almost all of my code is shit i toss together at like midnight
idk how ANY of this manages to work how it should
yes
you just need to copy that block to the edition and change ~= for ==
if pseudorandom('amo_retrigger_joker') < G.GAME.probabilities.normal / card.ability.extra.odds then
return {
message = localize('k_again_ex'),
repetitions = 1,
card = card
}
end ``` this part right you mean?
yes
yes, don't remove the code you already have
which is what made it just, not load
well no
thats not
how that works
a random if condition doesnt make it just stop loading
it is impossible that that code would make it not load
maybe it was a one off?
what I imagine is that your file loading system skips files that would crash
I nust have it crash if something would make it-
Just*
how do i make a joker with x mult and scaling
okay uh, turns out, im actually just stupid as all hell
thank you for putting up with my stupidity @red flower and @slim ferry
it works now
wait huh
okay thats
it gave 2xmult when in hand-????
sometimes???
so this? calculate = function(self, card, context)
if context.remove_playing_cards and not context.blueprint then
local face_cards = 0
for _, removed_card in ipairs(context.removed) do
if removed_card:is_face() then face_cards = face_cards + 1 end
end
if face_cards > 0 then
-- See note about SMODS Scaling Manipulation on the wiki
card.ability.extra.xmult = card.ability.extra.xmult + face_cards * card.ability.extra.xmult_gain
return { message = localize { type = 'variable', key = 'a_xmult', vars = { card.ability.extra.xmult } } }
end
end
if context.joker_main then
return {
xmult = card.ability.extra.xmult
}
end
end,
ik just is that the section
yeah
and uhh how i make xmult
it also doesnt want to work for scaling jokers?, like it retriggers the effect, but not the scaling?
look further in the same bit
would it be this
return { vars = { card.ability.extra.xmult_gain, card.ability.extra.xmult } }
we all are just a little
nah im alll
well what matters is that you learn
im very stupid
what matters. is that. you learn.
the only way you're proper stupid is if you keep making the same mistake over and over
that's why this entire chat is here to help ya, dw about it
have you made anything else or is this your first joker
what did they do
+4 mult
xmult is just that but change mult for xmult in the code
i have been trying to learn but cannot figure out how to create a failsafe for a joker that gives x10 mult for each discards remaining,
If it reaches 0 discard, it gives X0 mult and it causes mult to basically go 0 and get killed
i actually am just stupid
is there a way to just make it give X1 mult or something if it reaches 0 discards?
if it makes you feel any better, i used to make the same mistakes like 3 months ago
-- PSEUDOCODE
if discards > 0 then
return { xmult = discards * 10 }
end
its so simple
why didnt i think of that
the easiest answers are the ones we overlook the most
i still trip up over a forgotten comma in my tables every day
i sometimes keep forgetting to put comma in an place where its needed.
it makes me feel a bit stupid
if face_cards = 0 then
card.ability.extra.xmult = card.ability.extra.xmult * card.ability.extra.xmult_gain
end
approximatley like this
it shouldnt, it's probably the easiest mistake to make in all languages and applications
and make it do cards with the 5 rank
within the calculate function in the joker
and specifying the rank i still dont know that one myself tbh
that's not a condition i have set in memory
the rank can be checked in context.individual
but I would recommend looking at Walkie Talkie's code or something
personally i would really recommend just copying over jokers from vanilla that do something similar into your mod and tweaking them until they do what you want
frankly the best way to learn
as i've said: the best way to learn programming is trial by fire
Despite it being completely useless, yet im still thinking of adding single use jokers
like whats the point anymore
they are just glorified consumables at this point.
you forgot to write then on line 182
how can i allow for multiple jokers/consumables to be selected
the whoole calculate
increasing the area highlight limit with debugplus doesnt seem to work which i thought was the solution
its == not =
yeah, just screenshot it all
unless it's too big for that
ah
but also
what is face_cards here exactly
it should be
face_cards is not a value that does anything, it's a non-existent variable that was initialized before the code in the example given earlier
you would not replace that with '5' or anything, you need specific code for that (which is why i said to check walkie talkie)
okay nvm it just didnt work on already existing cards for some reason? though now how do i get this change to always apply when these areas are created
i think the time when i did joker that is called year 2012 which gives op amount of mult if rank 2, 10 or ace gets scored i did it like this.
not sure if its relevant but checking it like this is simpler for me.
you can patch them? i think that's what other mods do
Put it in a Game:start_run hook.
not sure how would i exactly create the scaling part.
i mean
luchador, diet cola, invisible joker
mine is kinda useless
it doesnt involve selling them. they just disappear if the scoring finishes
gonna be honest, im not sure what it could be
either eris was wrong ans its = instead of == (unlikely)
or it's just the fact that face_cards is a nonexistent variable
outside that, idk what it could be
if you want to check for cards with olny rank 5 cards i dont think face_cards is the right way to do it.
then how do i make it do rank 5 cards instead
context.other_card:get_id() == 5 then
im assuming thats what it should be.
i will also say, if you wanna just condense your code a little to make it look cleaner, you can do
if context.joker_main and context.other_card:get_id() == 5 then
instead of
if context.joker_main then
if context.other_card:get_id() == 5 then
I agree but also that code is wrong
there's no other_card in joker_main
that is a good point .w.
it should be individual like here
and cardarea == G.play
Honestly i need to make a code look cleaner because as of now it looks bad.
there is a single use joker i made that gives X2 mult for each scored card but i had no idea what i was doing
i think its also inefficient
i mean the code in the screenshot looks good to me
That one is a diffrent joker
im talking about this one
its supposed to give X2 mult for every played/scored card but due to my inefficency it kinda looks like im just getting way too many if statements to get all of the card ids
efficiency isnt really the problem, moreso readability
like, think of every indent as a step in a staircase, if you can have two statements on the same step, do it
yeah uhh if you want to do it for all you just... dont need to check rank
this will also not work with stone cards or modded ranks
somehow there is a missing code or something
if i try to delete the checks the game crashes.
i'll try to delete the checking part again just to be make sure
With what error message?
i havent screenshotted, i just assumed it needed that check for some reason
if context.individual and context.cardarea == G.play then
return { xmult = value }
end
that should be enough
you missed a comma somewhere
i would recommend brushing up on basic lua honestly
i've seen that exact error too many times in my own code
or added an = or whatever
or switch text editor to something like vscode
that is another possibility, doesnt happen as often tho lol
it is enough indeed.
now i gotta fix it in some other place since i recall re-using that same dumb check to all cards again.
this happens sometimes with my keyboard if i do a double = and i add an = extra or just copied and pasted my config into loc vars without removing the =
actually yknow what
@red flower question for ya
you're (dare i say) an expert with modding, do you ever still find yourself just forgetting a comma somewhere sometimes?
depends on what your definition of forgetting is because if i miss a comma i realize quite quickly because the editor tells me
that's why Oinite recommended switching to a good one
i'd say that still counts in my book lol
i'm just trying to make a point that it's not a stupid mistake to ocassionally make
idk i sometimes still miss my commas on vscode
granted everything in it updates slowly for me for some reason but eh
i realize quickly because the autoformatter doesn't work if there's any weird syntax error
even if it doesn't mark it immediately
vscode doesnt even tell me if i miss a comma, and if it does, i have never seen the indicator
im assuming you have the lua extension
sometimes i do wonder to myself
why i created certain jokers as they are. some doesnt look like it makes sense really.
well whatever, i fixed the issue with checks.
it works fine.
thanks for the help
i was about to tag Ali

<-- autistic early 1990's tech nerd
idk man, looks pretty cool if you ask me
its a set of jokers that are just windows
there is a specific booster pack for it, but there are other jokers that isnt windows so.
doesnt change the fact that it looks cool
There are some jokers that are windows but isnt necessary real
like windows cougar which is just cavendish but weaker
It looks cool, but i dont know if i ever get to release it.
Chances are i would need to get permission from some people before i can do a public release.
i was working on this mod together with my friends.
ah, yeah that is a shame :/
not to mention this mod is accidentally built on top of another one. which is why i said if i ever get to release it,
I think if i can sepreate my own files from the other mod. i think there is a chance but i still need to get permission from my friend
guess we'll wait and see then
windows jokers arent the only thing
like there is also flash game jokers in there as well
^
How do you make a function that lets you go to specific pages like the jokers added by your mod?
What's your code?
what do you want to make?
pika
here
When you click on "Grasslander Jokers", I want to trigger a function that brings up the jokers added by the mod.
Ik how to make functions trigger when clicking on text btw
you don't need to ping me every time 😭
You dont need to ping reply everytime
ah you just need to call the same function that the smods additions calls
give me 2 secs to find it
im sorry, i forget you can turn off the pin
mb bro
how i make it score now
ok i forgot its a bit more complicated. i think this should work
G.FUNCS.modprefix_your_collection_jokers = function(e)
G.ACTIVE_MOD_UI = SMODS.Mods["your mod id"]
G.FUNCS.your_collection_jokers(e)
end
then call that in the button
Thx
if context.joker_main then
return {
xmult = card.ability.extra.xmult
}
end
It brings me here, plus when I click on back it takes me to the collection menu instead of the challenges menu
On second thought, this might be a bit much to code in, nvm.
Thx tho
sorry 😭
but yeah the problem is that the normal collection and mod collection use the same function
You're all good 👍
but it checks if the mod has been selected in the smods menu
Got it
whats the best mod to play around with?
to skip blinds, add jokers, spawn specific blinds, etc
does your joker's config not have an extra table inside it?
debugplus
uhh i dont think so
thats what im looking at but some of the buttons like dont work
like [3] to spawn card
how does that work
ctrl + 3
No idea whats going on really.
without seeing how the code works. i cant tell if something is wrong
u hover the card
it should
your variables should be stored in config = { extra = {} } not just config
in collections
same for me but when i try to change rank or suit
press ctrl
hover over the card in collection
i dont think have vairables
ur an outsider!!!
and how do i spawn blinds?
you mean you dont have xmult or xmult_gain in your config?
i doint think so?
reroll manually or use debug++ to select a specific one
same thing
you can spawn in any game object from the collection
even though it just says cards
just send the code pls, i'll help you fix it
here?
that looks nothing like what i imagined.
what scares me is that there is no config = extra
im sayin
there is so many things wrong with it
it was easier for me to just create a new one entirely
calculate = function(self, card, context)
if context.individual and context.cardarea == G.play then
card.ability.extra.xmult = card.ability.extra.xmult + card.ability.extra.xmult_gain
end
if context.joker_main then
return{ xmult = card.ability.extra.xmult }
end
end
replace your calculate with this and correct the indents as necessary
and then under soul_pos, add this:
config = {
extra = {
xmult = --insert number here
xmult_gain = 0.5
}
}
you also dont need the in_pool function or pools variable
like at all
especially is it's just to instantly return true on what was already true
only time i needed to use pools variable is so make sure that booster packs works.
Working on a balatro card. Does this fit Balatro's artstyle or at least fit appearance wise
not quiteee
balatro cards are 71 pixels wide and 95 pixels tall
that seems a bit taller than that
Exact numbers ugh, thank you. I never could find out what specifically they were
are u british
u r 00:00, just like me
the fuck kinda Lee Oswald insta-clock are you pulling?? lmao
oh right, the clock in my bio .w.
what did go wrong this time?
you missed a comma, i assume in the config which is my own fault a bit lol
while yall are trying to figure out
i mean, im sorry i apologize i created this.
not going to be in final product
unless my friend says something about it.
wait ts peak
i meaaaannn
say what you will, it's funny as fuck
before you ask this scales properly but its kinda diffrent
you need to insert xmult in there.
just put a 1 in there
how would i get it to show the currently
you'd need a loc_vars funciton
you need loc_vars funcution
mine kinda looks like this.
oh, i didnt know you could return colours in a loc_vars o.o
comma
after the 1
-# you should also probably brush up on lua basics as was said before
my friend kinda did half of the work for the scaling joker, he kinda did loc_vars that way
i dont think its necessary unless its something i cant figure out
wtf
brb i gotta ask my friend
Are you properly closing the config table? It looks like you might be missing a }
Did you start a new run?
oh yeah, that is often a big problem too
Forwarding this here since it’s a dev event so if any devs wanna participate in something cool 👀
dont think i'll participate, i do terrible work under a time limit .w.
im still too new for these things, i odnt think i'll participate
is it like smallpox
how would i go about adding another slot for jokers, that specific jokers go into?
like mutiplater mod
Also it’s being organized by some pretty notable people beside myself, such as Eremel, Wilson, and Murphy
idk if vanillaremade is googleable but
also it needs a lot more logic depending of what you need it for
oh no im literally just putting custom jokers in it
for this do i just make a new file and put this code in it?
you can put it in any file that is loaded

