#💻・modding-dev
1 messages · Page 598 of 1
that is significantly easier, I can't believe I didn't think of that.
(thanks a lot!)
Hello, very embarrassed to ask, but would some of you good folks modders like to use some of my card sprites for your balatro mods 😶
sorry i use different theming for my balatro mod
sure why not
Is it better to group your jokers in chunks or give each it's own separate file?
i've been doing the latter
I think it's a bit more organized to do your jokers in groups by the sprite sheet but that's just what I picked up personally
i do the chaotic route and sort my jokers by rarity on the file names themselves
What does twister do?
if a seal triggers it triggers another seal effect
so if you get a tarot card off a purple seal there's the chance you get the effect of a gold seal from the joker (so $3)
Sorry for the late answer, I'm at work, which one would you like to take?
because of this, you can get another tarot card off the purple seal in the chance that you do trigger it
weep
i too am in this modification
is there a way to set a variable to a random poker hand?
i found out how yay
hi i need some sprites lol
Which ones would you like to take
im brainstorming a bit lol hol up
how do you change the description of a joker with malverk
can you even do it in the first place
oh wait
i forgot to add a bracket hold on
🍎 🍑
i got this working
i find it weird that malverk doesn't revert back to a crossmod joker's original textures and instead uses the balatro joker spritesheet as a fallback
💔
You should mame this atlas 1 texture tall :clueless:
One big line of jokers
can anyone help me figure out this hook? first time using them and I'm struggling to figure them out
Game.start_run = function (args)
--"This print statement will happen BEFORE the original code runs!--
local jokers =
jokers.config.highlighted_limit (args),
end,
--This print statement will happen AFTER the original code runs!--
return
jokers.config.highlighted_limit = 2,
end,
return jokers,
end
end```
What is the goal?
local oldstartrun = Game.start_run
function Game:start_run(args)
local g = oldstartrun(self, args)
self.jokers.config.highlighted_limit = 1000
return g
end
do i just have to deal with this like there's no fix for this?
How to place code at the final scoring step with a hook
You mean you want something to happen in context.final_scoring_step without any jokers, consumables, vouchers, challenges or decks?
Yeah specifically flipping (and unflipping) cards with a specific enhancement, i figured the best way would be to list them all up externally and run events
Use the mod calculate
is there a mod called calculate
SMODS.current_mod.calculate = function(self, context)
if context.final_scoring_step then
-- Code
end
end
lmfaooooooo

ok y'all im having a lot of trouble with a consumable i'm trying to make; i've checked in the Vanilla code and in other mods for examples to attempt to deconstruct, but I'm having a hard time. I'm trying to make a consumable that adds the sticker from the rightmost selected joker to the leftmost selected joker, then destroy the right joker. can anyone help me out?
table.sort(G.jokers.highlighted, function(a,b) return a.T.x < b.T.x end)
local left, right = G.jokers.highlighted[1], G.jokers.highlighted[#G.jokers.highlighted]
for k, v in pairs(SMODS.Stickers) do
if left.ability[k] then
right:add_sticker(k, true)
end
end
SMODS.destroy_cards(left)
so it take the two jokes highlighted, assigns them a and b functions, and prioritizes a over b. the local function takes the left and right selected cards (jokers, in this case) and equates them to the G.jokers.highlighted functions. k is the card ability (the sticker, in this case) and pairs is assigned to read the Stickers amongst the SMODS variables. It asks if the left most selected joker has an ability from a sticker, and if it does, it adds that sticker (k) applies it to the right, then destroys the left card.
did I get that right? I just want to clarify so i can learn instead of copying and pasting every time someons helps me
No.
ah.
It sorts the table so they are in order from left to right then it sets the left and right variables to the leftmost and rightmost jokers, then it iterates over SMODS.Stickers and checks if the leftmost joker has that sticker, and if it does, it applies it the rightmost joker, then it destroys the leftmost joker.
ok, so what are function(a, b) and the k and v variables for?
key = "stones",
set = "Tarot",
pos = { x = 2, y = 1 },
config = { max_highlighted = 2 },
table.sort(G.jokers.highlighted, function(a,b) return a.T.x < b.T.x end)
local left, right = G.jokers.highlighted[1], G.jokers.highlighted[#G.jokers.highlighted]
for k, v in pairs(SMODS.Stickers) do
if left.ability[k] then
right:add_sticker(k, true)
end
end
SMODS.destroy_cards(left)```
Am I not implementing it correctly?
Yes, it needs to be in use
This is the error I keep getting, i don't understand what's wrong in the code; I'm closing the bracket at line 25, but apparently that's wrong?
hey y'all is there an alternative to SMODS.Suits that is instead an ordered list of suits?
SMODS.Suit.obj_buffer?
calculate = function(self, card, context)
local isBossBlind = G.GAME.blind.boss
local isShowdown = G.GAME.blind.showdown -- G.GAME.blind.config.blind.boss.showdown
if context.joker_main and isBossBlind then
return {
xmult = card.ability.extra.xmult
}
end
if context.setting_blind and isShowdown then
G.GAME.blind.chips = G.GAME.blind.chips * 0.90
G.GAME.blind.chip_text = number_format(G.GAME.blind.chips)
card:start_dissolve({ G.C.RED })
end
end
}```
the setting blind during a showdown boss won't work at all, and yes i tried blind config shodown and wouldn't work either, i'm not sure what i'm doing wrong
the "use" line has improper syntax and should be replaced with use = function(self, card, area, copier)
also yeah for the config blind boss, it gives me this
No, it would be use = function(self, card, area, copier)
local isShowdown = G.GAME.blind.boss and G.GAME.blind.boss.showdown or nil
i'll try that, thanks
nope
i did changed the local as said so
local isShowdown = type(G.GAME.blind.boss) == 'table' and G.GAME.blind.boss.showdown or nil
Doesn't work either sadly, still stays in and work like if it was in a regular boss blind
I'd like to add some Multiplayer compatibility to my mod but I can't really find a channel for that on the Multiplayer server
Does anyone know how I'd go about checking when the nemesis (or any opponent in battle royal) plays a hand?
I was thinking about always looking at the current hand count, but it can get pretty hard to identify when an hand is played if an opponent gets more hands during the pvp, somehow
dog im gonna crash out
Isn't the balatro multiplyer server could help you on this ?
What doesn't work exactly ?
I'm not really making a proper mod, I'm making an add-on for Pokermon, so I can't really create a thread for my mod and ask that there
I'm not sure? The "nil" value is supposed to be 2, and when I select the two jokers (moving the Sticker from the left joker to the right) it doesn't let me use the consumable
pinged the wrong person lol
fuck
i believe it's missing a loc_vars bit
for the 'nil' you should add the card.ability.max_highlighted or card.ability.min_highlighted to it
oh my god i can't believe i missed that
ive been so focused on the rest of the code i missed one of the simplest bits
happens to me
also could you show your use function trough text ? i feel like it cutted some part of it in the image
key = "stones",
set = "Tarot",
pos = { x = 2, y = 1 },
config = { max_highlighted = 2, min_highlighted = 2 },
loc_vars = function(self, info_queue, card)
return { vars = { card.ability.max_highlighted } }
end,
use = function (self, card, area, copier)
table.sort(G.jokers.highlighted, function(a,b) return a.T.x < b.T.x end)
local left, right = G.jokers.highlighted[1], G.jokers.highlighted[#G.jokers.highlighted]
for k, v in pairs(SMODS.Sticker) do
if left.ability[k] then
right:add_sticker(k, true)
end
end
SMODS.destroy_cards(left)
end
}```
local isShowdown = type(G.GAME.blind.config.blind.boss) == 'table' and G.GAME.blind.config.blind.boss.showdown or nil
ok so the code works when I select two playing cards, but not when i select 2 Jokers
Yes, max_highlighted and min_highlighted only activate when cards in hand are selected.
so how do i apply it to jokers then?
nope :(
i think i remember crytpid had consumables working with more or less the same idea
try checking from there
this, probably you can see how this work then use it for stickers instead
arent you missing a can_use field
dog idk i've been doing this for a combined number of days less than a week
can_use = function(self, card, context)
return card.ability.min_highlighted <= #G.jokers.highlighted <= card.ability.max_highlighted
end,
local used_consumable = copier or card
local combinedTable = Cryptid.get_highlighted_cards({ G.hand, G.jokers }, card, 2, 2)
local highlighted_1 = combinedTable[1]
local highlighted_2 = combinedTable[2]
G.E_MANAGER:add_event(Event({
trigger = "after",
delay = 0.4,
func = function()
play_sound("tarot1")
used_consumable:juice_up(0.3, 0.5)
return true
end,
}))```
Something like this line from the Conduit?
though in base game you can't highlight 2 jokers
already taken care of that part, thankfully
oh, i guess not ? Honestly was expecting something else from it
local combinedTable = {}
dbl = false
no_dbl = false
for _, value in ipairs(G.hand.highlighted) do
if value ~= card then
if Card.no(value, "dbl") then
no_dbl = true
elseif value.edition and value.edition.cry_double_sided then
dbl = true
end
table.insert(combinedTable, value)
end
end
for _, value in ipairs(G.jokers.highlighted) do
if value ~= card then
if Card.no(value, "dbl") then
no_dbl = true
elseif value.edition and value.edition.cry_double_sided then
dbl = true
end
table.insert(combinedTable, value)
end
end
return (#combinedTable == 2 and not (dbl and no_dbl))
end,```
there's this as well
Thanks, it finally worked
maybe this can help, there's the jojer highlited part so
No, it would be return G.jokers and #G.jokers.highlighted == 2
Also legit speaking, it's pretty weird it took that much to make a shodown detectable
and that G.GAME.blind.config.blind.boss.showdown or G.GAME.blind.showdow didn't worked out
huh
loc_vars or config
In can_use
ok so everything up until i actually use the consumable works and then
i want. to scream.
Code?
key = "stones",
set = "Tarot",
pos = { x = 2, y = 1 },
config = { max_highlighted = 2, min_highlighted = 2 },
loc_vars = function(self, info_queue, card)
return { vars = { card.ability.max_highlighted } }
end,
can_use = function(self, card, context)
return G.jokers and #G.jokers.highlighted == 2
end,
use = function (self, card, area, copier)
table.sort(G.jokers.highlighted, function(a,b) return a.T.x < b.T.x end)
local left, right = G.jokers.highlighted[1], G.jokers.highlighted[#G.jokers.highlighted]
for k, v in pairs(SMODS.Sticker) do
if left.ability[k] then
right:add_sticker(k, true)
end
end
SMODS.destroy_cards(left)
end
}```
this is the consumable code, i can also provide sticker code
key = "trifuricated",
badge_colour = HEX("a86232"),
pos = { x = 6, y = 1 },
config = { extra = { retriggers = 2 } },
calculate = function(self, card, context)
if (context.repetition or context.retrigger_joker_check) and context.other_card == card then
return {
repetitions = card.ability.inscrypt_trifuricated.extra.retriggers,
}
end
end,
loc_vars = function(self, info_queue, card)
return { vars = { self.config.extra.retriggers } }
end
}```
Put SMODS.destroy_cards(left) in the use function.
Also it's SMODS.Stickers
when i change it to SMODS.Stickers the game doesn't start up
Log?
key = "trifuricated",
badge_colour = HEX("a86232"),
pos = { x = 6, y = 1 },
config = { extra = { retriggers = 2 } },
calculate = function(self, card, context)
if (context.repetition or context.retrigger_joker_check) and context.other_card == card then
return {
repetitions = card.ability.inscrypt_trifuricated.extra.retriggers,
}
end
end,
loc_vars = function(self, info_queue, card)
return { vars = { self.config.extra.retriggers } }
end
}```
No, on the consumable.
key = "stones",
set = "Tarot",
pos = { x = 2, y = 1 },
config = { max_highlighted = 2, min_highlighted = 2 },
loc_vars = function(self, info_queue, card)
return { vars = { card.ability.max_highlighted } }
end,
can_use = function(self, card, context)
return G.jokers and #G.jokers.highlighted == 2
end,
use = function (self, card, area, copier)
table.sort(G.jokers.highlighted, function(a,b) return a.T.x < b.T.x end)
local left, right = G.jokers.highlighted[1], G.jokers.highlighted[#G.jokers.highlighted]
for k, v in pairs(SMODS.Stickers) do
if left.ability[k] then
right:add_sticker(k, true)
SMODS.destroy_cards(left)
end
end
end
}```
exact same thing, exact same error
Which error?
You need to change it back to SMODS.Sticker on the sticker.
Well now when I use the consumable, it's A) Not adding the sticker and B) not destroying the left Joker
key = "stones",
set = "Tarot",
pos = { x = 2, y = 1 },
config = { max_highlighted = 2, min_highlighted = 2 },
loc_vars = function(self, info_queue, card)
return { vars = { card.ability.max_highlighted } }
end,
can_use = function(self, card, context)
return G.jokers and #G.jokers.highlighted == 2
end,
use = function (self, card, area, copier)
table.sort(G.jokers.highlighted, function(a,b) return a.T.x < b.T.x end)
local left, right = G.jokers.highlighted[1], G.jokers.highlighted[#G.jokers.highlighted]
for k, v in pairs(SMODS.Stickers) do
if left.ability[k] then
right:add_sticker(k, true)
SMODS.destroy_cards(left)
end
end
end
}```
Move SMODS.destroy_cards(left) out of the for loop.
nope
key = "stones",
set = "Tarot",
pos = { x = 2, y = 1 },
config = { max_highlighted = 2, min_highlighted = 2 },
loc_vars = function(self, info_queue, card)
return { vars = { card.ability.max_highlighted } }
end,
can_use = function(self, card, context)
return G.jokers and #G.jokers.highlighted == 2
end,
use = function (self, card, area, copier)
table.sort(G.jokers.highlighted, function(a,b) return a.T.x < b.T.x end)
local left, right = G.jokers.highlighted[1], G.jokers.highlighted[#G.jokers.highlighted]
for k, v in pairs(SMODS.Stickers) do
if left.ability[k] then
right:add_sticker(k, true)
SMODS.destroy_cards(left)
end
end
end
}```
It's still in the for loop.
How do you change the background colors like how the showdown blinds do?
Is there a way to check if something is a playing card in SMODS.Sticker, specifically should_apply?
ease_background_colour, apparently. I searched for boss_colour in all files
is there a md that adds a whole new type to cards like editions/seals etc.?
I know that Paperback adds "Paperclips" if that helps
thanks
if card.playing_card
Wait, why does return G.GAME.challenge == "c_cstorm_death_challenge" and not card.playing_card not work?
if card.ability.extra.round_left <= 0 then
return true
end
return false
end,
use = function (self,card,area,copier)
G.E_MANAGER:add_event(Event({
func = function()
G.consumeables:change_size(card.ability.consumSlot)
return true
end
}))
end,```
I dont understand why it doesnt change the size of the consumeable slot
Do you have consumSlot in the config?
yeah
round = 1,
round_left = 1,
consumSlot = 1,
txt = 'Not ready yet'
}},```
found out the bug
is that good cause it make me crash
SMODS.ConsumableType{
key = "would_you_rather",
collection_rows = {4,5},
primary_colour = G.C.JOKER_GREY,
secondary_colour = G.C.GREY,
loc_txt = {
name = "Would You Rather"
},
shop_rate = 0
}
what am I missing?
card.ability.perma_bonus = (card.ability.perma_bonus or 0) + card.ability.extra.chips
oh ok thx
Is it possible to make a joker that changes all text in the game?
well its possible but how
my ideas is that you would probably either need to make a new language localization and make the joker reload into that and back again or hook localize and modify the localized text
yeah, I've been looking into it decided to go with the first option
thank you anyway
is there a list of vanilla tag keys
Why does this not work?
--if in challenge, then apply to all jokers/consumables
return G.GAME.challenge == "c_cstorm_death_challenge" and not card.playing_card
end,```
they don't have the prefix for some reason
https://jokerforge.jaydchw.com/keys
so would i do add_tag(Tag('tag_double')) or add_tag(Tag('double'))
how can i change all starting cards for a deck ?
tag_double
G.E_MANAGER:add_event(Event({
trigger = 'after',
delay = 0.2,
func = function()
for i=1, #G.playing_cards do
[Code]
return true
end
}))
end ```
you're trying to index Giga before it actually exists
bump
yeah but like idk where I do that
lovely patch
oh
what can i add in the [Code] part ?
# PACKS MODIFICATION #
[[patches]]
[patches.pattern]
target = 'card.lua'
position = 'after'
pattern = '''
booster_obj = self.config.center
'''
payload = '''
if self.config.center.group_key == 'k_restaurant_pack' then
self.ability.extra = self.ability.extra + (G.GAME.giga and G.GAME.giga.vouchers and G.GAME.giga.vouchers.newMenu or 0)
end
if self.config.center.group_key == 'k_restaurant_pack' then
self.ability.choose = self.ability.choose + (G.GAME.giga and G.GAME.giga.vouchers and G.GAME.giga.vouchers._courseMeal or 0)
end
'''
overwrite = true
match_indent = true```
its probably in that but idk where cause I didnt change anything
definitely not
functions/state_events.lua
but I dont have that
you patch it somewhere i think
If I remove the and not card.playing_card, it applies the sticker to everything
thats not the way to check if a card is a playing card then
[patches.pattern]
target = "functions/state_events.lua"
pattern = "for _, area in ipairs(SMODS.get_card_areas('jokers')) do for _, _card in ipairs(area.cards) do"
position = "at"
payload = "local places = Giga.areaprocess(SMODS.get_card_areas('jokers')); for _, place in ipairs(places) do local scoreCards = Giga.areaprocess(place.cards); for _, _card in ipairs(scoreCards) do"
overwrite = true
match_indent = true
[[patches]]
[patches.pattern]
target = "functions/state_events.lua"
pattern = "for _, v in ipairs(SMODS.get_card_areas('playing_cards')) do"
position = "at"
payload = "local playedCardsPlace = Giga.areaorderprocess(SMODS.get_card_areas('playing_cards')); for _, v in ipairs(playedCardsPlace) do"
overwrite = true
match_indent = true```
oh yeah that but I litteraly just use the patch from Toga just by changing the name
yeah that
Giga doesn't exist yet
maybe you could check if the card has a base rank?
and what do I do
i assume Toga has a table somewhere that you didn't add when renaming
go check for it
ok
[patches.pattern]
target = "functions/state_events.lua"
pattern = "check_for_unlock({type = 'run_card_replays'})"
position = "before"
payload = "if togabalatro then togabalatro.playextracards() end"
match_indent = true```
is it that
no
what did you replace with Giga
What was it
its been like 2 month since i do that
and it crash just now
like I replace togabalatro for Giga
ctrl f togabalatro to find where it's defined and add that
also the functions in togabalatro
I have all the function that was needed for it
Idk but it just doesnt crash anymore
Just be mindful doing that will break my setup. 😅
-# We certainly need a hookable function in there, tbh.
Does anybody know an easy way to have a joker constantly shaking once a condition is met? (think invisble joker when it's ready to activate or dna on the first hand)
I've been using jokerforge as a base and then editing the code myself but their version of the effect is broken and I can't find a way to fix it
card.base?
if card.ability.set == 'Default' or card.ability.set == 'Enhanced'
this is how dna does it:
local eval = function() return G.GAME.current_round.hands_played == 0 and not G.RESET_JIGGLES end
juice_card_until(card, eval, true)
and trading card:
local eval = function() return G.GAME.current_round.discards_used == 0 and not G.RESET_JIGGLES end
juice_card_until(card, eval, true)
That works, thank y'all
Other question: How do I check if a card is flipped?
if card.facing == 'back'
how do I add a card to the title?
is it possible to call SMODS.calculate_effect with messages appearing on the consumables tray? i need to be able to call it without any card target
Have you tried putting G.consumeables where you would input the card?
is there a nicer way to modify ante scaling for a deck thats not modifying the get_blind_amount function
oh ante_scaling for config exists :clueless:
crashes
but thats a static number modifier can the base amounts be modified?
this is in a mod calculate
i might be able to try something with SMODS.merge_effects
Depends on what you want to do
Log?
Have you tried having the card input be a card but set message_card = G.consumeables in the effect?
does the card exist
could try that?
i've swapped the effects to be a normal calculate return though
this works except the attention text is displayed over the deck
mod calculate uses the deck yes
yea
i'm trying to get it to use the consumables tray
but i don't quite know how i'd do that
message_card = G.consumeables? maybe
just realized i also used #ret > 0 instead of next(ret) 
yep that worked
is it possible to reduce the intensity of the juice effect on it
most people seem to think the tray being juiced looks very silly
i dont think it can be adjusted but im pretty sure you can add no_juice = true to remove it
ah
change all cards in deck
add cards
remove cards
How do you return exponential mult using Talisman? I cant find any documentation. And I have more luck finding a needle in a haystack than actually reading the source code and then understanding it lol.
emult = <value>
I'll try that
i thought it was e_mult
you can do that on other things??????
wrow
bump
oh uh
ok thx
i noticed {C:G.C.SUITS.#1#}#1#{} isnt working
yeah
any ideas or workarounds
ah oki
colours = {...} under vars
and then you can use them with V:1, V:2, V:3, etc in order
return { vars = {drinksuit, colours = {G.C.SUITS[drinksuit]}} }
local drinktxt = {
"When sold, randomly turns",
"half of your deck into",
"{V:1}#1#{}, and the other half into",
"a random other suit"
}```
still not working??
are you not forgetting card.ability... part
also the suit colour keys are plural
but idk if thats an issue
local suits = {"Spades","Hearts","Clubs","Diamonds"} -- todo: check for paperback/bunco suits
local drinks = {["Spades"]={2,3},["Hearts"]={3,3},["Clubs"]={4,3},["Diamonds"]={5,3}}
for drinksuit, drinkatlas in pairs(drinks) do
local drinkid = 'drink_'..string.lower(drinksuit)
SMODS.Joker {
key = drinkid,
config = {},
loc_vars = function(self, info_queue, card)
info_queue[#info_queue + 1] = { set = "Other", key = "hypr_devart" }
return { vars = {drinksuit, colours = {G.C.SUITS[drinksuit]}} }
end,
…
yeah
because drinksuit is a local variable of the for loop
it wont exist anymore after the joker is created
config = { extra = {mult = 20, chips=100, xmult = 3, dollar=25, min = 1, max = 3, set_value = 0 }},
loc_vars = function(self, info_queue, card)
return { vars = { card.ability.extra.mult,card.ability.extra.chips,card.ability.extra.xmult, card.ability.extra.dollar } }
end,
calculate = function(self, card, context)
if context.setting_blind then
card.ability.extra.set_value = pseudorandom('cymbal_untextured', card.ability.extra.min, card.ability.extra.max)
return {
message = "?"
}
end
if context.joker_main then
if card.ability.extra.set_value == 1 then
return {
mult = card.ability.extra.mult,
key = "j_cymbal_untextured_alt"
}
elseif card.ability.extra.set_value == 2 then
return {
chips = card.ability.extra.chips,
key = "j_cymbal_untextured_alt2"
}
elseif card.ability.extra.set_value == 3 then
return {
xmult = card.ability.extra.xmult,
key = "j_cymbal_untextured_alt3"
}
end
end
end
}
tried to make my joker change its text depending on the set value, at first i wanted to do when setting the blind, then tried to do with joker scoring but in both case it does nothing, not sure how to fix that, would appreciate the help !
Or should i use the loc_vars and key thing even in that case ?
In there, yeah.
You can `return { key = 'mod_key' } to use different locentry to show.
oh i see, but can i use then something like
loc_vars = function(self, info_queue, card)
return { key = card.ability.set_value == 1 and "j_cymbal_untextured_alt" or nil,card.ability.set_value == 2 and "j_cymbal_untextured_alt2" or nil }
end
or it needs to be different ?
key = condition1 and self.key.."_alt" or condition2 and self.key.."_alt2" or self.key
okay i think see now so something like
key = card.ability.set_value == 1 and self.key"_alt" or card.ability.set_value == 1 and self.key"_alt2" or self.key
with conditions being the card.ability.set_value, am i understand it right ?
is there a proper way to implement modded joker skins on malverk that completely prevents this type of thing to happen? even as a separate mod/skin it can still happen if the skin isn't applied so it's either you have it on or remove it from the mod loader
Yes, but remember to have .. between self.key and "_alt" so that they become one string.
noted, thanks a lot
return {key = card.ability.set_value == 1 and self.key.."_alt" or card.ability.set_value == 2 and self.key.."_alt2"or card.ability.set_value == 3 and self.key.."_alt3" or self.key}
end```
```lua
return {
descriptions = {
Joker = {
j_cymbal_untextured = {
name = "U.. extu ..d J.k. r",
text = { "{C:inactive} (Does something different each round.)"
},
},
j_cymbal_untextured_alt = {
name = "U.. extu ..d J.k. r",
text = { "{C:chips}+100{} Chips"
},
},
j_cymbal_untextured_alt2 = {
name = "U.. extu ..d J.k. r",
text = { "{C:mult}+20{} Mult"
},
},
j_cymbal_untextured_alt3 = {
name = "U.. extu ..d J.k. r",
text = { "{X:mult,C:white}x3{} Mult"
},
},
getting unsure of what i'm doing wrong, the self key and the keys themselves are correct but it'll still stay to the default text
i dont think you can evaluate inside tables
hello! i'm having problems with the localization of seals and booster packs, i've put them onther "Other" like other mods do, but it's the only things that show up blank, jokers and consumables are working fine
<@&1133519078540185692>
damn
that bot did NOT like your question
lmaoo
i will now proceed to cry
thanks you mods
let me see
this should be fine it's identical to other mods but it doesn't show up
for boosters it should be p_mod-prefix_booster-key
yeah bt this still doesn't work
yes
For some reason, the exponential mult isnt triggering, and I dont know why. The idea is that for every 5 cards with this seal scored, it gives ^1.25 Mult.
everything works except that
it's emult
I thought it didnt matter
if I used e_mult or emult
I'll try it though
hrm
honestly i had the same problem with exp mult and i ended up dropping the idea..
cause i didn't solve it
imo exp mult is just too strong but that's a different conversation
im reading and a lil confused
is SMODS.create_card{ set = 'Joker', rarity = 0.96 } a correct syntax to spawn a random rare joker?
rarity = 3 is rare
why's rarity = 0.96?
well it still didnt trigger lol
3 is rare yeah
yeah.. cryptid uses emult but i think they probably have a lovely patch for that? idk
it should work if you have just talisman in theory
how would i make a deck have 2 voucher slots in shop
but it doesnt
this is under this right?
return {
descriptions = {
Other = {
p_napoli_tombola_normal_1 = {
name = "Panaro",
text = {
'yeah'
},
},
},
},
}
......
and how is the text not working
like in-game
does the description show up but not the title?
idk im going by this
and double checking that your mod prefix is "napoli"?
yeah.. otherwise everything else wouldn't work
i'm just checking cuz i don't see anything else wrong
like jokers work fine
yeah me neither but idk how to troubleshoot this
honestly i've had trouble with the Other tab for localization too
for now you could just set the loc_txt to whatever you want
yeah that works for everything except the seal badges
how so?
i mean idk how i would use loc_txt on those
for seals it's
loc_txt = {
name = 'name'
label = 'badge'
text = {
"text"
}
}
yeah
if you don't intend on doing translations it's no big, but if you do then it's a big
will lovely patches affect all relevant lines if multiple lines match the pattern, or only the first line?
(the patches.pattern, not the regex)
i suppose i can just find out lol
pretty sure only the first instance of the pattern
fuck
could i have a second copy of the patch to hit the second instance?
My friend wants to make a translation mod for toki pona, how do you add your own language to balatro? Thanks!
nope it patched all instances
card.ability.extra.set_value... you missed the extra table.
thank you!
oopsie
thanks
thanks a lot, it does work properly now
Hello, how do P_CENTERS work? I created a consumable but now Im not being able to summon it via a joker because it can't find the center. Do I define the centers? Is done automatically?
What's the key of it and what's your modprefix?
key is "erebos_favour" the modprefix idk how that works 😅
it's "mtgg" nvm
still dont know how to use it tho
do I need to pass the modprefix in the SMODS.add_card function?
okay so how do you actually spawn a random rare joker
SMODS.add_card({set = 'Joker', rarity = 'Rare'})
vanillaremade is your friend in future
but yeah what something said
key = "c_[mod prefix]_[key]"
well i checked vanillaremade and the way they did it sucks
why
because that is exactly what something said
thank you :)
there's not an actual example it's buried within the rare tag
Wraith
how does one get if high contrast is enabled? it's probably G.SETTINGS.<something> but idk what that something is
if G.SETTINGS.colourblind_option?
oh found it
suit colour values change automatically based on high/low contrast settings
what aboud added suits
you shouldnt need this unless youre making smth else entirely
all suit colours work like that
the normal way is to just set both colour values in the suit itself
there's no reason to do anything else
do make sure to include the mod prefix in the suit keys when you do use them
i don't understand this
oh yeah
i forgot i change one
thanks
how can i change ERROR ? it's not like this ?
is it because it says "extra_zero" instead of just "zero"? or the other way around?
yeah i think the key in the SMODS.Rank should be extra_zero, not just zero
what does your full localization file look like
all my backs then just this
misc shouldn't go inside descriptions
put it at the same level, after line 110 in that screenshot
mooooooods
we in it to win it gang
oh good lord
ZA WARUDO
so close to being done I just hate work and want to play wind waker
when my joker tries to Play a sound during scoring, the game crashes to this Any of yall know how to fix this?
4.jpg never works
custom sound?
Yea
Tried going from .ogg to .mp3 which didnt also work Idk what i was expecting honestly
I recall personally also having issues w/ ogg, and it working with mp3
I see
dunno though, I've never done much else w/ music in my mods
this error message didnt change when i was changing the file from ogg to mp3 and forgot to Change the path for the SMODS.Sound to say mp3 at the end
Which is kinda suspicious but Idk what it could mean
there's one thing I do remember, it loads things differently if the word "music" is somewhere in the key iirc?
Do you mean like if the word "music" is in the key it could mess up or Should i try having "music" in the key
I don't remember haha, try both I'd say
if music is in the key it could mess it up, as that's intended for background music
na its not in the key fortunately
Honestlyy i doubt it'd work but might be worth trying at this point 😭
if that doesn't work either double check the file location (path and name)
it's failing while trying to find the filepath
this is supposed to override drawing cards which im sure is extremely wrong haha
draw_card merely executes the draw of a card...
function draw_card(from, to, percent, dir, sort, card, delay, mute, stay_flipped, vol, discarded_only)
Trying to make my enhancement increase in Xmult for every other card with that enhancement in full deck, but the code (which i totally didn't steal from the steel card from vanilla remade) causes a stack overflow when hovering over for some reason?
AHHH okay genuinely no one told me the args to draw card
thank you ali
This had been very much the same thing when I was also counting for specific enhancement on cards - you need to add a "is calculating" local variable to prevent looping into itself.
i have a joker that does this
but for money im pretty usre
just search all files for function draw_card, no?
Interesting, where would I put it? Still pretty new to coding
isn't a context check better?
Or that.
-# Brain currently storming ideas about how feasable are replacements of my destructive patches... running on fumes.
In that case, what context check would be better?
if I'm understanding correctly, the calculates are looping somehow
weird thing is you already have a context check
I had an issue like this before... https://github.com/TheOneGoofAli/TOGAPackBalatro/pull/2
that one's because your calculate didn't guard against contexts
calculate = function(self, card, context)
card.ability.extra.totalrepetitions = card.ability.extra.repetitions*toga_gettotalsteelcount() or 0
....
end
wow nice indentation, thanks discord
ah, indentations! discord coder's worst nightmare!
(i would suppose, i'm not sure)
is this your only joker/object present that's calculating?
i'm a bit confused on the question
I'm wondering if your joker is the one infinitely looping or if your joker just triggers the infinite loop somewhere else
Where are you hovering over the joker?
(e.g. in a run, in the collection)
Ah, it's an enhancement! I already tried hovering over the card in either a run, collection, and even in the shop
Same result as always
Ah my bad
(stack overflow crash)
No pressure LOL
quick question do i have to do a while loop to prevent #G.hand > G.hand.config.card_limit while drawing or is that done automatically
i'm just trying to make a straight with my custom ranks..
Ah, think I found it
that info_queue[#info_queue+1] = G.P_CENTERS.m_jsm_wet is not doing any favours for avoiding recursion
Well, from what i see it IS an info queue so it does look suspicious...
In any case, I never touched it, as i... actually have no idea what it does
You're telling balatro to generate the little tooltip on the side of the enhancement
stack overflow :(
Ah! I see
and every time balatro adds a tooltip, you tell it to add "just 1 more"
ad infinitum
similar to how the Fool -> Magician -> Lucky card tooltip works
but then yours is Wet Enhancement -> Wet -> Wet -> Wet -> ...
OH YEAH (sorry to pop in guh)
infinite info queue 
yea
Aha! Makes sense
Well, in that case it's useless since it's a enhanced card which already has the tooltip. Meaning if i delete the info queue... it'll be fine?
hi nix washing machine
should be
only thing i changed
my custom ranks are in every decks, how can i disable that ? (and only show in one deck)
-# 
Yeah sorry that was confusing since infinite recursions with calculate cause a similar crash like Ali said
Hey I was wondering if anyone knows how to add a negative tooltip onto a card, is it somewhere in loc_txt?
I'm so lost I tried a few things but I'm not sure what to add 😅
My description works fine but I can't for the life of me seem to get the tooltip to show xD
loc_txt = {
name = "Card",
text = {
"Has a {C:attention}10%{} chance to create {C:attention}20{}",
" {X:dark_edition,C:dark_edition}Negative{} copies of random {C:consumable}consumables{}",
" when leaving the {C:shop}shop{}."
}
},
Add it to the info_queue table in the loc_vars method, see https://github.com/Steamodded/smods/wiki/Localization#loc_vars
i don't know how to code TwT
i'm trying but i really don't know how to do this
<@&1133519078540185692> pls
Take a look at what other mods with modded suits do maybe? Or just bang your head against the wall trying and see if you can figure it out
THANK YOU SO MUCHH
🙏
👀
It's G.deck not G.deck.cards
from paperback, i have something, i use the code from the dreamer's sleeve (the only way to start with apostles) but the "is_buffed" don't work (the part from the apostle code works the rank doesn't spawn)
so i don't know what can i add instead of the "is_buffed"
-# i'm going to sleep anyway that's too hard for me
you'd have to check the deck used in the rank's in_pool method
No, only in draw_card
oh gotcha
Hello! Anyone know any contexts for when a card with an enhancement is played?
there isn't a context for everything
there's a few contexts for "when a card is played" depending on what you mean by that, and then you can check if the relevant card has an enhancement with next(SMODS.get_enhancements(card))
Oh i mean, a context for when a playing card with an enhancement scores
Quick question:
I wanna code up 15 consumable cards similar to each other with slightly different effects (some buffing face cards, some odd, some even, some composite, and so on). However, I don't want to make a different variable for each one. Is there a way I can make those buff happen in the card itself?
context.individual is when a playing card scores, and then you can check if context.other_card has an enhancement from there
splendid! much appreciated!
Can't forget about context.cardarea == G.play too right?
👀
uhhh right yea, usually you don't have to worry about the cardarea but now that i think about it context.individual triggers on e.g. steel and gold cards held in hand too
so the cardarea check keeps it to played cards
YIPEE
wait couldn't i do SMODS.has_enhancement(playing_card, 'enhancement key') for enhancements instead?
if you're looking for a specific enhancement, then yea that's better
the version i gave just checks if the card is enhanced with anything
light bump
makes sense, thank you!
i mean it would depend on what you want to do but i'm sure it's possible
i'm unclear on what you want here; is it that you want to automate the creation process so you don't have 15 different SMODS.Consumable { ... } definitions in your code?
Not the creation, but the buffing. Like the next hand has certain cards that they add 20 mult per each, and I don't want to make multiple sections for one card each.
i'm
more confused now
I want to define each consumable.
I want to define each one to buff certain cards.
I don't want to make individualized variables for each consumable.
you should be able to just put local variable = value outside of any SMODS.Consumable definitions, and then for the rest of that file you can use variable
Now is the second part: how do I set up each consumable to activate on different ids?
Not on just one, but like on a good few
i'd probably recommend having each consumable set a global variable to true when you use it, and then have the effects all trigger in your mod calculate function and reset the global variable to false
That's kinda what I was hoping against, but at least I can define one. Where should I define my variable anyway?
i'm still unclear on what this variable is supposed to do
it's just a base addmult variable
give an example of what one of these consumables would do, i think that'll help me understand
like one specific one
Upon use, one would add 20 mult per card of four letters for the next hand, as an example. Another would do three and a third would do five.
(Like fours, fives, nines, jacks, and kings)
ah i see
yea you can literally just define this variable in a file outside of any tables or SMODS.Somethings, as long as it's in the same file as wherever you're using the variable it's fine
like put it on line 1
So, how do I have the card activate on the certain ids?
you
check for the id
i'm sure there's a way to get a rank's name from the ID, and then there's a way to count how many characters are in a string
Can I do that in the consumable or no?
is this supposed to just trigger when you're holding the consumable, or do you want to be able to use it to "activate" it?
ok, you'll need to put in a bit of work but yes you can set it up like this
- set the consumable's
keep_on_usefunction to return true - the consumable should have its own variable that tracks whether it's active, initially set to false
- set the consumable's
usefunction to just set that active variable to true - set the consumable's
can_usefunction to only return true if the active variable is false - set the consumable's
calculatefunction to first check if the active variable is true. if it is, then do the calculation code and putSMODS.destroy_cards(card)right before the return function (don't worry, it'll still calculate fine even as it's being destroyed)
steps 1-4 are exactly the same for every consumable you have, which is why i suggested automating the definition a little bit
SMODS.Consumable {
key = "asdf",
set = "xiferp_Keyboard",
atlas = "Golden_Typewriter",
cost = 3,
pos = { x = 12, y = 5 },
unlocked = true,
discovered = true,
can_use = function(self, card)
return true
end,
use = function(self, card, area, copier)
G.GAME.xiferp_asdf_mult = (G.GAME.xiferp_asdf_mult or 0) + 5
end,
loc_txt = {
name = 'asdf',
text = {
'Adds +5 mult per Jack for',
'the hand after this is used',
},
},
}```
Here's one of the consumables I have, for ref
i gave you a rather detailed answer
I know
So, add a calculate function to this that does the buff and destroys the card?
as well as steps 1-4
How much of the other 4 steps have I covered?
...none of them
unsure of the error here but i may be missing something
im trying to set it up similar to how seltzer displays it's current retriggers but for the +Mult to change
what is the active variable?
if it's any help the joker's gimmic is that it's ult doubles every hand
have you considered checking how seltzer does it
https://github.com/nh6574/VanillaRemade/blob/main/src/jokers.lua#L2889
(you need "hands" to be a variable in the joker's config -> extra table, not a local variable. then the calculate function will change it for you and loc_vars just has to return the variable)
a variable that you make in the consumable's config -> extra table, which will indicate if the consumable is active or not
i got it preemtpively when i got online 🥀
anything specific to put or will just about anything do?
you can name it whatever you want. you are coding here, you have the power. as for the value:
- ...initially set to false
i think you may misunderstand but noted
the hands played wont be displayed, just the mult
yea my bad
but the point is that the calculate function will do the work of calculating how many hands have been played, the loc_vars function shouldn't be doing that at all
so can i still use a local variable to count the hands played
?
no
it needs to be a new variable you add to the config -> extra table
Can I just put if other_card.get_id() == 4 or 5 or 9 or 11 or 13?
no it'd have to be if other_card.get_id() == 4 or other_card.get_id() == 5 or ...
which is why i recommended getting the rank's name and then counting how many characters there are in it (which would also support crossmod ranks)
The crossmod thing I'm not immediately caring for, just want to make a clean mod now. making it multi-mod compatible is a secondary thing at the moment
so something like this?
nearly
loc_vars should be return { vars = { card.ability.mult * math.exp(card.ability.handsplayed) } } tho, going by your initial screenshot
hand on i think i was doing the doubling wrong
the crossmod thing is a bonus, the main benefit is not having to type out 5 sets of other_card:get_id() ==
at the very least do a local id = other_card:get_id() beforehand, then you can just do if id == 4 or id == 5 or ...
it should've been added handsplayed to itself
i'm pretty sure math.exp is e^x actually
to be clear, you want it to be mult * (2^handsplayed)?
yes exactly
i should probably make it start at 0 to return 1
ok yea
it'll actually just be card.ability.mult * (2 ^ card.ability.handsplayed), lua has a ^ operator
SMODS.Consumable {
key = "qwerty",
set = "xiferp_Keyboard",
atlas = "Golden_Typewriter",
cost = 3,
pos = { x = 12, y = 4 },
unlocked = true,
discovered = true,
keep_on_use = function(self, card)
return true
end,
can_use = function(self, card)
return true
end,
config = { extra = { yes_is_no = false } },
use = function(self, card, area)
G.GAME.xiferp_text_mult = (G.GAME.xiferp_text_mult or 0) + 10
end,
calculate = function(self, card, context)
if context.individual and context.cardarea == G.play and context.other_card.get_id() == (whatever) then
if card.ability.extra.yes_is_no = true and (G.GAME.xiferp_text_mult or 0) > 0 then
local give_mult = G.GAME.xiferp_text_mult or 0
SMODS.destroy_cards(card, nil, nil, true)
return { mult = give_mult }
end
end
end
end
}```
Like this?
getting there
still missing step 3 and 4
and you don't need the global variable anymore (unless you want it to stack where e.g. using a four-letter card and a five-letter card gives both bonuses on each played card that matches either 4 letters or 5 letters)
new issue
SMODS.Consumable {
key = "qwerty",
set = "xiferp_Keyboard",
atlas = "Golden_Typewriter",
cost = 3,
pos = { x = 12, y = 4 },
unlocked = true,
discovered = true,
config = { extra = { yes_is_no = false } },
keep_on_use = function(self, card)
if yes_is_no = false then
return true
end,
can_use = function(self, card)
return true
end,
use = function(self, card, area)
set yes_is_no = true
end,
calculate = function(self, card, context)
if context.individual and context.cardarea == G.play and context.other_card.get_id() == (whatever) then
if card.ability.extra.yes_is_no = true and (G.GAME.xiferp_text_mult or 0) > 0 then
G.GAME.xiferp_text_mult = (G.GAME.xiferp_text_mult or 0) + 10
local give_mult = G.GAME.xiferp_text_mult or 0
SMODS.destroy_cards(card, nil, nil, true)
return { mult = give_mult }
end
end
end
end
}```
Firstly, is this more like it?
and secondly, I just wanna be safe in case that comes up.
mult quadruples instead of doubling
I see 2 ^ 2, which may be your issue.
(card.ability.handsplayed)
no to be clear
if you're using the global variable
it will add more mult per played card if you use two consumables than if you just use 1
anyway for step 3: set isn't a thing. this is basic lua. literally just fucking card.ability.extra.yes_is_no = true
and you put step 4 in the wrong function (it should be in can_use, not keep_on_use), and it needs to be card.ability.extra.yes_is_no
loc_vars needs to just be return { vars = { card.ability.mult * card.ability.handsplayed } } then, since you're multiplying it by 2
did some other fixes, works perfect now tysm
SMODS.Consumable {
key = "qwerty",
set = "xiferp_Keyboard",
atlas = "Golden_Typewriter",
cost = 3,
pos = { x = 12, y = 4 },
unlocked = true,
discovered = true,
config = { extra = { yes_is_no = false } },
keep_on_use = function(self, card)
return true
end,
can_use = function(self, card)
if card.ability.extra.yes_is_no = false then
return true
end,
use = function(self, card, area)
card.ability.extra.yes_is_no = true
end,
calculate = function(self, card, context)
if context.individual and context.cardarea == G.play and context.other_card.get_id() == (whatever) then
if card.ability.extra.yes_is_no = true and (G.GAME.xiferp_text_mult or 0) > 0 then
G.GAME.xiferp_text_mult = (G.GAME.xiferp_text_mult or 0) + 10
local give_mult = G.GAME.xiferp_text_mult or 0
SMODS.destroy_cards(card, nil, nil, true)
return { mult = give_mult }
end
end
end
end
}
}```
Like so?
yes there you go
Also, what do I do for the variable itself?
Currectly it's just local variable = (exists) in my code
fucking christ
you know what you want to use that variable for, right? then use it where you want to use it
it exists, so you can use it
you're acting like there's a right or wrong answer when there isn't really
this is coding. you are the maker. you decide what to do with the variable
meta crash out
Then I'll set it to 0 to start off
real
i should probably step back at this point
recommended reading. just in general https://www.lua.org/manual/5.1/manual.html
no, just me being... me
I'm a Balatro player, I can't! /j (in all seriousness, I will.)
how did In do that ?
Anyone figured this out yet? Here’s the code I have so far.
if hand_chips + context.other_card.chips + card.ability.extra.chips_penalty < 0 then
penalty = -(hand_chips + context.other_card.chips)
end
return {
chips = penalty,
colour = G.C.CHIPS
}```
Or a snippet
didn't work, probably impossible
instead, can I make a booster pack unskippable?
i try something and it works!
in balatro multiplayer's giga standard pack, it has unskippable = true, as a parameter. could that work?
oh also you'll need to chuck in a hook, it isn't vanilla nor smods built in
local can_skip_ref = G.FUNCS.can_skip_booster
G.FUNCS.can_skip_booster = function(e)
if SMODS.OPENED_BOOSTER and SMODS.OPENED_BOOSTER.config.center.unskippable then
e.config.colour = G.C.UI.BACKGROUND_INACTIVE
e.config.button = nil
else
return can_skip_ref(e)
end
end
I'll figure this out soon enough...
How do I make it so if a joker is copied by blueprint or brainstorm, they can add xMult to the joker they're copying instead of themselves?
Yay
clean
Can someone help me with a joker that, each time a card is triggered:
adds 10 chips and plays a message,
adds 3 mult and plays a message,
multiplies mult by 1.1x and plays a message,
plays a final message with no modification
having the chips and mult apply hasn't been an issue for me but for some reason I can't get messages to play in sequence like this
for the first three messages, do you want it to be different from the usual "+10"/"+3 Mult"/"X1.1 Mult" messages?
Yeah, custom written ones
I plan to have sounds play with them as well but I figure once the messages are done that shouldn’t be too hard to figure out
gotcha
when you return from a calculate function, you can return an extra table in the return table. this extra table itself behaves like a return table, so you can have another extra table inside that. the extra table is calculated after the main table is calculated
for your purpose, you'd do something like this:
return {
chips = 10,
message = "Something",
extra = {
mult = 3,
message = "Something else",
extra = {
xmult = 1.1,
message = "A third thing",
extra = {
message = "A fourth thing"
}
}
}
}
and in each level, you can also have sound = "soundeffectkey" to play a custom sound
no problem
No, it would be chip_mod, mult_mod and Xmult_mod
ah dang it right
Is there a way to trigger a Joker's "on setting blind" context effect manually? With Modeling Clay (my Joker that changes effect each round) sometimes its effect can't trigger because it also changes its effect while setting the blind
-# it also acts weirdly with scaling jokers displaying nil values but that's a separate issue
( based on this implementation #⚙・modding-general message )
The previous joker or the current joker?
Ideally the one it just turned into
As in, setting blind -> change joker -> trigger setting blind effect of new joker
i think you can use SMODS.calculate_context and put appropriate stuff fot the context
It should do that if you're changing the joker first then triggering the joker.
Ooh, alright
I'll double check my code next time I'm working on it, just hopped off for the night
Ooh alright sweet, thanks! This'll help too most likely
No, that would trigger everything that happens in context.setting_blind again.
yea
what if
negative booster packs
temporarily adds a +1 booster slot when it was present
probably not possible in smods
how can i remove starting cards with a deck ?
like remove all the aces
I think theres something wrong with my version of balatro
How can I make another Joker other than Jimbo be the default for the Joker pool when it runs out?
Does that work for overriding the base Joker pool too? And not a custom one?
Yes.
Alright, thank you!
guys i worked hard on this :( /lh /nm
waw
how did you do that ?
thank you!!! they're essentially just playing card enhancements
I may or may not make this a whole thing
ow okay
What's the context.type equivalent of context.setting_blind?
Nothing, because it doesn't exist.
Can I find the possible context.types somewhere?
Also, tags only work with context.types and wouldn't work with just simply doing context.setting_blind, right?
Yes, they don't have normal contexts.
how do i get a card's edition?
card.edition.key
ty
How can I wait for the previous tag to finish? Now all tags are triggering at the same time and it completely bugs the game out:
key = "pool",
min_ante = 2,
pos = {
x = 4,
y = 2
},
loc_vars = function(self, info_queue, tag)
info_queue[#info_queue + 1] = G.P_CENTERS.p_pool_1
end,
loc_txt = {
name = "Pool Tag",
text = {"Gives a free", "{C:attention}Mega Pool Pack"}
},
apply = function(self, tag, context)
if context.type == 'immediate' then
local lock = tag.ID
G.CONTROLLER.locks[lock] = true
tag:yep('+', G.C.SECONDARY_SET.Spectral, function()
local booster = SMODS.create_card {
key = 'p_pool_1',
area = G.play
}
booster.T.x = G.play.T.x + G.play.T.w / 2 - G.CARD_W * 1.27 / 2
booster.T.y = G.play.T.y + G.play.T.h / 2 - G.CARD_H * 1.27 / 2
booster.T.w = G.CARD_W * 1.27
booster.T.h = G.CARD_H * 1.27
booster.cost = 0
booster.from_tag = true
G.FUNCS.use_card({
config = {
ref_table = booster
}
})
booster:start_materialize()
G.CONTROLLER.locks[lock] = nil
return true
end)
tag.triggered = true
return true
end
end,
in_pool = function(self, args)
return false
end
}```
Why aren't you using new_blind_choice?
my enhancement is not counting as a face card for jokers, how would I fix this?
Hook Card:is_face
lemme try
how do i do something to the hand at the end of round
like this?
Oh wow that works, thank you!
I thought that only triggered when skipping
No, it's Card:is_face(from_boss)
Why from_boss
A face card is only a face card when it is not debuffed, from_boss makes it so it doesn't check for debuff.
Should I do the same with get_id?
No, Card:get_ids only input is the card.
I see I see
I do wanna get better at hooking stuff cuz I barely have any clue about it

nvmd i think i found it
how would i use SMODS.add_card{} to give a random card from a specific mod
local cards = {}
for k, v in pairs(G.P_CENTERS) do
if v.original_mod and v.original_mod.id == 'modid' and (v.set == "Joker" or v.consumeable) then
table.insert(jokers, k)
end
end
local key = pseudorandom_element(cards, 'seed')
SMODS.add_card({key = key})
nope, am still confused
ideally for that use original_mod instead of mod, the latter is influenced by take_ownership (so usually not what you want)
if context.end_of_round and context.individual and context.cardarea == G.hand
okay
but i want to do smtn once to the hand, not per-card
or is context.individual the one for per-card
why did u add context.individual i said i DON'T want it to be per-card
if context.end_of_round and context.main_eval
G.hand.cards
How do I change the square color of the edition scoring message?
how can i get the mod that an enhancement is from just from the enhancement key?
G.P_CENTERS[key].original_mod
grand
add a colour entry to the return table
how do i make a rank that gives +1 mult instead of +1 chip ?
if context.post_joker or (context.main_scoring and context.cardarea == G.play) then
return {
colour = G.C.CSTORM.GREY,
x_chips = card.edition.x_chips
}
end
end```
crashes my game
what's the crash
I get this when hovering over the card
I found the error, it was in the description
I accidentally typed V: instead of X:
colour doesn't work though, the square is still the default color
what's the exact text you have
This is the calculate in my edition
Or what do you mean?
can you somehow make a card be scored 5 times every time its scored?
Do you mean retrigger?
I guess retriggering 5 times by itself could work
No, because the game would crash.
how do you do retriggers
nah, the text that isn't working as intended
the loc_txt or localization entry
if context.repetition and context.cardarea == G.play then return {repetitions = 5} end
wouldn't it be context.main_scoring instead of context.repetition
There is nothing wrong with that
No, it would be context.repetition
i dont understand context.repetition from the wiki explanation
It is a context that checks how many times a playing card should be retriggered.
would it trigger when I score it
cuz thats my intention
if it scores, it retriggers 5 times
Yes.
i will try it out I guess
what part of the game code handles planets leveling up hands?
is it the update_hand_text and level_up_hand?
okay great thanks
level_up_hand also uses update_hand_text normally
but SMODS.smart_level_up_hand doesnt do it when there isnt anything to update
okay thanks
Back to my question: How do I change the color of that square behind the text?
what do i need to put into target to lovely patch smods?
thanks
you said the bg colour doesn't work
close
target = '=[SMODS _ "file path"]'
ah
No, I said that I accidentally typed V: instead of X: and that using colour = in return doesn't change the color of the square (referencing #💻・modding-dev message)
is there a mod that adds new planet cards that add like 2x to chips or mult so i can check it out because i really dont understand how to use smart_level_up_hand
in base smods you can only just level up x times
Universum cryptid
you need to create a function yourself for doing like anything else
makes all planets double chips and mult
universum cryptid patches level_up_hand to change its behaviour while you have it
not a good example i would say
ah ok
oh okay thanks
[[patches]]
[patches.pattern]
target = '''=[SMODS _ "src/game_object.lua"]'''
pattern = '''
hand[self.key] = math.max(hand['s_'..self.key] + hand['l_'..self.key]*(hand.level - 1), 0)
'''
position = "at"
payload = '''
hand[self.key] = math.max(hand[self.key] + hand['l_'..self.key]*amount, 0)
'''
match_indent = true
times = 1
``` use this patch to stop hand stats from recalculating from base level every time they level up
true
(i have a PR open in SMODS that, among other things, stops hand stats recalculating from base level. need to make some requested changes and write some utility functions but it should hopefully be merged eventually)
yes
thanks
the timing's a little wonky here
it runs the add_card event and creates the new joker before cards are scored even though it's in context.after, but then runs destroy_cards at the right time
any thoughts?
how do i get what rank a card is?
ty
how would I access the number of vouchers in the shop as a variable?
what are you trying to do exactly?
tldr is a joker that has a chance to either add or remove a voucher from the shop. I'm trying to store the current number of vouchers so that I can make the change temporary
Try taking a look at the Voucher Tag. It adds another Voucher to the Shop; it might have some pointers for you.
have been doing so but the way it works doesn't let me remove a voucher
SMODS.change_voucher_limit(number) you can use this do increase/remove a voucher slot in shop
in a cards code is what is self and what is card?
or are they the same?
for example in a consumables use function
it is function(self, card)
self is the center, and card is the consumable.
Also, a suggestion building off of @true jasper's: calculate the increase/decrease chance before entering the shop.
youre creating an empty event currently, the event code to run should go into func in the event
yeah i got it, thanks though
Yo! Does anyone know any easy ways of messing around with shaders without having to reopen the game every 5 seconds?
Yes, DebugPlus
Splendid! How would I use it?
use 3 to spawn a joker (this requires empty slots)
ctrl+c will forcefully spawn a joker even if joker slots are full
in the console type watch shader Mods/your mod/assets/shaders/name.fs
it will automatically update whenever you modify the .fs file
oh that's SICK
Used watch lua when developing the mod config tabs.
what language are balatro shaders?
GLSL.
Hello friends! It's finally time for me to put together something I've been putting off for a while: The god of Time, Dialga
I tried to make it so it retriggers all played cards twice, but it's not working. Could someone help me fix this?
jf code is unreadable 😭
IM SORRY 😭 it was originally made with Jokerforge and I tried reformatting it but it evidently still looks like shite
this is insane knowledge for later, bless 🙏
is there a tutorial on making shaders for balatro?
i'd also like to know that
key = "qwefeqrgaergar",
set = "xiferp_Keyboard",
atlas = "Golden_Typewriter",
cost = 3,
pos = { x = 0, y = 0 },
unlocked = true,
discovered = true,
can_use = function(self, card)
return true
end,
loc_txt = {
name = 'qergwetgwqetgt',
text = {
'Gives 1 random card a random suit',
'and adds +5 chips to your next hand.',
},
},
use = function(self, card, area, copier)
G.GAME.xiferp_text_chips = (G.GAME.xiferp_text_chips or 0) + 5
calculate = function(self, card, context)
local suit = pseudorandom_element(G.GAME.suit, 'aniceoutfit')
local card_to_change = pseudorandom_element(G.hand.cards, 'shufflethedeck')
G.E_MANAGER:add_event(Event({
func = function()
SMODS.change_base(card_to_change, suit)
return true
end
}))
end
end
}```
Why isn't this applying a new suit?
G.GAME.suit isn't a thing
Well, what should I replace it with?
SMODS.Suit.obj_buffer
thank you, the both of you
and then you'll have to use suit.key in the change_base call
at least i don't think change_base can handle taking a whole suit object
so, just SMODS.suits?
what is the simplest shader in balatro
didn't work
Code?
key = "qwefeqrgaergar",
set = "xiferp_Keyboard",
atlas = "Golden_Typewriter",
cost = 3,
pos = { x = 0, y = 0 },
unlocked = true,
discovered = true,
can_use = function(self, card)
return true
end,
loc_txt = {
name = 'qergwetgwqetgt',
text = {
'Gives 1 random card a random suit',
'and adds +5 chips to your next hand.',
},
},
use = function(self, card, area, copier)
G.GAME.xiferp_text_chips = (G.GAME.xiferp_text_chips or 0) + 5
calculate = function(self, card, context)
local suit = pseudorandom_element(SMODS.Suit.obj_buffer, 'aniceoutfit')
local card_to_change = pseudorandom_element(G.hand.cards, 'shufflethedeck')
G.E_MANAGER:add_event(Event({
func = function()
SMODS.change_base(card_to_change, suit)
return true
end
}))
end
end
}```
Remove the calculate function.
Sure that'll work?
Yes.
cuz it still didn't
im a bit confused on why this keeps crashing
Code?
It's self, info_queue, card
well that's something i haven't realized yet, strict ordering
does anyone know how to make a custom info_queue message type
SMODS.Consumable {
key = "magnesium",
set = "xiferp_Element",
atlas = "Golden_Brick_Road",
cost = 3,
pos = { x = 0, y = 0 },
unlocked = true,
discovered = true,
can_use = function(self, card)
return true
end,
loc_txt = {
name = 'Magnesium',
text = {
'Gives 1 random card a random suit',
'and adds +5 chips to your next hand.',
},
},
use = function(self, card, area, copier)
G.GAME.xiferp_alkemetal_chips = (G.GAME.xiferp_alkemetal_chips or 0) + 5
local suit = pseudorandom_element(SMODS.Suit.obj_buffer,'aniceoutfit')
local card_to_change = pseudorandom_element(G.hand.cards, 'shufflethedeck')
G.E_MANAGER:add_event(Event({
func = function()
SMODS.change_base(card_to_change, suit)
return true
end
}))
end
}```
Here is the actual code
Well? Why isn;t it working?
i have a joker that changes the rank of cards before scoring, is it possible to make it re-evaluate the hand type?
When are you changing the ranks?
More accurately, how do I pick a random suit and apply it?
Have you tried printing suit and card_to_change?
no, but I do know the card_to_change code works. It's on another card that adds a random seal
context.before
iirc you could also pass SMODS.Suits to pseudorandom_element, though?
lemme check
Even though SMODS.Suits and SMODS.Ranks are unordered tables, it is possible to feed them directly into pseudorandom_element to get a random suit or rank while respecting in_pool. Example: local rank = pseudorandom_element(SMODS.Ranks, pseudoseed('myrank'))
Didn't seem to work...
local suit = pseudorandom_element(SMODS.Suits,'aniceoutfit')
stuck it in like this
add a debug print(suit) after that line to see if it's actually getting a suit
Add .key to the end.
it said 'Spades'
ok so it's not an issue with the pseudorandom call
revert back to how you had it when it printed spades
when are you using the consumable? during a blind?
anyone knows how to make a deck that starts with a specific joker?
config = {jokers = {'j_modprefix_key'}}
thanks! i'll take that into account
can anyone help me?
how do i matchmake in multiplayer balatro
all i can do is join directly to lobbys
you might want to ask that in #⚙・modding-general
idk
also what could i do here to make this more discreet, since cards that flip via the effect have a short period of time where they can be seen by the player:
SMODS.Back{
key = "GG_eclipsedeck",
atlas = "atlasholders",
pos = {
x = 4,
y = 2
},
loc_txt = {
name = "Eclipse Deck",
text = {
"Cards may be drawn face down",
"according to the amount of",
"hands left, {C:blue}+1{} hand",
"every round"
}
},
apply = function(self)
G.E_MANAGER:add_event(Event({trigger = "after",
func = function()
G.GAME.round_resets.hands = G.GAME.round_resets.hands + 1
return true
end,
}))
end,
calculate = function(self, deck, context)
if context.hand_drawn then
for k, v in pairs(context.hand_drawn) do
if v.facing ~= "back" and pseudorandom("eclipsedeck") < G.GAME.current_round.hands_left * 0.03 then
v:flip()
end
end
end
end
} ```
yeah. It's to buff a hand
how do you make the unlock requirement of a card be “win a run with this specific joker (for example Blueprint)”? I can’t remember for the life of me
Look up similar cards on VanillaRemade
are there any Vanilla cards where the unlock requirement is based on winning a run with a different joker? Am I tripping? I could have sworn there weren’t
nvm
check_for_unlock = function(self, args) return args.type == 'win_custom' and next(SMODS.find_card('j_modprefix_key')) end
cool, thanks. That was driving me crazy
use context.stay_flipped
return stay_flipped = true to draw a given card face down
basically, what I’m doing is making temporary upgrades of Vanilla jokers. If you happen to win a run with one in the upgraded state, you unlock the corresponding legendary version (usually the same effect but doesn’t downgrade back to the vanilla joker).
Is there a way to block all legendaries in a certain pool from spawning via The Soul until after they’ve been properly unlocked? I think I could do it with flags but if there’s another way to do it that doesn’t require hundreds of flags that would be nice
I'm trying to use it to buff the next hand
wait to be clear
is the issue that it's not changing the suit for a random card, or that it's not buffing the next hand?
because you literally have zero code to do the "buffing the next hand" part
Does this abide with individual cards or the entire hand? since I'm planning to make it where the deck uses pseudorandom + hands left to determine the chance of a card getting flipped
individual cards
The not changing cards part. The 'buffing next hand" is elsewhere, and works fine
ok i dunno then
neither do I, that's why I'm asking around
It achieved half of it, but how can I flip it back forward exactly using this context?
flipping back forward would have to be done during a seperate context
stay_flipped is only called once when a card is drawn
Could you demonstrate it perhaps?
well
idk what youre trying to do
i thought you only had to flip newly drawn cards for your thing
Yea, the deck would flip it similar to blinds like the wheel
But I am a bit puzzled why it unflipped the second hand and not the first
it should not unflip anything with context.stay_flipped
It seems to be unflipping rn since I'm testing it
did you remove the context.hand_drawn part
is there anything else that could mess with flipping cards or smth
<@&1133519078540185692>
Hello, does anyone know if I can make my flags affect vanilla cards?
For example: Wheel of fortune
1 in 4 to Foil, Holo or Poly -> 1 in 4 to Poly
SMODS.Consumable {
key = "magnesium",
set = "xiferp_Element",
atlas = "Golden_Brick_Road",
cost = 3,
pos = { x = 0, y = 0 },
unlocked = true,
discovered = true,
can_use = function(self, card)
return true
end,
loc_txt = {
name = 'Magnesium',
text = {
'Gives 1 random card a random suit',
'and adds +5 chips to your next hand.',
},
},
use = function(self, card, area, copier)
G.GAME.xiferp_alkemetal_chips = (G.GAME.xiferp_alkemetal_chips or 0) + 5
local suit = pseudorandom_element(SMODS.Suits, 'aniceoutfit')
print(suit)
local card_to_change = pseudorandom_element(G.hand.cards, 'shufflethedeck')
for i = 1, #G.hand.highlighted do
local percent = 1.15 - (i - 0.999) / (#G.hand.highlighted - 0.998) * 0.3
G.E_MANAGER:add_event(Event({
trigger = 'after',
delay = 0.15,
func = function()
card_to_change:flip()
return true
end
}))
end
G.E_MANAGER:add_event(Event({
trigger = 'after',
func = function()
SMODS.change_base(card_to_change, suit)
return true
end
}))
G.E_MANAGER:add_event(Event({
trigger = 'after',
delay = 0.15,
func = function()
card_to_change:flip()
return true
end
}))
end
}```
testing this version (with flips)
if you want to change the effects of existing things, use take_ownership https://github.com/Steamodded/smods/wiki/API-Documentation#taking-ownership
Yea ok, the cards seem to unflip improperly, I played a high card and the second concealed card was unflipped while the first one wasnt...
i'm trying to make a custom deck, but the deck's art always looks like checkered deck
any fix for this?
i defined the atlas
the key?
imma share it rq
I could try initial_scoring_step to ensure the played cards are unflipped?
Or is that the wrong context in this equation
cards are always unflipped when they are played
Some cards seem to not follow this rule, especially when some don't score
One last issue, how do I apply a suit to a card?
because SMODS.change_base(card_to_change, suit) isn't working, even though both variables are defined
then youre definitely doing something wrong lol
whats the code look like
It is very generic 🙏
?
Like basic
i just want to see the code vro
Ok sorry 😔
SMODS.Back{
key = "GG_eclipsedeck",
atlas = "atlasholders",
pos = {
x = 4,
y = 2
},
loc_txt = {
name = "Eclipse Deck",
text = {
"Cards may be drawn face down",
"according to the amount of",
"hands left, {C:blue}+1{} hand",
"every round"
}
},
apply = function(self)
G.E_MANAGER:add_event(Event({trigger = "after",
func = function()
G.GAME.round_resets.hands = G.GAME.round_resets.hands + 1
return true
end,
}))
end,
calculate = function(self, deck, context)
if context.stay_flipped then
if pseudorandom("eclipsedeck") < G.GAME.current_round.hands_left * 0.05 then
return {
stay_flipped = true
}
end
end
end
}```
hmmmmmmmmmmm
okay im just going to guess
do you have wierd face-down cards that are also like darker than normal
because im pretty sure those are like the wierd inbetween state of ghost cards and real cards where they can be selected/played but dont score or do anything
bump
well it could be since it doesnt do it when every card scores, but if its like a few cards that score, few dont, there are inconsistencies
i dunno if context.initial_scoring_step allows me to get the full hand so if thats the case, i could just run a for loop to skim through the cards for this
its context.full_hand i reckon so i could just use that if its available
Pastebin.com is the number one paste tool since 2002. Pastebin is a website where you can store text online for a set period of time.
ohhhh
Well it seems like it's working, small delay but it does seem remotely functional
I put the atlas field and nothing crashes, except the image doesn't show up
I already put hapodeck.png in both 1x and 2x
did you get the position right
hold on
I moved the position of the thing to 0 and now it "works"
jokers should be a table of keys
as in, i can see it, but it's like way smaller
and you dont need the apply to add the joker
did you put the correct image size
72 px 95 py
did you not accidentally mix up the 1x and 2x
do i need to shrink 1x down
what is the size of the actual image file
I finally found a fix and the deck FINALLY works
bump 2
disregard the previous message, I totally fixed it and didn't realize
polite bump
SMODS.Consumable:take_ownership('wheel_of_fortune',
{
I'm try but dont work
