#💻・modding-dev
1 messages · Page 647 of 1
it almost works the way i intend, except that it multiplies wrong as it probably repeats the function
adn this is what happens when you combine freakshow, cryptid, and paperback
What is the goal?
to multiply the values of every joker in hand thats in a specific pool by 1.1X
if context.end_of_round and context.main_eval
omfg it was that simple of a fix thanks man
does context refer to the state the game is in?
think so
hm alright
i need to change that now that the smods docs are better
is there a way to have showman’s function affect a specific pool?
SMODS.showman? it gets the key for the object to be created so you can check its pool
I mean like do something like showman but for a specific pool, if that’s not what you already mean
yes
Alright I've been messing with this for about two hours now, and it feels like it should be working - I'm trying to reskin a base game joker, and have it animate
I'm declaring an SMODS.Atlas, declaring it as an atlas_table = 'ANIMATION_ATLAS', and using take_ownership with the atlas key, but it's just... not doing anything
I debated it, but since the newest beta for SMODS allows animation atlases to be declared so easily, it seems like it shouldn't be that nasty of a process anymore to animate it without?
no im not saying the animation is the problem
im saying taking ownership to replace the atlas is the problem
malverk solves that part
Oh
It's been working fine for the other jokers so far, the ones that aren't animated, I've got ~15 being overwritten
and im saying that idk if malverk accepts animations yet but probably it does
the pr that added animated atlas support might not have taken take ownership into consideration maybe
Balls, that's true
alright time to delve into the other possible option for getting this to work, in the style of the Aura mod (the other possible way without Malverk, that is. I'm... really not sure why I'm so adamant about this)
CORRECTION: IT'S WORKING
how can I make it ignore duplicates of cards in a specific pool
(G.P_CENTERS[card_key].pools or {}).pool_key
like this?
nostalgic pillar
ok apparently G.P_CENTER_POOLS.Joker still contains locked jokers, how would I go about checking which of them in that pool are unlocked or not, if I have to loop for it what would i need to check
G.P_CENTER_POOLS.Joker and check if u can have "unlocked = true" or something
you MIGHT have to use the current pool
would looping through them like v.config.center.unlocked == true work
uhhhhhh give it a spin idk
No, it would be if v.unlocked
oooh ok
oh right because its a key in the joker itself, not the config
errr
SMODS.Joker{
key = 'reunlockall',
atlas = 'crs_jokers',
rarity = 4,
cost = 20,
unlocked = true,
discovered = true,
blueprint_compat = true,
eternal_compat = true,
perishable_compat = true,
pos = {x = 0, y = 0},
config = {extra = {div = 50, retrig = 1}},
loc_vars = function(self, info_queue, card)
return { vars = { card.ability.extra.div, card.ability.extra.retrig} }
end,
update = function(self, card, dt)
if G.P_CENTER_POOLS.Joker then
local count = 0
for i, v in ipairs(G.P_CENTER_POOLS.Joker) do
if v.unlocked == true then
count = count + 1
end
end
card.ability.extra.retrig = (math.floor(count/card.ability.extra.div))
end
end,
calculate = function(self, card, context)
if context.repetition and context.cardarea == G.play then
return {
repetitions = card.ability.extra.retrig
}
end
end,
crs_credits = {
mod = "Re:Unlock All"
}
}
So like
wtf lol
How many of them is actually unlocked??
Isn't taht discovered?
Lol
how do i reference the balatro code for patches again 😅
Look in Mods/lovely/dump
is there a way to make every boss blind a specific one when a joker is held
Yes, hook get_new_boss
luasteam doesnt work as intended 😭
hi chat, quick question
is there a way to do something like this but for the soul sprite?
oh
thanks a lot
use card.children.floating_sprite
not my code, my entire code is just for regular legendary stuff
center is the card sprite itself afaik
im decently sure it is
didnt know about floating_sprite though
i dont usually work with legendaries
well that seemed to work
thanks a lot !!
np
how does the idol take a random card from the deck?
ah i see
<@&1133519078540185692>
Does anyone know if its possible to reference the in game joker atlas for a back? I've tried setting the atlas to 'Joker', 'Jokers', "Joker", "Jokers", "joker", "jokers", 'joker', and 'jokers" but the game crashed attempting to index field 'atlas' [a nil value]
atlas = 'Joker',
prefix_config = {atlas = false},
Thank you!
question
when changing the score requirement of the blind by G.GAME.blind.chips, how does it return to its original score post-hand and how do i prevent this
basically any modifications you do get overwritten by the hand scoring after calculation
i think you can use events to get around it
how
you can also wait for/copy this
https://github.com/Steamodded/smods/pull/1167
isnt G.GAME.blind.chips the blind requirement
not the current score
it might be the text thing
https://github.com/nh6574/VanillaRemade/wiki#how-do-i-change-the-blinds-requirement-in-the-middle-of-a-blind
This code does not as the tooltip describes. What must I do?
calculate = function(self, card, context)
if context.remove_playing_cards and context.other_card == card and ((#G.consumeables.cards + G.GAME.consumeable_buffer) < G.consumeables.config.card_limit) then
G.GAME.consumeable_buffer = G.GAME.consumeable_buffer + 1
G.E_MANAGER:add_event(Event({
trigger = 'before',
delay = 0.0,
func = function()
SMODS.add_card({ set = 'Spectral' })
G.GAME.consumeable_buffer = 0
return true
end
}))
return {
message = localize('k_plus_spectral'),
colour = G.C.SPECTRAL
}
end
end
context.remove_playing_cards doesn't have context.other_card, you would have to check if card is in context.removed
That worked perfectly!
card_added
rad, thanks!
is context.card:add_sticker("perishable", true) valid, or does Perishable use a different key?
should be
schweet
info_queue[#info_queue + 1] = SMODS.Stickers["perishable"]
why is this line crashing the game?
crashes at if not G.localization.descriptions[set][_c.key] then set = "Other" end in common_events
you cant do sticker tooltips like that
it has to be info_queue[#info_queue + 1] = { key = "perishable", set = "Other", vars = { G.GAME.perishable_rounds, G.GAME.perishable_rounds } }
ah, i see
idk about the vars since i think vanilla hardcodes a 5 for the total amount of rounds in the desc
What-
well yeah ive been sent this about 6 times but i dont work well on this website
i think it would have been better to start there then
what's the part you dont understand?
is there an explanation on how the soul card is rendered with the small animation sprite overlayed on it
wanna learn how to do that
setting a soul_pos attribute on an object will set that floating sprite
If you want custom animations for the floating sprite you will need a draw function
looking at the soul sprites is technically considered an enhancer
vanillaremade The Soul has code to see this
being in the same sprite sheet
annoying caveat: the soul sprite needs to be on the same atlas as the base card
vanilla soul doesn't do this but it uses thunk's spaghetti code instead
if u saw the mess i've made for this mod
it fits right in
just place holders for now
but the idea is it gives u super strong legendary twitch chat related jokers for doing stuff
one of the ideas is banning a user in chat for a 100x mult
rename the placeholder :Kappa: for now
I wonder if it's possible to use emotes as text
hi! I need help having a joker remember a specific playing card in hand after reloading, does anyone have an idea of how to go about that
trying to make a joker that adds x0.5 mult per polychrome card in deck
info_queue[#info_queue + 1] = G.P_CENTERS.e_polychrome
local poly_tally = 0
if G.playing_cards then
for _, playing_card in ipairs(G.playing_cards) do
if SMODS.has_edition(playing_card, 'e_polychrome') then poly_tally = poly_tally + 1 end
end
end
return { vars = { card.ability.extra.xmult, card.ability.extra.xmult * poly_tally, card.ability.extra.divine } }
end,
calculate = function(self, card, context)
if context.joker_main then
local poly_tally = 0
for _, playing_card in ipairs(G.playing_cards) do
if SMODS.has_edition(playing_card, 'e_polychrome') then poly_tally = poly_tally + 1 end
end
return {
Xmult = 1 + card.ability.extra.xmult * poly_tally,
}
end
in_pool = function(self, args)
for _, playing_card in ipairs(G.playing_cards or {}) do
if SMODS.has_edition(playing_card, 'e_polychrome') then
return true
end
end
return false
end```
it comes up with a weird "not defined" error
is SMODS.has_edition a thing?
it is not
it would be card.edition and card.edition.key == "e_polychrome" for the check
thankes
well the basics are there
just need to make it were the twitch soul doesn't appear so often
but with the lower joker pool already still has a high chance
is there away to fix the jimbo jokers that appear when the pool gets lower than what's available without having to stuff it with vanilla jokers
guys, im trying to figure out which card in a played hand was force selected but i cant figure it out 😭
if you created whatever is force selecting the card, you can just also have it set card.ability.something = true and then check for if card.ability.something is true when you need to see which one was force selected
o
makes sense, thank you
does that save when reloading though? or should i run save_run()
game autosaves every 10 seconds and whenever you do most things like adding a modification to a card (although if it's a type of modification you implemented yourself, you might need to still manually add it)
kk
is that modification permanent or only for the hand? because id probably have to remember to remove it if its the former
yea you have to remove it afterwards
kk
i was today years old when i realised that all localisation texts ending with _ex end with exclamation marks too
k_upgrade_ex is short for k_upgrade_exclamation_mark
still not sure what the k means though :3
is there a context for a played hand after all cards are scored btw? or would i just manually loop with joker_main
koolio obviousl-
context.after?
thanks :)
ok so this is my situation
-# red = reality, blue = expected
-# x = time, y = blind score requirement
-# im deducting the blind score but it comes back
send the code that does it
I tried assigning a weight didn't work either
I guess I should just keep it a spectral

calculate = function(self, card, context)
if context.cardarea == G.jokers and context.joker_main then
return {
func = function()
if G.GAME.blind.in_blind then
local amount = pseudorandom('RANGE:50|100', 50, 100)
G.E_MANAGER:add_event(Event({
trigger = 'after',
delay = 0,
func = function()
card_eval_status_text(
context.blueprint_card or card,
'extra',
nil, nil, nil,
{ message = "-"..tostring(amount).." Blind Size", colour = G.C.GREEN }
)
G.GAME.blind.chips = G.GAME.blind.chips - amount
return true
end
}))
return true
end
end
}
end
end
wait hang on maybe because i also have blindside installed
lol
soul_rate
doesn't work
soul_rate = 0.003, determines how likely this legendary is to replace each card in a pack
It appears at same odds as everything else
soul_rate only works if hidden is true
damn maybe if I could read it would have saw it says that a few sentences up on the wiki

thx man
That should do it
soul rate works now
Just shame doesn't work on jokers
wanted it to be in the booster with all twitch related stuff
not sure i can get it a shot
I just realized I put it in the wrong booster set

been testing for 15mins in the wrong boosters
either i'm just incredibly unlucky with 60 pulls in a row
or it's not working
yeah about to
yeah that looks like its it
changed to 1
now one spawns every pack
Aweeome
I guess now just finding the sweat spot
for spawn rate
key = "ttv_ttv_twitch_jokers",
cards = {
["j_ttv_f"] = true,
["j_ttv_copycat"] = true,
["j_ttv_donation"] = true,
["c_ttv_kappsoul"] = true
},
})```
also
should I have it in the pool
or is it not necessary
with the soul_set
With soul_set it isnt needed
incredibly basic question but how do you make tarot-like cards be the right size again
i forgor
I'm planning on making mod that requires states. Where a state is just information of what the user currently has. Like the number of hands, what jokers, how much money, etc. I also want one of the states to be a "sub state". Where it tells me where the user is in the game. Such as: selecting a blind, in the shop, playing a round etc. I wanted to know if anyone had a full lists of these "sub states" since I know certain jokers, like Perkeo, or Golden Joker trigger during specific states
also G.STATE tracks something like that too
alright man, don't gotta be like that. I was just asking a question
To expand on the other two replies some things in the game are saved in G.STATE (in the shop, in a booster, selecting a hand, using a tarot) basically when there's some state machine kind of thing that the entire game needs to know it's under. Some others are given as a context to the calculate_joker function (or other calculate functions in smods), these are signals for actions such as skipping a booster, rerolling the shop, ending a blind, scoring steps, etc.
bump
hey why wont my config menu show up
--Typ0.lua
local config = SMODS.current_mod.config
SMODS.Sound({
key = "music_typ0_me",
path = "music_me.wav",
volume = 0.6,
pitch = 1,
select_music_track = function()
if config.typ0_pack_music ~= true then
return nil
end
if G.STATE == G.STATES.SMODS_BOOSTER_OPENED then
local pack_cards = G.pack_cards and G.pack_cards.cards
if pack_cards and #pack_cards > 0 then
local first_card_mod = pack_cards[1].config.center.mod
if first_card_mod and first_card_mod.id == "Typ0" then
return 1
end
end
end
return nil
end,
})```
--config.lua
return {
typ0_pack_music = true,
}```
there both in my root folder
Code?
this is the newest code introduced which is when crashes started (just verified the game works fine without this code)
ah i didnt see that part i was just looking here https://github.com/Steamodded/smods/wiki/The-Mod-Object#mod-config
You're not inputting self into the old function.
ohhhh
that makes a lot of sense yea
i saved it as . and nort :
this shouldnt matter for prep_draw hook at the bottom right?
that never takes self
No, it should still be . you just need to input self as the first input into sprite_draw_shader
yes
i mean that like
with . you need self
Yes.
ofc, if i saved a var as : it doesnt make sense
tyy
new issue
notice i print hi..tagvar at the top
my console is showin tagvar as nil
in my sticker i have this code
(notice how i add true, true at the end there)
so it should make my two extra variables in my hook true
but i seem to be mistaken
@rocky plaza
Do you have a global table for your mod?
i do yes
Do you have the game update function hooked at some point in your mod?
yes
holy fucking shit
In your game update hook add
if G.STEAM and not Tangents.user_steam_id then
Tangents.user_steam_id = G.STEAM.user.getSteamID()
end
where Tangents can be replaced by the actual name of your global mod table
then to check, run
eval Tangents.user_steam_id
in debug+
sure
anyways i gotta go
see ya thunder
gonna bump this since it got pushed up
but i think i have some misunderstanding of how to utilize hooks
TLDR: i made a hook and am calling the function in my code with additional custom arguments but it seems to be nil every time
what is this trying to do
ok
ok
so i have a sticker sprite i made that is double the normal size of a sticker sprite
as a result it renders incorrectly
(i added a green border to visualize it better)
i made a bunch of hooks to try and make it so if the game draws my sticker it does it with an offset
its scaled down to the size of a regular sticker btw
have you tried the values the function already has for scale and offset
im assuming so
yea
tbh, im working with old code here
i solved this exact issue before but lost the changes and that was months ago and i picked up the project again
so im just like retracing my steps
based on images i sent here in the past
rn i think i have the exact or basically the same hooks and stuff i did earlier to fix it
but right now, it seems like this additional variable im adding is just always nil
have you tried instead of adding new arguments to pass them through a global
-- outside everything, because making random globals is not good practice
YourModTable = {}
draw = function(...)
YourModTable.tagVar = value
sprite:draw_sprite(...)
YourModTable.tagVar = nil
end
then you would check YourModTable.tagVar in the hook
bump
(G.P_CENTERS[card_key].pools or {}).EveryImasJoker
ah smart
btw, defining yourModTable anywhere in my file lets me access it right?
oh it has to load before the hook
which
well yea that makes sense ofc lol
this is the main.lua file i have
most functions will run after it loads so its fine
i think i can repurpose UTM
yeah thats what that should be for
great
ill try that
this also actually works far far better
because right now im patching 2 other functions
to get the variable where it actually needs to make a chane
while not as clean its usually better than adding new arguments because it will conflict with other hooks and patches
ye, its not bad either
its not so spaghetti its hard to understand at least
close enough
lmfao
it works, cheers
idk if I did it well but I want my card to not being able to be debuff and after when the card is played it remove debuff from card that are debuff in the played hand and if its held its the same thing its removing debuff from held in hand card
is this a joker
no an enhancement
hmm yeah thats hard
return remove_debuff doesnt exist
I tried this some month ago but wasnt able to do it with the skill I was having a this time
you want all cards to be undebuffed when you play it?
kinda
imagine you play the card with the enhancement, every card that you played with it get their debuff remove
and if its held in hand all cards in hand?
for those two effects I would do a check in the global mod calculate to see if you have any in play or hand and then in context.debuff_card you wopuld return { prevent_debuff = true } for all cards in that area
for the card itself i would probably use SMODS.debuff_card(card, 'prevent_debuff', "source string") on it when the ability changes, i think theres a context for it you can use in global mod calculate too
but you would need to remove it once its unenhanced
or rather, you can probably do the prevent_debuff in set_ability and remove it in mod calculate
I want to make a function that gets triggered after every event. Do I need to override each function in order to inject my function, or is there a more simple way to do this?
im not sure how to do it, like idk what you meant in return prevent_debuff in context.debuff_card
why isnt it toggeling my music
you know how to give mult in a joker you return mult = number in context.joker_main
yeah obviously but like how is it going to target each card
have you used context.individual
no i mean
debuff_card works like individual
you shouldnt use individual here
like so
How do I count the chip total of a hand and have a joker add it back to a later hand?
it doesnt have cardarea sadly, you need to check context.debuff_card.area
also e_w_held will not be kept between contexts
(hello?)
nope
cause its not doing the thing at the start like it will remove only when a card is played
nono I want it to not remove the debuff at start
yes my solution wouldnt work then
yeah
but do you have an idea that could make this enhancement strong
like its the upgraded version of the wild card
bump (ping if anwser)
so now its
local ante = G.GAME.round_resets.ante
local sign = 1
if ante % 2 == 0 then
sign = -1
end
if (G.GAME.chips - G.GAME.blind.chips) * sign >= 0...
chip total as in the final score that the played hand is worth?
i should have an answer for you no matter what but i do need clarification on that
bump
First hand's final score added to last hand's chips
in context.after, SMODS.calculate_round_score() should get you the final score of the current hand. (running it in an earlier context will get the score at the moment of that calculation, not accounting for jokers to the right/anything scored in later contexts). just save that as a value to the joker, and give it on the last hand
to make sure you only do it on the first hand, delete the value in the joker during the last hand (set it to nil), and then only save the value if it doesn't exist yet
so, if context.after then
Smods.calculate_round_score()
end
yes?
not quite lol
like i said, you have to save it as a value in the joker's ability table
(i'm not gonna write all the code for you immediately, i'd like to encourage you to take a crack at it yourself first)
key = "breadclip",
atlas = "My_Way_and_The_Highway",
rarity = 2,
pos = { x = 3, y = 3 },
cost = 6,
blueprint_compat = false,
config = { extra = { bag_of_chips = 0 } },
loc_vars = function(self, info_queue, card)
return { vars = card.ability.extra.chips }
end,
calculate = function(self, card, context)
if G.GAME.current_round.hands_played == 0 and context.after then
return {
card.ability.extra.bag_of_chips == SMODS.calculate_round_score()
}
end
if G.GAME.current_round.hands_left == 0 and context.final_scoring_step then
return {
chips = card.ability.extra.bag_of_chips
}
end
end
}```
This is probably off somewhere
the first return in your calculate shouldn't be a return at all, just card.ability.extra.bag_of_chips = SMODS.calculate_round_score()
otherwise that should be good, yea
worth noting that if you're in a situation where the player only has one hand (e.g. needle), then it'll give the stored score from the previous round, but i'm not sure how to handle that cleanly
thank you
Anyway, now to code more cursed cards
SMODS.Joker {
key = "sandwich",
atlas = "My_Way_and_The_Highway",
rarity = 1,
pos = { x = 3, y = 3 },
cost = 2,
blueprint_compat = false,
config = { extra = { mult = 4 } },
loc_vars = function(self, info_queue, card)
return { vars = card.ability.extra.mult }
end,
calculate = function(self, card, context)
if context.joker_main then
for i = 1, #G.jokers.cards do
if G.jokers.cards[i].key == 'lhc' then
SMODS.add_card { key = 'c_xiferp_bolognium' }
end
end
end
if context.individual and context.cardarea == G.play and context.other_card == context.scoring_hand[#context.scoring_hand] and context.other_card:get_id(full_hand[1]) == context.other_card:get_id(full_hand[#context.full_hand]) then
return {
mult = card.ability.extra.mult
}
end
end
}```
Like this beast, who's supposed to spit off +4 mult if hand is a sandwich
is it even close to rightly coded for that?
how do i add a sticker to a playing card with debugplus
ive done some more trying and switched to this
SMODS.Sound({
key = "music_typ0_me",
path = "music_me.wav",
pitch = 1,
volume = 0.6,
select_music_track = function()
local mod = SMODS.current_mod
local config = mod and mod.config
if not config or not config.typ0_pack_music then
return nil
end
if G.STATE == G.STATES.SMODS_BOOSTER_OPENED then
local card = G.pack_cards and G.pack_cards.cards and G.pack_cards.cards[1]
local card_mod_id = card
and card.config
and card.config.center
and card.config.center.mod
and card.config.center.mod.id
if card_mod_id == "Typ0" then
return 1 -- positive number = play this track
end
end
return nil
end,
})```
its still not working
the goal is to make it only play the music while the config is true
Is there a way to make it so joker slots arent modified by the modify_joker_value function somethingcom made?
nvm fixed
SMODS.Joker {
key = "chance_card",
atlas = "My_Way_and_The_Highway",
blueprint_compat = false,
rarity = 2,
cost = 7,
pos = { x = 3, y = 3 },
config = { extra = { mult = -4 }, },
loc_vars = function(self, info_queue, card)
return { vars = { card.ability.extra.mult } }
end,
calculate = function(self, card, context)
if context.before then
if G.jokers.config.card_limit >= 5 then
G.jokers.config.card_limit = G.jokers.config.card_limit + 1
end
return {
mult = card.ability.extra.mult
}
end
end
}```
Got another issue: Uh... I'm pretty sure this will add an extra joker slot, bbut it will keep adding them
what are u trying to do
subtract four mult and add one joker slot when the card is held
see above
if context.after and context.cardarea == G.play then
-- Loop through the scoring hand.
for index, otherCard in ipairs(context.scoring_hand) do
-- If we found our card, continue.
if card == otherCard then
-- If the next card exists, continue.
if (index + 1) >= #context.scoring_hand then
index = 0
end
-- Apparently, calculate functions process before animations finish.
-- So to make the change of the sticker line up with the message, we had to use an event
-- (The event is added at the end of an event queue, which means this will run after animations ig)
G.E_MANAGER:add_event(Event({
func = function()
-- Apply the sticker to the next card.
SMODS.Stickers[self.key]:apply(context.scoring_hand[index + 1], true);
-- Remove the sticker from the current card.
SMODS.Stickers[self.key]:apply(card, false);
return true
end
}))
-- Return the message to display when the sticker is applied.
return {
message = 'Tagged!',
message_card = context.scoring_hand[index + 1],
colour = G.C.RED,
}
end
end
end
this is code for a sticker, it is meant to move itself to the card on the right after scoring
it works fine, but i noticed that if there are only 2 cards in the hand and the left card has the sticker, instead of displaying tagged on the right card and moving over, it displays tagged on the left card and removes itself
and im not going to lie, i dont see in the code where any kind of logic would lead to that happening
wait
im actually stupid
i figured it out
i think
if (index + 1) >= #context.scoring_hand then
index = 0
end
i assume its this
but also idk why its resetting to index = 0
I'm trying to set up hooks based off the vanilla wiki Am I only allowed to make hooks with vanilla functions? Did I mess anything up with the other files like the json or main one? Everything is in the root directory, no folders. I also had it before where hooks was not a file, and everything in there was in the main file
//a.json
{
"id": "DeepLearning",
"name": "Deep Learning",
"display_name": "Deep Learning",
"author": ["Hawker"],
"description": "Debug Mod to help with Deep Learning",
"prefix": "dp",
"main_file": "main.lua",
"version": "0.1.0",
"dependencies": ["Steamodded (>=1.0.0~BETA-1221a)"]
}
--hooks.lua
local win_game_ref = G.FUNCS.win_game
function win_game()
-- Do something before the original code
print("win game before")
local ret = win_game_ref
-- Do something after the original code
print("win game after")
return ret
end
--main.lua
--- STEAMODDED HEADER
--- MOD_NAME: Deep Learning
--- MOD_ID: DeepLearning
--- MOD_AUTHOR: [Hawker]
--- MOD_DESCRIPTION: Debug Mod to help with Deep Learning
----------------------------------------------
------------MOD CODE -------------------------
----------------------------------------------
------------MOD CODE END----------------------
iirc, if your mod loads after another mod, AND you are modifying a function that is defined specifically by that mod, you can hook into it as if it was a vanilla function
but i might be wrong
eg cryptid made a function called xyz_function(arg1, arg2, etc) and you loaded after cryptid
you can just hook it like you would normally
i think
so i should probably make it so my mod loads first
yea u can
your mod has to be a higher priority number tho (load after)
thats literally what youre doing for a lot of vanilla functions anyway since SMODS hooks a lot
wait why
yea i did some print debugging
if i have a pair as my played hand with this sticker on the left card
it somehow triggers the loop around failsafe
or afterwards(?) I think I misread what you meant
yea it needs to be after
cause hooking into a function that doesnt exist will cause problems
wait im stupid
problems like crash
bump
Are you possibly missing a return true statement after G.jokers.config.card_limit = G.jokers.config.card_limit + 1?
I've yet to actually test it, I have a vibe it will just keep adding them
You could be correct. ¯_(ツ)_/¯
will ping if breaks
So I changed the following: made the priority a large number making sure my mod is loaded last. Used debug prints to verify the line would appear in the log (I am using debug plus, so it should work), but nothing changes :(. No logs when I win a run. Sucks bc I got this working a few months ago with a different function, but that was with vanilla
//a.json
{
"id": "HawkerDeepLearning",
"name": "Deep Learning",
"display_name": "Deep Learning",
"author": ["Hawker"],
"description": "Debug Mod to help with Deep Learning",
"prefix": "hdl",
"priority": 100,
"main_file": "main.lua",
"version": "0.1.0",
"dependencies": ["Steamodded (>=1.0.0~BETA-1221a)"]
}
--hooks.lua
local win_game_ref = G.FUNCS.win_game
function win_game()
-- Do something before the original code
print("win game before")
sendDebugMessage("win game before", "MyDebugLogger")
local ret = win_game_ref
-- Do something after the original code
sendDebugMessage("win game after", "MyDebugLogger")
return ret
end
quick question, how would one implement a non-standard texture size blind? it looks fine outside of blinds (minus the weird transparency box, dont know whats up with that but in gameplay it looks entirely wrong - i'm looking for a dependencyless solution, so please don't direct me to API mods
might be smods goofing off.
in SMODS.Blind:set_blind and a Blind:load hook, reset the atlas for the blind
G.GAME.blind.children.animatedSprite.scale = {x = 512, y = 512}
G.GAME.blind.children.animatedSprite.scale_mag = 512/1.5
G.GAME.blind.children.animatedSprite:reset()
use the smaller value of x and y for scale_mag
and in the SMODS.Blind:defeat function, reset it
G.GAME.blind.children.animatedSprite.scale = {x = 34, y = 34}
G.GAME.blind.children.animatedSprite.scale_mag = 34/1.5
G.GAME.blind.children.animatedSprite:reset()
Are you loading hooks.lua? Also it should be win_game not G.FUNCS.win_game.
I forgor how to load hooks. How do I do that? 🧍🏾♂️
not anything specific, just "is your mod actually loading the file hooks.lua"
Pressuambly not since the function debug lines are not being printed
my main file is main.lua if that's what you're asking
yea, the game will only auto-load your main file and a config.lua file. you need to manually load all other files from your main file
https://github.com/Steamodded/smods/wiki/Utility
got it thanks
does this mean all functions, even if they are vanilla, should not have G.FUNCS.?
oh! thank you so much
np jane balatrostuck
any idea what the semitransparent box might be caused by?
there are some vanilla functions that do have a G.FUNCS., but win_game is not one of them
and yea generally you shouldn't be adding your own stuff to G.FUNCS unless it's for a function that runs upon clicking a button
how do you make something link to an info_queue for a non existent object
like just explaining what a term in the joker says
i mean i know it could just be referring to a localization entry but i dont know the exact table youre supposed to put it in
So how come this hook causes a softlock when all I said was print something before and after the original function? The lines do print which is a good thing, though at what cost
local end_round_ref = end_round
function end_round()
-- Do something before the original code
print("end round before")
local ret = end_round_ref
-- Do something after the original code
print("end round after")
return ret
end
It should be local ret = end_round_ref()
how come i didn't have to do that here?
Also, invoking the function causes the function to trigger twice.
-- hooks.lua
local win_game_ref = win_game
function win_game()
-- Do something before the original code
print("win game before")
local ret = win_game_ref
-- Do something after the original code
print("win game after")
return ret
end
local end_round_ref = end_round
function end_round()
-- Do something before the original code
print("end round before")
local ret = end_round_ref()
-- Do something after the original code
print("end round after")
return ret
end
im guessing jank with your files
So looking back at this, it seems that there are two intances of my mod. Or at at least that is what I am assuming since when I load up the game , there are two of the same Deep Learning mod loaded log. Even though my main file only says it once
INFO - [G] Deep Learning mod loaded
INFO - [G] 2026-01-18 23:41:48 :: WARN :: DeckSkin :: Old DeckSkin formatting detected on DeckSkin LPB_hearts_skin!
INFO - [G] 2026-01-18 23:41:48 :: WARN :: DeckSkin :: Old DeckSkin formatting detected on DeckSkin LPB_spades_skin!
INFO - [G] 2026-01-18 23:41:48 :: WARN :: DeckSkin :: Old DeckSkin formatting detected on DeckSkin LPB_clubs_skin!
INFO - [G] 2026-01-18 23:41:48 :: WARN :: DeckSkin :: Old DeckSkin formatting detected on DeckSkin LPB_diamonds_skin!
INFO - [G] Deep Learning mod loaded
-- main.lua
--- STEAMODDED HEADER
--- MOD_NAME: Deep Learning
--- MOD_ID: DeepLearning
--- MOD_AUTHOR: [Hawker]
--- MOD_DESCRIPTION: Debug Mod to help with Deep Learning
----------------------------------------------
------------MOD CODE -------------------------
print("Deep Learning mod loaded")
assert(SMODS.load_file('hooks.lua'))()
----------------------------------------------
------------MOD CODE END----------------------
how do i reset cards affected with set ability
Yes, remove the header.
for i, v in G.P_CENTERS do
gave me a attempt to call table value in reset game globals
for k, v in pairs(G.P_CENTERS) do
i already realised but actual jumpscare
bump
How did I mess up this function? I assume the logs I have should appear right when I start a blind considering I have a full deck
-- original function
G.FUNCS.draw_from_deck_to_hand = function(e)
if not (G.STATE == G.STATES.TAROT_PACK or G.STATE == G.STATES.SPECTRAL_PACK) and
G.hand.config.card_limit <= 0 and #G.hand.cards == 0 then
G.STATE = G.STATES.GAME_OVER; G.STATE_COMPLETE = false
return true
end
local hand_space = e or math.min(#G.deck.cards, G.hand.config.card_limit - #G.hand.cards)
if G.GAME.blind.name == 'The Serpent' and
not G.GAME.blind.disabled and
(G.GAME.current_round.hands_played > 0 or
G.GAME.current_round.discards_used > 0) then
hand_space = math.min(#G.deck.cards, 3)
end
delay(0.3)
for i=1, hand_space do --draw cards from deckL
if G.STATE == G.STATES.TAROT_PACK or G.STATE == G.STATES.SPECTRAL_PACK then
draw_card(G.deck,G.hand, i*100/hand_space,'up', true)
else
draw_card(G.deck,G.hand, i*100/hand_space,'up', true)
end
end
end
--hook.lua
local draw_from_deck_to_hand_ref = G.FUNCS.draw_from_deck_to_hand
function draw_from_deck_to_hand(e)
-- Do something before the original code
print("draw_from_deck_to_hand before")
local ret = draw_from_deck_to_hand_ref(e)
-- Do something after the original code
print("draw_from_deck_to_hand after")
return ret
end
Yes, it should be function G.FUNCS.draw_from_deck_to_hand not function draw_from_deck_to_hand
oh
why doesnt this do my xmult 😭
this is copy pasted from an identical file where the only difference is the other one gives mult
wait im an idiot
disregard everything i said, i didnt capitalize xMult in my extra.xmult part
bump
Is TYP0_CONFIG equal to SMODS.current_mod.config?
yes
if you look at the original post then my config code is visible. if it would be convienent to have that in text form i can paste it here.
and now i cant even view the collection without crashing.
``` and a attempt to index field extra
this shit is gonna make me switch to vigil 😭
WHAT DOES IT WANT ME TO DO
I THINK I MIGHT BE LOSING MY HEAD
i mean all vscode wants is for you to make sure 'other' exists, but if you know it'll always be smth that has a [1] you're fine to ignore it
also other[1] == nil can probably be written as not next(other) and it'd do the same thing but without the warning maybe?
-# don't quote me on that
It should be card.ability not card.config
this thi ng just ends up killing you immedietely as soon as you play a hand
bypassing everything ive set specifically to limit it
atr im pretty sure this obelisk got rabies.. that or i should just scrap this entirely
nvm it works
is there away to remove the sell option from a joker
Need to replace it with something
I might be brainfarting but wouldn't defining the defuse button as self.children.use_button in your Card:highlight hook remove the sell button?
I'll give it a shot
Right now in bed
Spent all night working on the mod
Can't wait to finish it for two ppl to play it and tell me it sucks

love to see the next "vanilla but its better because i made it bigger" joker
No.
yo can yall go over my code? its crashing and idk why lol
It should be m_steel and m_gold not Steel and Golden
ty o7
okay
i was confused cause it said it took string values
is blinds mentioned like this blind.small, blind.big and blind.boss or is it something else cause i make a madness but only trigger at boss blind
No, only blind.boss exists.
so i cant make a madness only trigger at boss blind only
yes check blind.boss
there's also no reason you can't just take madness and add a not to invert the condition
bump
i think it would be better to put all information in one message rather than make people jump through a reply chain lol
ok i will
SMODS.Sound({
key = "music_typ0_me",
path = "music_me.wav",
pitch = 1,
volume = 0.6,
select_music_track = function()
-- Get the latest config every time
local mod = SMODS.current_mod
local config = mod and mod.config
if not config or not config.typ0_pack_music then
return nil
end
if G.STATE == G.STATES.SMODS_BOOSTER_OPENED then
local card = G.pack_cards and G.pack_cards.cards and G.pack_cards.cards[1]
local card_mod_id = card
and card.config
and card.config.center
and card.config.center.mod
and card.config.center.mod.id
if card_mod_id == "Typ0" then
return 1
end
end
return nil
end,
})```
TYP0_CONFIG = SMODS.current_mod.config
if TYP0_CONFIG.typ0_pack_music == nil then
TYP0_CONFIG.typ0_pack_music = true
end
SMODS.current_mod.config_tab = function()
return {
n = G.UIT.ROOT,
config = { align = "cm", padding = 0.05, emboss = 0.05, r = 0.1, colour = G.C.BLACK },
nodes = {
{
n = G.UIT.R,
config = { align = "cm", minh = 1 },
nodes = {
{
n = G.UIT.T,
config = { text = "Typ0'S Random Jokers", colour = G.C.RED, scale = 0.5 }
}
}
},
{
n = G.UIT.R,
nodes = {
{
n = G.UIT.C,
nodes = {
create_toggle {
label = "Enable Pack Music",
ref_table = TYP0_CONFIG,
ref_value = "typ0_pack_music"
},
}
}
}
}
}
}
end```
my goal is to make it so that the music only plays inside my booster packs when the config is on.
and ive tried a fair few things to make it work
but i cant seem too
have you added prints to see if it enters any of the conditions
also have you tried returning a number bigger than 1
The select music track will always return nil if I’m not mistaken, you can’t access SMODS.current_mod after the game has loaded
yeah thats what i just discovered
what should i use instead of current_mod?
You need to store the current mod outside of the objet
People normally do modname = SMODS.current_mod at the top of their main file
Hello I have a quick question, does anybody happen to know where the default joker's calculation function is stored? I'm trying to call a random base game joker within a mod I'm working on.
Thank you in advanced, and I hope you all have a great day!
Calling calculate functions from cards you don’t actually have is a lot more advanced than where the function is stored, they use a lot of internal values and functions that are stored within card objects themselves
i'd like my sticker label to fade between three colours. how can i do that?
👍 Ok I shall rethink how this joker works then.
It’s not impossible though, I’ve implemented it a couple of different ways in the past!
I'm looking into card.lua rn.
i gotta tap into this
Hello! I have a quick question about modifying values for cards, I'm wanting to try and change some of the econ jokers' given cash but I can't seem to find a universal way to do it. Is there any? I'm changing scoring jokers' values in the Card.calculate_joker method. Thank you to anyone who can help!
u think its possible to make a booster/consumable in the shop where if u open it you get a custom ui instead of having to pick a card
yes
for the consumable using the use function to open the ui is enough for boosters i think you would need to hook some things
are you making a public mod or is this for yourself
Probably just for myself and my friends
i would recommend checking this out anyway, it makes it easier to modify jokers
https://github.com/Steamodded/smods/wiki/API-Documentation#taking-ownership
there's also a table in card.lua that has all the default joker values
So I do have to hardcode it in for every joker?
what do you want to do exactly?
sadly most of the values are in different places with different names
I have a custom stat stored in card.ability which I want to universally change the money given
money given by jokers or any money obtained
Given by jokers
well some of them are in calculate_joker and others in calculate_dollar_bonus, you can change them there
the proper way would probably be to use context.post_trigger to change returned dollar values and hook calculate_dollar_bonus for the end of round ones
if you want to support all modded jokers
O_o
you could also hook SMODS.calculate_individual_effect for returned dollars
Alright, I'll try these. Thank you!
I get a nil value with whatever I put
but this seems like the direction
return {
mult = card.ability.extra.mult
}
end```
Okay, I played a flush, and this activated on EVERY card
Flush didn't even have a pair
Card.get_id doesnt take any arguments outside of self, so youre essentially checking context.other_card:get_id() == context.other_card:get_id()
not sure what exactly the intended effect is here but i assume you want to check if context.other_card is the first or last card at least
if first card and last card are =
any tricks to make that happen?
so if context.full_hand[1]:get_id() == context.full_hand[#context.full_hand]:get_id()
and also check if context.other_card is either of those cards
oh. I got them backwards, thanks!
Okay, it didn't activate at all
if context.individual and context.cardarea == G.play and context.full_hand[#context.full_hand] == true and context.full_hand[1]:get_id() == context.full_hand[#context.full_hand]:get_id() then
yeah because context.full_hand[#context.full_hand] isnt going to equal true
idk what the idea there is
Is context.other_card == #context.full_hand any better?
i assume you mean context.other_card == context.full_hand[#context.full_hand]
yes
yeah that works
Also, in the same card is
for i = 1, #G.jokers.cards do
if G.jokers.cards[i].key == 'lhc' then
SMODS.add_card { key = 'c_xiferp_bolognium' }
end
end
end```
G.jokers.cards[i].config.center.key
(adds a specific consumable if another joker is held)
Besides the one joker I'm checking for
no
why?
gotcha
just out of curiosity, how feasible would it be to make a deck that adds chips and mult together on the final scoring step instead of multiplying them together? I would be nerfing the blind scaling heavily so it would maybe be possible to beat
should be very simple
just SMODS.set_scoring_calculation("add") iirc
for the deck apply
oh is it already just a default setting? oops
its pretty recent but yeah
alright I'll check it out, thanks for pointing me in the right direction
Also, couldn't figure out how to code a card with xmult multing itself
like x2x2x2x2x2 and so on
if context.before then
return {
xmult = card.ability.extra.mult
},
card.ability.extra.mult == card.ability.extra.mult * 1.1
end
end```
so the code looks like this
firstly
you cant run code after returning
second, you shouldnt have a comma after the return
third, it should be = and not ==
anything else?
no
actually
yes
you cant do scoring in context.before because it gets reset after, you should use context.initial_scoring_step
How do I display the running multiplier?
what
this is basic localization usage
have you considered learning basic lua ?
kid named loc_vars
I'm getting a crash whenever I try to start a game with the deck, here's my code in case I did something stupid:
key = "preschooldeck",
atlas = "badlatroenhancements",
pos = {x = 5, y = 0},
config = { ante_scaling = 0.1 },
loc_txt = {
name = "Preschool Deck",
text = {
"{C:blue}Chips{} and {C:red}Mult{} are added",
"together instead of multiplied",
"{C:red}X#1#{} base Blind size"
}
},
loc_vars = function(self, info_queue, back)
return { vars = { self.config.ante_scaling } }
end,
apply = function(self)
SMODS.set_scoring_calculation("add")
end
}```
I also tried updating Steamodded and nothing changed
it does need an event, yeah
yeah that seems to have worked, thank you again
now to see if this is actually viable to play lmao
the apply function overrides the default i think
so youll need to do G.GAME.starting_params.ante_scaling = self.config.ante_scaling manually in the apply
I tried changing the blind scaling with loc_vars and it seems to work fine?
that's not true
loc_vars will run a lot so that definitely isnt a good idea
'Currently {X:mult,C:white} X#4# {} Mult',```
Not working right...
(joker code for context)
```SMODS.Joker {
key = "pex_card",
atlas = "My_Way_and_The_Highway",
blueprint_compat = true,
rarity = 2,
cost = 7,
pos = { x = 3, y = 2 },
config = { extra = { xmult = 1 }, },
loc_vars = function(self, info_queue, card)
return { vars = { card.ability.extra.xmult } }
end,
calculate = function(self, card, context)
if context.joker_main then
xmult = card.ability.extra.xmult
card.ability.extra.xmult = card.ability.extra.xmult * 1.1
end
end
}```
you should actually return the xmult
or SMODS.calculate_effect the xmult
if you need the mult increase to go after
also youre using #4# in the description when the mult is variable 1 in loc_vars
fill in "xmult" wherever eris said just "mult"
the point is the position of the value
I am working on just getting familiarize with the code. I started yesterday in which all I did was make a hook script that logged the other scripts. It was working fine yesterday, but now, I cannot open the game. lovely opens for a bit, and then closes. What did I do wrong? Verifying integriy of files does not do anything
-- hooks.lua
local win_game_ref = win_game
function win_game()
-- Do something before the original code
print("win game before")
local ret = win_game_ref()
-- Do something after the original code
print("win game after")
return ret
end
-- imagine fucntions like this for: end_round, new_round, draw_from_deck_to_hand, discard_cards_from_highlighted, play_cards_from_highlighted, and evaluate_play_ref
What did I do wrong I am pretty new to modding
https://github.com/nh6574/VanillaRemade/tree/main/src also use this as a reference if you need one since i get the idea that whatever it is youre using is at least a bit outdated
Im using the source code
yea don't use any vanilla balatro code as reference, it's not an accurate reflection of how to mod the game
vanillaremade remakes all the vanilla content as if it was modded content
yeah balatro source code is quite different from mod code (and is pretty janky in some places because thunk)
ok
At least its an error I have never seen before
this is because you dont have any context checks which makes your card calculate probablities inside the contexts that calculate probability which makes an infinite loop
also loc_vars is inside calculate for some reason
i'm not exactly sure what's up here
i don't have amulet so should i just turn off talisman in general
i'd download amulet but it's 11pm and i just wanna make sure the joker works before i go to bed
yeah
what do I need to change
how do i make a deck that adds +1 booster slot
ok it works when talisman isn't losing it's shit cool
i'll code a talisman fix tomorrow for now i need to eepy
yeah
But booster
no reason to, just make players use amulet
i would rather make sure the mod is usable no matter what other mods you like to play with so it does kinda matter to me
amulet is literally a talisman replacement
like it's the same mod but without the crash
How do I fix that infinite loop problem
talisman is probably being deprecated in favor of amulet soon
ah i see
you need to add context checks
did you read the calculate wiki page at all?
this is like my first time hearing about this stuff lmao
no
me when i don't follow the advice given to me and expect help
ok well eris linked you it last time you asked, and i highly recommend reading it lol
srry
does anyone happen to know why a blind debuffing hearts like this is toggles the debuffs whenever a card gets an enhancement/a non-playing card is added?
return {debuff = true}
end```
I also have some code that prevents you from scoring at all unless a queen is visible, so that might be doing something weird but I have no idea what:
```if context.debuff_hand and not G.GAME.blind.disabled then
local _queenheld = false
for i = 1, #G.hand.cards do
if G.hand.cards[i]:get_id() == 12 then
_queenheld = true
end
end
for i, queencheck in ipairs(context.full_hand) do
if queencheck:get_id() == 12 then
_queenheld = true
end
end
if _queenheld ~= true or string.find(context.scoring_name, "Flush") then
blind.triggered = true
return { debuff = true }
end
end```
oh and these are both in a calculate function, just in case this makes it look like I forgot that or something
im trying to figure out how exactly i would get the last used planet card
Hey, guys I'm new to modding Balatro(and lua in general)
How can i manipulate the odds of joker appearing in shop(Guaranteed on every roll or has increased chance compared to other jokers)
info_queue[#info_queue + 1] = G.P_CENTERS.e_polychrome
local poly_tally = 0
if G.playing_cards then
for _, playing_card in ipairs(G.playing_cards) do
if card.edition and card.edition.key == "e_polychrome" then poly_tally = poly_tally + 1 end
end
end
return { vars = { card.ability.extra.xmult, card.ability.extra.xmult * poly_tally, card.ability.extra.divine } }
end,
calculate = function(self, card, context)
if context.joker_main then
local poly_tally = 0
for _, playing_card in ipairs(G.playing_cards) do
if card.edition and card.edition.key == "e_polychrome" then poly_tally = poly_tally + 1 end
end
return {
Xmult = 1 + card.ability.extra.xmult * poly_tally,
}
end
in_pool = function(self, args)
for _, playing_card in ipairs(G.playing_cards or {}) do
if card.edition and card.edition.key == "e_polychrome" then
return true
end
end
return false
end
``` it no worky
if you make your own rarity, i believe you can alter the shop rate (e.g. shop rate = 4), but im unsure how to do that with regular jokers
your in_pool function is currently inside the calculate function
happens to the best of us lol
im gonna assume this isnt saved already in the game and i would need to make a hook to do that
at least it loaded
you can use the global mod calculate and save it in context.using_consumable
consumeable?
one of the two
had oops btw
whats global mod calculate...
short answer: you cant
long answer: you can make a rarity, change how create_card_for_shop works by patching it or change how the pool system works entirely
also N' thanks for help
Ok thanks for answering :)
oops was not at fault
ohhh my god i didnt know you could do that
that changes things ok
do i do it like this, in the mod.lua?
yes
table should be context (i mean it could be table but its the context)
also assuming J_O_Y = SMODS.current_mod
what do I do 😭
ok this seems to be doing straight up nothing
can i not store this in our custom table do i have to use SMODS.current_mod
thats probably what it is
yea smods doesn't know shit about your mod's custom global table, SMODS.current_mod refers to the mod object that SMODS keeps track of
N said that was ok because he assumed you had local J_O_Y = SMODS.current_mod earlier in the file
yeah i misunderstood what he thought i meant, lmao
i still dont know how to do this
is it a basic lua thing or is it like,
unclear what you're asking
so i wanna store a variable in here that tracks the last used planet card
so that another joker can reference that
ahh right
so for global variables like that, you'll want to save it as a variable in the G.GAME table. so basically just
if context.using_consumeable then
G.GAME.joy_last_planet = context.consumeable.config.center.key
end
and then your joker can check if G.GAME.joy_last_planet exists, and if it does, do something with that
right
uhhh the center should store some info about its set but i dunno that off the top of my head, lemme check
wait i can just check constellation
ah yep
if anyone dares to use joy as a prefix im suing them
right i forgor
hey so for some reason it thinks GAME is a nil value
right here
dw ours has underscores
don't set the last planet in the config table, that won't update
but also GAME is nil at certain times (it doesn't get generated until you start a game for the first time in the session, or at least after the jokers are all initialized)
ah. yeah
you can just use G.GAME.j_o_y_last_planet directly in the calculate function and loc_vars and whatever
im trying to add compat with spectrum framework by making the decks with extra suits have the lower spectrum values, but nothing seems to be happening? the config has easy_spectra = true which isn't carrying over to G.GAME.starting_params, though G.GAME.starting_params.diverse_deck is set to true only on the 6 suit decks so i have to assume spectra is detecting it, so im not sure why the values arent decreasing
that's strange
it. should
yea i can confirm that it saves and loads anything stored in G.GAME just fine
maybe the game saves before calculating anything with using_consumeable, and you just quit too quickly for it to autosave
well it runs through the calculation just fine
i have a joker that updates its display to match the last sold joker, it updates fine
but then when i exit and relaunch it resets the display
so i think the variable is resetting
we had this issue with another joker some time ago too
and you're directly using G.GAME.j_o_y_last_planet in the loc_vars function?
local config = card.ability.extra
local planet = G.GAME.j_o_y_last_planet
local label
if G.GAME.j_o_y_last_planet then
table.insert(info_queue, planet.center)
label = localize { type = "name_text", set = planet.set, key = planet.key }
else
label = localize "k_none"
end
return {
vars = { config.planet_count, label }
}
end```
this is what the loc_vars code looks like
ok yea, like i said, maybe you're just quitting too fast after the calculation runs for the game to save
try advancing the game state in any way (picking a blind, opening a pack, playing a hand, etc) in between using a planet and quitting the game, and see if the issue still remains
oh YEAH
Technical questions :).
I'm working on a mod which adds unique modification which functionally and cosmetically change jokers effect (with each joker having a set of unique modifications). Currently I'm using custom hidden editions which I use to display infoqueques for each joker variant. The code for the mod is in the joker itself, not the edition. There's a way to make the edition display a variant used by the specific joker it is being used as an infoqueque from ?
Sorry for the long question but I wanted to be clear about it
i feel like an idiot, thank you 
That doesn't give much context
A74 code?
Although I'm not sure how the source of a seal could be a problem
But who knows
my card that i made, just checking if it could have been my mod or something else
Code?..
If anyone uses a similar code somethingcom wrote or knows it, How would I reset a joker's values back to normal at the end of a round? Other methods I've tried give errors and this gives nothing
chosen_joker doesn't exist in the context.end_of_round check.
nope, only purple is bugged
And if you get one a different way?
i havent tested that yet
Buh
ok so i've discovered 2 things:
- blue seal is also broken
- its bugged with cards that arent generated via triple rainbow
red seal and gold seal seem to work poperly though
So triple rainbow isn't a problem then
And since your mod is jokerforge, I would assume you wouldn't exactly make some new mechanics that break shit
Probably another mod's fault
yeah i'll try disabling some of the mods i have on
it's probably bunco, it started just after i downloaded bunco
tbf bunco breaks everything
how would i check to see each time the shop is re-rolled?
have you checked flash card
i completely forgot about that joker 😂
i've only been playing blindside sense it came out
add card is not adding the cards to deck at all, and is only creating ghosts
how are you suppoed to change the joker limit? i've tried setting G.jokers.config.card_limit but that yields extremely glitchy results
Probably G.jokers:change_size(number)
how does one change the music with a balatro mod?
how do i get unscoring cards anyway
context.cardarea == 'unscored'
did they change jokerExists?
No, because that doesn't exist.
if it was, it was probably in like smods 0.9.8
use SMODS.find_card for what you're trying to do
No, it never existed.
you are
sounds like a chatgpt invention
the fact that the first mention is 7 months ago when i was already modding makes me believe it's either just the same chatgpt hallucination or people copying code from a mod without copying the function too
they all mention it in regards to making a sound too
jokerExists isn't real i think
ok yeah it's the second thing
https://github.com/search?q=jokerExists&type=code
the fact people did this when find_joker exists is astounding
ah it's also in yahimod
what part of my sticker should i target to allow it to work with the set_sprite_pos function? (eg. for jokers instead you use card.children.center:set_sprite_pos({ pos }))
G.shared_stickers[key]
Guys, i need small help, i create a function that replaces on reroll(almost) every joker with baron, it works through create_card, but when i try to chance the 'j_baron' with my modded joker key, it crashes and gives me an error about center is nil
i tried to replace it with ortalab 'j_biker' and it generates. What i did wrong?
code?
`local original_create_card = create_card
local force_next_joker = false
function create_card(card_type, area, legendary, rarity, skip_materialize, soulable, forced_key, ...)
if card_type == 'Joker' and force_next_joker and not forced_key then
force_next_joker = false
print('[ForceNextJoker] FORCING BARON')
return create_card('Joker',area,legendary,rarity,skip_materialize,soulable,'j_baron')
end
local card = original_create_card(card_type,area,legendary,rarity,skip_materialize,soulable,forced_key,...)
if card_type == 'Joker' then
force_next_joker = true
local key = forced_key
if not key and card and card.config and card.config.center then
key = card.config.center.key
end
print('[ForceNextJoker] Joker created:', key)
end
return card
end`
This is the part of function.lua there another thing
and what are you replacing j_baron with?
pseudorandom_probability is missing an argument
The joker with key='banancik' the joker i added
thanks
like 'j_[mod prefix]_banancik'?
No....i did like 'banancik' as if wrote it in joker.lua
it needs the full key
Thanks, il try this when i get to the computer, hope it works
why does it do this
your context check is not strict enough
when do you want it to act
when a card is played
for each card played?
yes
then youre missing context.individual
also you should indent your code properly
i think some of your conditions are at the wrong level
idk if its not working or im getting really unlucky
does oops automattically work with modded jokers?
the only conclusion then is that it is not crashing but not working
and I basically changed nothing
context.individual and context.cardarea == G.play
it can't be context.cardarea and context.individual?
it can but 1) it's better to have the proper context first before the other information in the context (cardarea is an attribute of individual) 2) you need to check what area context.cardarea is, not what context.individual is
I have an effect that reduces ante on blind skip, if I trigger it and then exit the run, the ante goes back up but the skip is still taken. However blinds still show the reduced chip score until entered. Other effects triggering on blind skip seems to work properly
try saving the run after the tag is used
I tried save_run() after changing ante but it didn't change anything
can i see the code
` calculate = function(self, card, context)
if context.skip_blind and not context.blueprint then
card.ability.extra.skip_counter = card.ability.extra.skip_counter + 1
if card.ability.extra.skip_counter >= card.ability.extra.skips then
ease_ante(-card.ability.extra.anti_ante)
G.GAME.round_resets.blind_ante = G.GAME.round_resets.blind_ante or G.GAME.round_resets.ante
G.GAME.round_resets.blind_ante = G.GAME.round_resets.blind_ante - card.ability.extra.anti_ante
card.ability.extra.skip_counter = 0
card.ability.extra.skips = card.ability.extra.skips + 1
save_run()`
save the run in an event
what timing should it use? just immediate?
i just used the default
so this?
G.E_MANAGER:add_event(Event({ func = function() save_run() return true end }))
yeah
yup that works, thanks!
my Joker isn't doing anything, why not?
if context.individual and context.cardarea == G.play and context.other_card:get_id() == card.ability.extra.chosen_rank then
return { xmult = card.ability.extra.xmult }
end```
i've checked, and it has both its chosen rank and xmult assigned
it's not giving any xmult when its chosen rank is played
ah have the full code
You're setting the chosen rank to card.base.value, which is a string
either that or do get_id() in the set_ability function
no problem!
blocking = true,
func = function()
if #G.consumeables.cards > 0 then
SMODS.destroy_cards(pseudorandom_element(G.consumeables.cards, pseudoseed('tRex_destroy')))
if not context.blueprint then
card.ability.extra.mult = card.ability.extra.mult + card.ability.extra.mult_add
card.ability.extra.chips = card.ability.extra.chips + card.ability.extra.chips_add
end
end
G.E_MANAGER:add_event(Event({
blocking = true,
func = function()
if #G.consumeables.cards < G.consumeables.config.card_limit then
local set = next(SMODS.find_card("j_giga_velocyraptor" or "j_giga_velocyraptor_alt")) and 'Spectral' or 'Tarot'
SMODS.add_card({set = set})
else
SMODS.calculate_effect({ message = localize('k_no_room_ex') }, card)
end
return true
end
}))
return true
end
}))``` why does the card is always destroy after
so I remove every event and it will work
you should keep the event for creating the card but remove the other
okok
does anyone happen to know why a blind debuffing hearts like this is toggles the debuffs whenever a card gets an enhancement/a non-playing card is added? I use context.debuff_hand elsewhere as well, so I can't just do debuff = {suit = 'hearts' }. I've also tried commenting out the other code and nothing has changed, so something about this specific code doesn't work:
return {debuff = true}
end```
you should do context.debuff_card:is_suit('Hearts', true), with the true here making it bypass a debuff. otherwise the debuff will toggle every time its checked because debuffed cards normally dont count as their suit
that was the problem, thank you
just checked over my code again and it still no worky
info_queue[#info_queue + 1] = G.P_CENTERS.e_polychrome
local poly_tally = 0
if G.playing_cards then
for _, playing_card in ipairs(G.playing_cards) do
if card.edition and card.edition.key == "e_polychrome" then poly_tally = poly_tally + 1 end
end
end
return { vars = { card.ability.extra.xmult, card.ability.extra.xmult * poly_tally, card.ability.extra.divine } }
end,
calculate = function(self, card, context)
if context.joker_main then
local poly_tally = 0
for _, playing_card in ipairs(G.playing_cards) do
if card.edition and card.edition.key == "e_polychrome" then poly_tally = poly_tally + 1 end
end
return {
Xmult = 1 + card.ability.extra.xmult * poly_tally,
}
end
in_pool = function(self, args)
for _, playing_card in ipairs(G.playing_cards or {}) do
if card.edition and card.edition.key == "e_polychrome" then
return true
end
end
return false
end```
@frosty rampart what do
it doesnt do anything
ah yea that would do it
also you still aren't ending the calculate function properly, so the in_pool function isn't going to do anything. you need to add another end, right before the in_pool function
you still have calculate code at the bottom that isnt inside calculate
you should put that in calculate
moved it
i have a new issue now: how do i make a booster pack pick up a card instead of applying it
Whats hex vale of G.C.CHIPS
It is #009DFF
its fine i fixed it
is there a way to allow any version of a mod in dependencies? do i just not include a version?
yea that should work
wait actually i just realized that having smods dependency with no version restriction is pointless because you literally need smods to see missing dependencies anyway
add a balatro dependency
oh that does remind me tho
is there a way to make a mod conflict with talisman without also conflicting with amulet (which provides talisman)
looking at the code for conflicts i dont think so
dang, ok
heya, why this doesn't get retriggered?
i had a fix in a form of 'return nil, true' but now it's here by default and the joker still doesn't get retriggered
Hey guys, does someone have a joker sample? I wanna trace over one but the one I found isn't the right size
nvm i found it
am i missing something?
[REDACTED]
WAIT
WHERE DID THE SIZE THING COME FROM
istg i do NOT remember that
i still get the same error :(
here's the corrected code that i still get the error on
SMODS.Joker{
key = "foolsgold",
loc_txt = {
['name'] = 'Fools Gold',
['text'] = {
[1] = 'Played {C:attention}Gold{} cards',
[2] = 'have a {C:green}#1# in #2#{} chance to',
[3] = 'create a {C:tarot}Fool{} card',
[4] = '{c:inactive}(Must have room){}'
},
},
pos = { x = 9, y = 8 },
cost = 5,
rarity = 1,
blueprint_compat = true,
eternal_compat = false,
perishable_compat = false,
unlocked = true,
discovered = false,
atlas = 'CustomJokers',
config = { extra = { odds = 4 } },
loc_vars = function(self, info_queue, card)
local numerator, denominator = SMODS.get_probability_vars(card, 1, card.ability.extra.odds, 'j_hatch_foolsgold')
return { vars = { numerator, denominator } }
end,
calculate = function(self, card, context)
if context.individual and context.cardarea == G.play and SMODS.has_enhancement(context.other_card, 'm_gold', 'j_hatch_foolsgold') and
SMODS.pseudorandom_probability(card, 1, card.ability.extra.odds) then
return {
G.E_MANAGER:add_event(Event({
func = function()
SMODS.add_card {
key = 'c_fool',
}
G.GAME.consumeable_buffer = 0
return true
end
}))}
end
end
}
your probability calls are wrong
you need a string as the seed between card and the numerator
how do i do that
vremade_bloodstone?
SMODS.pseudorandom_probability(card, "something", 1, card.ability.extra.odds). the string can be anything you want
and do the same for the get_probability_vars function too
oek
vanillaremade usually uses the key of the joker as the seed
yeah for pseudo random probability u need to have ur seed
seed,,,
,,,,
i also decided to simplify no dice (a joker of mine) bc its code was way too janky
if two different probability calls share the same seed, then you could (theoretically) predict the outcome of one based on the outcome of the other
uh what the Fuck
SMODS.Joker{
key = "foolsgold",
loc_txt = {
['name'] = 'Fools Gold',
['text'] = {
[1] = 'Played {C:attention}Gold{} cards',
[2] = 'have a {C:green}#1# in #2#{} chance to',
[3] = 'create a {C:tarot}Fool{} card',
[4] = '{c:inactive}(Must have room){}'
},
},
pos = { x = 9, y = 8 },
cost = 5,
rarity = 1,
blueprint_compat = true,
eternal_compat = false,
perishable_compat = false,
unlocked = true,
discovered = false,
atlas = 'CustomJokers',
config = { extra = { odds = 4 } },
loc_vars = function(self, info_queue, card)
local numerator, denominator = SMODS.get_probability_vars(card, 1, 'j_hatch_foolsgold', card.ability.extra.odds)
return { vars = { numerator, denominator } }
end,
calculate = function(self, card, context)
if context.individual and context.cardarea == G.play and SMODS.has_enhancement(context.other_card, 'm_gold') and
SMODS.pseudorandom_probability(card, 1, 'j_hatch_foolsgold', card.ability.extra.odds) then
return {
G.E_MANAGER:add_event(Event({
func = function()
SMODS.add_card {
key = 'c_fool',
}
G.GAME.consumeable_buffer = 0
return true
end
}))}
end
end
}
the code rn
whats ur description
i used to use jokerforge to make probability jokers
oh no
yeah and now ive switched to standard coding i keep finding random bugs
whats weird is that other probability jokers (e.g. staircase) work
wot
dont mind the weird structure, i'm ommiting the uninteresting
invert ur seed and ur odds when u do local numerator, denominator
also ur french
@viscid talon
yeah those arguments are in the wrong order
I am here
oak
i have an icon for malverk, i still have the project file if u wanna tweak
I'm okay, thanks, I'll make my own at some point
oh okay
you should definitely use this for something though!
uhhh idk lol
FGRHRHSHFSHEFHESDFHSGH I STILL GET THE SAME ERRORRRR
heres the raw lua file im gonna need to take a breather and eat some dinner
your SMODS.pseudorandom_probability call is missing the seed
the thing feli was saying was only for get_probability_vars, the seed needs to go before the numerator in the pseudorandom_probability call
there's actually no seed at all in get_probability_vars, which again, is my mistake for saying so initially. that string is just the identifier for the probability call
that's what i just said 😭
no
i cant even test the code anyways because my game keeps crashing when i hover cards 😭😭
i know
