#💻・modding-dev
1 messages · Page 686 of 1
correct for what? if you're just doing this in debugplus eval, you don't need additional checks. otherwise you need somewhere to put it, that condition alone doesn't help you
i do
always printing poker hands not would only result in lag, but also in a crash cause the table would be empty at game startup
correct for checking when is the poker hand displayed
debugplus has a console you can access at any time by pressing /
you can run eval any valid lua code in the console to run code
i'm not sure what exactly SMODS.displaying_scoring is used for, but i don't think it helps you if you're just evaling things?
my point was that, when the scoring was displayed, it would also print the poker hands table
you can just eval it in the console on G.hand.highlighted instead
eval doesn't help you run code at any specific timing other than through hooks
checking for SMODS.displaying_scoring will check if it's true right now and doesn't care about what happens sometime else
okay...
i feel like you're still missing the point that debugplus has a console where you can evaluate code at will
no no
i'm testing that
but
if you want to constantly display the info while hand is being selected, you want UI for this like I said
INFO - [G] > eval G.FUNCS.get_poker_hand_info(G.play.cards)
INFO - [G] < NULL, NULL, Table:
Flush House: Table:
Full House: Table:
top: Table:
Flush: Table:
Pair: Table:
Four of a Kind: Table:
Straight Flush: Table:
Straight: Table:
Three of a Kind: Table:
Flush Five: Table:
Two Pair: Table:
Five of a Kind: Table:
High Card: Table:
, Table:
, NULL
idk if i should evaluate it with G.play.cards as an argument
it returned all possible hands
but not just with my cards, with all cards
oh
you want G.hand.highlighted
G.play.cards only exists while a hand is being scored, if you run the code any time else it's empty
like i and aure said, you should do it with G.hand.highlighted instead, and that will get the poker hand info based on the hand you currently have selected
cards only move to G.play once you play them, otherwise it's empty
how do i display the description for a custom edition?
this isnt working, but idk why
ah okay
G.P_CENTERS.e_cotc_bane
ah, thx
^ editions have an e_ prefix, like jokers have a j_ prefix
Alr that's more reasonable but what do these values even mean
i see that the available poker hands have a table, and the other ones have an empty table
printing cards is usually unhelpful
as for what these are, each entry is an array of arrays of cards, each representing a possible instance of the hand
alr, that's hilarious
why did it even give me cards information on get_poker_hand_info. i assumed it would've returned smth like it is used here in src/overrides.lua:
local _, _, _, scoring_hand = G.FUNCS.get_poker_hand_info(cards)
then i could get the scoring_hand
i tried to evaluate it like this:
local _, _, _, scoring_hand = G.FUNCS.get_poker_hand_info(G.hand.highlighted)
I got nil
all you did was put its returns into local variables
you need to return the variable you want in the eval
assigning things to local variables does return nil
also you messed that codeblock up pretty bad
true, mb
yeah, idk why but discord somehow doesn't allow me to put multiple backticks
it's because you have unescaped _ making italics
discord likes to be extremely funky with those
crap
whatever
INFO - [G] > eval local pokerhand = G.FUNCS.get_poker_hand_info(G.hand.highlighted)
return pokerhand
INFO - [G] < Pair
yeeeey
at least i got the hand it should be played. it's the first argument of the table. no surprise
seems like it's a table containing a very big bunch of tables. that's not good
whatever
i'll focus on SMODS.PokerHandPart
does it not affect poker hand evaluation or am i just stupid
...and it also doesn't fully support poker hand calculation as far as i'm aware
-# - me
tysm
Hey guys. Do you know if I can make a deck give a tag at the beginning using the config like with vouchers?
I tried to use config = { tag = { 'tag_coupon' },, but it doesn't work. 😑
Add an event in apply function that gives a tag.
apply = function(self, back)
G.E_MANAGER:add_event(Event({
func = function()
if G.playing_cards then
add_tag(Tag('tag_coupon'))
play_sound('generic1', 0.9 + math.random()*0.1, 0.8)
play_sound('holo1', 0.4, 1)
return true
end
end,
}))
end,
for adding a Coupon Tag at start of run, as example.
yo can someone code a bossblind for me? The Curse: Each hand, (ante/1.25+1)X Blind size. Mult: (1/ante+1), Dollars: (ante * 5)
Hey, thanks. Will try it out. ❤️
can someone help me understand the booster pack background colour?
vremade uses G.STATES and i see cryptid using G.C but i dont know how to make either of those work for me
i have the custom colours i want to use, i just dont know how to write it properly
the G.STATES stuff only works with vanilla stuff, it will be of no use here
for custom colors, here's what you do
ease_background_colour = function(self)
ease_colour(G.C.DYN_UI.MAIN, CUSTOM_COLOR_HERE)
ease_background_colour { new_colour = CUSTOM_COLOR_HERE, special_colour = G.C.BLACK, contrast = 2 }
end
replace CUSTOM_COLOR_HERE with whatever color you want. for the simplest way to go about it, you can literally just use HEX("FF00FF") with any hex color code; cryptid saves them in G.C but that's not strictly necessary, it's only a time save for if you use the color in a lot of places and you end up wanting to change it
Ah okay, so does that just mean G.C is just another form of G.ARGS.LOC_COLOURS?
No, G.ARGS.LOC_COLOURS is for colours that you can use in descriptions.
Well shit then
In that case, is there any way i could translate the custome colours in the first pic to be G.C or smth just so i can make this easier?
you don't need to put them in G.C
if you're only going to use it for the booster you could define a local variable before the call to SMODS.Booster for example
Or just pass HEX('FFFFFF') directly.
ease_background_colour({ new_colour = HEX("515966"), special_colour = HEX("121417"), contrast = 1.25 })
also works.
...hm? i thought HEX() only took 8-digit hex codes
last time i did a 6-digit hex code, i got a crash
¯_(ツ)_/¯
function HEX(hex)
if #hex <= 6 then hex = hex.."FF" end
local _,_,r,g,b,a = hex:find('(%x%x)(%x%x)(%x%x)(%x%x)')
local color = {tonumber(r,16)/255,tonumber(g,16)/255,tonumber(b,16)/255,tonumber(a,16)/255 or 255}
return color
end
Been using 6-digit since i started tbh, havent had any issues
Hell, didnt even know it could use 8-digit till like 2 months ago

heya folks, was wondering if anyone knew how to check if a played poker hand contains a certain enhancement? i'm doing it with custom one but even just knowing if it has a stone card for example will do lol
the final goal is to check for a pair with at least one card having whatever enhancement
i've seen mods with poker hands having stone cards and stuff before so i know it should be possible
just not sure where to look
if context.scoring_name == 'Pair' then
local passed = false
for k, v in pairs(context.scoring_hand) do
if SMODS.has_enhancement(v, 'm_modprefix_key') then
passed = true
end
end
if passed then
end
end
i think i found it my own way lol
looked at how cryptid does stone card hands
but thx :)
he's real
No, you should be using SMODS.has_enhancement not checking card.config.center.key
ah i see
would this be in the evaluate for the poker hand?
this is what I have currently
evaluate = function(parts,hand)
if next(parts._2) then
print("SB -- is pair")
local settebello = false
local _pair = parts._2
for _,v in ipairs(_pair) do
print(#_pair)
for i = 1, #v do
print("SB -- ", v[i].base.value)
print("SB -- ", v[i].config.center_key)
settebello = settebello or v[i].config.center_key == 'm_sb_settebello'
end
end
if settebello then
return parts._2
else return {} end
end
end
new to modding balatro so i'm figuring it out as i go really
local ret = {}
for k, v in pairs(parts._2) do
for kk, vv in pairs(v) do
if SMODS.has_enhancement(vv, 'm_modprefix_key') then
table.insert(ret, v)
break
end
end
end
return ret
ahhh
i think when i tried to do it like that before i forgot that there's another level down in the arrays
thanks very much :)
...how do i iterate through every card in the deck again? 
for k, v in pairs(G.playing_cards) do
end
how do i differentiate between cards that are out (i.e. in G.play.cards for booster, G.hand.cards for blind) and cards that are... uh, not (discarded, undrawn)
if card.area ~= G.deck and card.area ~= G.discard
sanity check: localize{ type = 'name_text', key = 'e_foil', set = 'Edition' }?
Yes.
why do jokers i add show up in the shop even if i own them? I haven't added anything that would make that happen so is there something i need to add to make it so they can't show up multiple times?
Are you spawning your jokers using DebugPlus? If so, that's why.
is that seriously the issue? dang well thanks
ok so its weird, I have a card that's spawn a negative and after one that spawn a normal one but why does the second one dont spawn
Code?
for the overcharge if context.giga_pre_joker and context.cardarea == G.play then return { func = function() for _ = 1, self.config.extra.tarot + math.floor(Giga.discarded_overcharge() / 4) do if SMODS.pseudorandom_probability(card, pseudoseed('giga_orangeovercharge'), self.config.extra.odds, self.config.extra.chances) then G.GAME.consumeable_buffer = G.GAME.consumeable_buffer + 1 G.E_MANAGER:add_event(Event({ func = function () SMODS.add_card({set = 'Tarot', edition = 'e_negative'}) G.GAME.consumeable_buffer = 0 return true end })) SMODS.calculate_effect({ message = localize("k_plus_tarot"), colour = G.C.PURPLE }, card) else if #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({ func = function () SMODS.add_card({set = 'Tarot'}) G.GAME.consumeable_buffer = 0 return true end })) SMODS.calculate_effect({ message = localize("k_plus_tarot"), colour = G.C.PURPLE }, card) end end end return true end } end
for the potteryif context.destroy_card and context.cardarea == G.play and context.destroy_card == card and SMODS.pseudorandom_probability(card, pseudoseed('giga_pottery'), card.ability.extra.odds, card.ability.extra.chances) then return { func = function() if #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({ func = function () SMODS.add_card({set = 'Giga_Artefact'}) G.GAME.consumeable_buffer = 0 return true end })) SMODS.calculate_effect({ message = localize("k_plus_artefact"), colour = HEX('444444FF') }, card) end return true end, remove = true } end
you shouldn't be adding to the consumeable buffer when you create the negative card
that causes the pottery to think that there won't be any room, even though there will
how to make the game update what poker hand you're making when you move cards instead of just selecting/deselecting
how can I tell if a card is generated in the collection
if card.area and card.area.config.collection
thx
Is there ways to manipulate the calculation process mid-calculation?
As two examples of what I mean:
- A joker that changes the card scoring to happen upon the joker itself scoring instead (so that scoring starts at held-in-hand, then scores jokers until it reaches this joker, in which case it scores your cards, and then continues scoring the rest of the jokers to the right of this one)
- A joker that skips scoring the joker to the right (different from a debuff since its only blocking the "context.cardarea == G.jokers and context.joker_main" context on the joker to the right)
For the first one you would hook SMODS.calculate_main_scoring and end it early if context.cardarea == G.play and call it when the joker is triggered with the context, for the second one you would hook eval_card and end it early if context.joker_main
Oh wow, super cool that this is possible at all
What would hooking SMODS.calculate_main_scoring look like?
I know I can hook like this:
local old_main_scoring_func = SMODS.calculate_main_scoring
function SMODS.calulcate_main_scoring(context, scoring_hand)
--Some Code here to do prior
old_main_scoring_func(context, scoring_hand)
--Some Code here to do after
end
But, it sounds like you're suggesting here to modify something mid-function, and I'm not sure where I would go about doing that
for mid-function modifications, you'd have to use a lovely patch
ahh okay I'll have to look into that ty
No, you would just put if next(SMODS.find_card('j_modprefix_key')) and context.cardarea == G.play then return nil end before calling the original function.
man i wsih there's likje ways to pin these
i dont have a use for it right now but it would be so good to have it for later
forward to an alt
or another server
For the first example, could I just hook eval_card, skip and cache anything where context.cardarea == G.play and then call the cache when the card is that joker?
I'm trying to write down anything I see that sounds useful and make a git-hosted html site with common questions on it to make it easier to find answers to questions
yeah thats what i wanted to do but with not as much effort as you
I've not gotten very far and it might be ambitious, so..
I'm not sure how well itll turn out lol
like i dont have any concepts or ideas for mechanics that'd use this function right now
fun, fact, a site like this already exists
is there still a proper way now to detect if a badge is your own mod's badge? i used to check DynaText.string but that doesnt seem to be working anymore as it creates a bunch of extra dynatext in the top left
vremade wiki
eh
No, you would hook SMODS.calculate_main_scoring and call it when the joker triggers like I said.
if its not on there make a pr
Ahhh so, is SMODS.calculate_main_scoring something that is called multiple times?
(also, is there a good source for figuring out the different methods you can hook onto and what they do?)
Yes, it's called once for each scoring playing card card area.
awesome tysm I'll write that down
You can hook every function except the functions that run before your file is loaded.
Yeah but, figuring out WHAT the methods do I was wondering how one would do that?
tried looking at the SMODS github documentation but didnt see anything about SMODS.calculate_main_scoring
i mean I don't see why you couldn't hook those too
they just won't affect anything before yoru file
I don't see any results at all for googling/duckduckgoing this
putting "vremade" in quotes to specifically search for that term is just not showing anything
(is it a typo?)
vanillaremade
yeah doing shortform isnt gonna show up
Ahhhh gotcha thank you
to be fair we did not make that clear
I feel so dumb most the time lol, I feel like I barely know what I'm doing or whats going on
New to modding, and modding balatro, and new to some of the enviornments (like navigating github wikis), so I think I'm missing a lot of common knowledge
to be fair the common knowledge is very badly documented
like github wiki is terrible at being a wiki
I got a whole lot of C# programming experience, so, I'm working off of mostly JUST that (which is vastly different from lua), and skimming through examples and discord history
I really appreciate the people here, yall been like, very very helpful
and most of the answers you'd want are lost in the logs of this chat
Yeah I want to make the information more accessible for people
so honestly your best bet to find any answer is first check vanillaremade, then Ctrl+F in this chat
most of the time it worked for me
but then if something isnt there i just ask here, so it exist in this channel
not ideal but it's the best we have for now
thats pretty much what I've been doing so far lol, sometimes the searching is hard to hit a balance between specific enough to address my problem instead of 100s of others, and un-specific enough to be something that people actually had help with before in the discord
Looking at this on the vanilla remade wiki and Yeahhhh I think I just need to start using VSCode instead of just Visual Studio, because it looks like all the setup is for that, and aside from some of the plugins that help me with C# programming, its basically just a fancy colored notepad without any context menus or anything lol
well no
this is showing you how to set up the Lua environment IF you're using vscode or any vscode-based editor
but like you can very well use your preferred editor, ive seen some use notepad++ or heck even normal notepad
the lua environment setup is just to aid you with syntax autofil and basic debugging
Well yeah, thats what I'm saying missing has been a huge pain
i mean if you're gonna start now then get vscodium maybe
surely a lua plugin is avaiable
im still using vscode just because i dont want to setup everything anew
but like for all i know use atom that's a perfectly good ide
vscodium is just a vscode fork i think
But debloated
so most things should be similar
yea, and that debloat helps a lot from what i know
like im doing fine but there are some noticable chugs as it's trying to present its copilot bullshit on me
Awesome ty for the suggestion I'll check it out
Just a question
Do I need to worry about assigning anything to my mods global table mixing with other mods? Or are each mods given their own enviornment?
mods are not given their own environment, no
but accidental overlap is rare. just give your table a reasonably unique name and not like, MyMod
just set your mod object to a global table named with your mod id
example with mine: Sagatro = SMODS.current_mod
it's just that simple
Weakness
Decreases rank of up to 2 selected cards by 1
can someone help me with the art
please
i dont know how to draw
can you please stop posting the same message in multiple channels in very short succession? most people in the community look at all the modding channels anyway, and anyone who only looks at one channel is doing so for a reason
sorry
I was just wondering in the case of making my own helper functions. I wanted to avoid typing a long table name each time
But, perhaps I can do something like this at the top of whatever files:
local D = DISHEVELED (where DISHEVELED is my mod table that contains all my helper functions and whatnot)
then anywhere in the file I could just do
D.something() instead of DISHEVELED.something()
unless there is some issue I have not forseen here with doing something like that
that should work fine, yeah
cool cool ty
tables and functions in lua are always references
if you know pointers in C, it's pretty much similar
local D = DISHEVELED basically makes D refer to whatever DISHEVELED is referring to
If I wanted to make a Riff-Raff clone for modded Jokers, is there a parameter I could use for add_card to specify what mod it should pull from?
if it's just for your own mod, you should just add an attribute to all your modded jokers and then use SMODS.poll_object to get the key of a random joker with that attribute
what if it's not
that's trickier
but SMODS.poll_object takes a really cool filter function that should help. poll for a generic joker, and then use the filter function to remove objects from the pool if they're not from the relevant mod(s) you care about
https://github.com/Steamodded/smods/wiki/Weight-System#smodspoll_objectargs---stringnil
woah
something like this:
SMODS.poll_object {
...
filter = function(pool)
local new_pool = {}
for i, v in ipairs(pool) do
if G.P_CENTERS[v.key].original_mod.id == whatever then
new_pool[#new_pool + 1] = v
end
end
return new_pool
end,
...
}
This is a reference
its streangth but opposite(thats why its just streangth with inverted color and changed text)
is there a way to make consumeables in a booster pack not need to be instantly used?
cause i have alot of custom stuff that cant really be intantly used like that
select_card = 'consumeables'
ah, thx
oh, now that that exists i should implement it in my mod packs
how did you do the thousands separtor with the xmult
you mean the commas? that's just built into the game
???
what version are yu playing
is it not???
i know damn well i didnt do anything on purpose to make it happen
i know it's the most recent, that's all
at the time of that screenie, i gave myself a shit ton of money to make sure i could afford the booster packs for repeated testing
i did nothing to actually make the commas, it's just like that
...wut
Yeah my game gets commas for numbers like that too, just by default.
uhhhhhhh
can i ask how a tarot that adds mult makes any sense
Make it keep on use, so the use button turns into an “activate/deactivate” button instead
And then, when it triggers on your coming hand, it deletes itself
Oh neat
Ty
Took inspo from the combo cards in ColdBeans
im making google translate balatro because ive lost control of my life
im sure this has been done already but i dont care
i mean like come on
SMODS.Consumable {
key = 'powerplay',
set = 'Spectral',
atlas = 'RTD',
pos = { x = 0, y = 0 },
soul_pos = { x = 1, y = 0 },
hidden = true,
soul_set = 'Mannpower',
use = function(self, card, area, copier)
for i = 1, #G.jokers do
G.E_MANAGER:add_event(Event({
trigger = 'after',
delay = 0.4,
func = function()
play_sound('timpani')
local editionless_jokers = SMODS.Edition:get_edition_cards(G.jokers, true)
for i2 = 1, #editionless_jokers do
local edition = 'e_negative'
editionless_jokers[i]:set_edition(edition, true)
end
check_for_unlock({ type = 'have_edition' })
card:juice_up(0.3, 0.5)
return true
end
}))
delay(0.6)
end
for i, playing_card in ipairs(G.playing_cards) do
local editionless_cards = SMODS.Edition:get_edition_cards(G.playing_cards, true)
for i2 = 1, #editionless_cards do
local edition = 'e_polychrome'
editionless_cards[i]:set_edition(edition, true)
end
end
end,
can_use = function(self, card)
return next(SMODS.Edition:get_edition_cards(G.jokers, true))
end,
}
SMODS.Edition:get_edition_cards only works with card areas.
Okay now it's not crashing, but it doesn't do anything when used
sanity check: ```lua
SMODS.change_base(card, pseudorandom_element(SMODS.Suit), pseudorandom_element(SMODS.Rank))
i forget whether the smods suits/ranks classes are singular or plural
plural, but you'll want to do pseudorandom_element(SMODS.Suits).key (and the same with ranks)
change_base takes just the key, while SMODS.Suits and SMODS.Ranks contain the whole suit and rank objects
This is looping endlessly, is there an easy way to fix that?
if card.ability.extra.active == true then
print("istrue")
if context.money_altered and context.amount > 0 then
print("money1")
card.ability.extra.money = context.amount
card.ability.extra.active = false
print("money2")
end
end
if card.ability.extra.active == false then
ease_dollars(card.ability.extra.money)
end
elaborate on "looping endlessly" and show more info about where this code is written
Oh okay!
So that code is within calculate on a joker
SMODS.Joker {
key = 'hyperdrive',
loc_txt = {
name = 'Hyper Space',
text = { "Double $","Double Blind" }
},
atlas = "Jokers",
rarity = 1,
cost = 4,
unlocked = true,
discovered = true,
blueprint_compat = true,
eternal_compat = false,
perishable_compat = true,
pos = { x = 0, y = 3 },
config = { extra = { money = 0, active = true } },
loc_vars = function(self, info_queue, center)
return { vars = { center.ability.extra.money, center.ability.extra.active } }
end,
calculate = function(self, card, context)
if card.ability.extra.active == true then
if context.money_altered and context.amount > 0 then
card.ability.extra.money = context.amount
card.ability.extra.active = false
end
end
if card.ability.extra.active == false then
ease_dollars(card.ability.extra.money)
end
end
}
And Im assuming its and endless loop because this was me attempting to fix it seeing itself add money which was causing a endless loop of adding money and crashing the game. and this is crashing the game the same way
no crash report game just closes
Just trying to double any money a player would gain lol
calculate = function(self, card, context)
if context.money_altered and card.ability.extra.active then
card.ability.extra.active = false
ease_dollars(context.amount)
card.ability.extra.active = true
end
end
try this instead?
Tried to open a pack I made and it crashed with this
im lost
Hey this worked wonders!
Thanks heeps!
no problem!
I'm lost too, you can't just post code and expect us to know what the issue is
I'm trying to have this joker apply negative and a sticker as well as squaring its values if possible
doesn't seem to work properly from what I've seen
the sticker is fine but applying the edition and squaring values is the issue
Im not the best at wording this kinda stuff so
yeah
you haven't really explained which part isn't working, but never store card objects in ability tables like you did with card.ability.choice = chosen_joker
ic
How would i go about getting a random card in hand?
pseudorandom_element(G.hand.cards, 'seed')
Thanks!
I've gotten to here
calculate = function(self, card, context)
if context.individual and context.cardarea == G.play and context.other_card:get_id() == 12 then
print("SEX")
card.ability.extra.death_card = pseudorandom_element(G.hand.cards)
if card.ability.extra.death_card then
G.E_MANAGER:add_event(Event({
func = function()
SMODS.add_card{ set = "Base", rank = "Jack"}
SMODS.destroy_cards(card.ability.extra.death_card, nil, true)
return true
end
}))
end
end
end
But if playing like 3 of a kind queens, they all destory the same card. Is there a way to make them each randomise what they destroy?
...you shouldn't destroy cards like such mid-scoring. Consider tagging the randomly selected card in your existing check.
local rndcard = pseudorandom_element(G.hand.cards)
rndcard.slayqueen = true
and then checking against context.destroy_card.
if context.destroy_card and context.destroy_card.slayqueen then return { remove = true } end
i'm planning out a showman-esque joker that also gives 1xmult for every duplicate held. what's the most efficient way to check how many duplicate jokers exist in G.jokers.cards? 
e.g. if you have say, 2 blueprints and 2 brainstorms, that would be x3 mult (because 2 duplicates after x1 base)
off the top of my head, i think
local existing_joker_keys = {}
local dupeCount = 0
for _, jkr in ipairs(G.jokers.cards) do
if existing_joker_keys[jkr.config.center.key] then
dupeCount = dupeCount + 1
else
existing_joker_keys[jkr.config.center.key] = true
end
end
and i can't help but wonder if that feels stupid or if that's the correct way to do that
or at least, there's no better way to do that
I won't say for sure that it's the best method (you never know with coding), but that is how I'd do it.
mixing camelCase and snake_case for variable names should be against the modding rules
i blame steamodded, i used to only write camelCase but ever since i started doing PRs, snake_case has wormed its way into my cursed-ass coding """""philosophy"""""
camelCase is natural to me but 😭
although i have written worse
Swag
Is there a way to make playing a hand cost 2 hands instead of just doing -1 twice in quick succession
note to self: look into "misprint but hands"
first thing that comes to mind is to patch state_events.lua, in G.FUNCS.play_cards_from_highlighted and then take the part where it goes ease_hands_played(-1) and then mess with that, write some conditional so that normally it does -1, but when it meets your condition, it does -2
Ok
oh you're going to hate my code
theres a project i'm working on that uses both js and python
i originally kept the cases seperate
i guarantee you there is no code worse than mine 
but at one point I gave up
I have a camel cased python function being passed a snake_case function being assigned to PascalCase variable
several times
@rapid stag 
still better than other things i've written
still better than other things i've written
If an event plays mid-hand does that halt everything that's going on until the event is done
I had to present this to judges
with a straight face
under pressure
bad code is funny and all
until suddenly its not just your bad code
what exactly am i walking through if i do
for _, card in ipairs(SMODS.merge_lists{
G.jokers.highlighted or {},
G.consumeables.highlighted or {}
}) do
-- what is card
end
so if i'm holding a fool, would card end up being the fool directly or would it be a table with the fool in it
try it and see!!!!
what is causing this in the main menu top left
the only thing i can link this to is that all of the text that ends up here are name fields of entries i'm adding to info_queue
how are you adding them
via code i patch into generate_card_ui just before the recursion loop at the end, that passes info_queue among other things into a mod function
are you creating ui elements directly
or using one of the balatro functions like create_something
no, i'm just adding { key = 'key', set = 'Other' } to the info queue
tbh idk, maybe you're adding stuff to info_queue too early
or it's not the info_queue stuff in the first place
how can i grab the level of the currently played hand? this is my current attempt:
if context.post_joker or (context.main_scoring and context.cardarea == G.play) then
card.ability.extra.mult = G.GAME.hands[handname].level
print (card.ability.extra.mult)
end
end```
replace handname with context.scoring_name
thanks 👍
this does give me an idea for a PR though
i made a mod that can choosing level and multiply into Blind Chips , but when I test , all the decks convert into Red Deck , how can i fix it?
blind size multiplication at run start? isn't that plasma's doing?
||tiếng Anh hơi trôn, giải thích bằng tiếng Việt cũng đc, ko có gì hết||
send an mp4 next time, I don't wanna download it just to watch once
||cái này hơi nâng cao rồi, rốt cuộc bro muốn thêm ascension vào game mà ko phải là stake à||
hello, whats the event for when consumable is bought?
context.buying_card and context.card.ability.consumeable
Thanks!
đúng r bro , tôi ms hc code nên ko có nhiều kinh nghiệm cho mấy cái này , nhưng cái lỗi đấy là sao v
||mới học code mà đã bay vào code thứ cao siêu
||
how would you make a custom rank give something like mult instead of chips?
is there a place where i could search up whatever event i want to use and not just ask here bothering you?
Hook Card:get_chip_bonus and Card:get_chip_mult
there are not that many context checks, for example what if i want a context check that runs things only when blind is selected?
context.setting_blind
yea, so is there a place where all those context checks are put together?
thì làm mod để tự nghịch cho vui mà , ai biết nó phức tạp thế 
có cách nào để fix ko
hey is joker forge even good
||phức tạp thì
thôi, ko cho xem code biết đường nào mà giúp||
gửi code ra chat riêng đc k
||ở đây cũng không vấn đề gì, người khác cũng có thể giúp nếu cần||
Thank!
Anyone know why this is crashing?
SMODS.Blind {
key = "greatfilter",
loc_txt = {name = "The Great Filter", text = {"Debuffs Most Played Hand"}},
dollars = 8,
mult = 2,
pos = { x = 0, y = 7 },
boss = { showdown = true },
boss_colour = HEX("e34244"),
debuff = {hand = { [G.GAME.current_round.most_played_poker_hand] = true }},
}
||sao lại nhảy về menu trực tiếp thế, code này là dở rồi|| 😭
setting G.STATE directly is bad practice
thế viết như thế nào?
||gọi thẳng UI chọn độ khó gì gì đó luôn, mắc gì hook vào Game.update bắt nó kiểm tra từng frame||
còn chỗ nào nữa không
||bỏ hook kia đi, rồi sửa lại G.FUNCS.reopen_fide_selector thành:||
G.FUNCS.reopen_fide_selector = function(e)
local profile = G.PROFILES[G.SETTINGS.profile]
if profile and G.STATE == G.STATES.MENU then
profile.fide_setup_complete = false
G.FUNCS.overlay_menu{definition = create_fide_selector_ui(), config = { align = "cm", type = "full" }}
end
end
it means it's not recommended to use global mult to access the mult parameter
I dont think im doing that
Code?
calculate = function(self,card, context)
local has_whimsy = false
for _, playing_card in ipairs(G.playing_cards or {}) do
if SMODS.has_enhancement(playing_card, 'm_zwp_whimsical') then
has_whimsy = true
end
end
if has_whimsy == false then
if context.joker_main and
SMODS.pseudorandom_probability(card, 'zwp_coin', 1, card.ability.extra.odds) then
return {
x_mult = card.ability.extra.xmult1
}
else
return{
x_mult = card.ability.extra.xmult2
}
end
end
end
thats the calculate
if i give myself the joker then enter a blind it crashes with that
you did not gatekeep your logic with a context
it fires at any context, which is not good
ah
ok
so I should only call anything in there when joker.main is the context
thank you
in this case
It should be: ```lua
if context.joker_main then
if SMODS.pseudorandom_probability(card, 'zwp_coin', 1, card.ability.extra.odds) then
return {
x_mult = card.ability.extra.xmult1
}
else
return{
x_mult = card.ability.extra.xmult2
}
end
end
yep and there's also a list of contexts with descriptions for when to use them here: https://github.com/Steamodded/smods/wiki/Calculate-Functions#contexts
cool thanks
nó vẫn lỗi red deck bro ơi :((( có cần lovely diagos ko
||vấn đề là không biết lỗi red deck ở đâu kìa 😭||
Hay do cấu hình máy yếu
||cấu hình máy liên quan gì
||
Tưởng nó phk load mod , máy có 4gb ram mở phát lag banh máy
||4gb ram trong năm 26 lớn
||
||vấn đề ở đây là đống code không có vẻ gì sẽ đụng chạm đến phần bộ bài, nói chung là vẫn đang bí đây
||
Làm phiền bro tốn tg xem code ngại quá
we all speak English here
this guy is an exception, he isn't very good at it so I asked him to talk in Vietnamese
at least that takes less efforts out of my comprehension skill
nothing will ever be funnier than running anyhting through google translate a shit ton
I am sorry if i disturbed anyone
dont worry, you're good
how do you juice up the table operator
hi people
i'm trying to make some individual assets for my jokers
however, they look blurry, especially the 1x version (which you can see by disabling pixel art smoothing). I exported with GIMP, with compression set to 0
why does that happen?
even discord renders them blurry. in GIMP they look sharp, since they're just pixels
these are the 2x versions, which i scaled down to get the previous ones
SMODS.Atlas{
key = 'SuspiciousJoker',
path = 'SuspiciousJoker.png',
px = 71,
py = 95
}
SMODS.Atlas{
key = 'FunnyJoker',
path = 'FunnyJoker.png',
px = 71,
py = 95
}
These are my atlases
its been goin crazy
probably happened when you were scaling them
look for anti aliasing and select nearest neighbor somewhere
uhhh
if gimp had antialiasing...
maybe try a different program
im certain it does but yk
i use libresprite usually
i only have interpolation on scaling settings
set it to none
already did
hm
these are my export settings btw
developing a mod without DebugPlus is a bold choice
doing this with libresprite didn't help either
these don't look like they have any anti-aliasing problems
what can it be then?
if you zoom in, you'll notice that my modded joker looks blurry
oh hm you're right
https://github.com/Renzo-MGRR/Planetarian I'm sharing the github just in case discord did some reencoding with the sprites I sent
right? wth
they're straight up pixels on a low res image
also, does the 2x one look right to you?
the 2x looks right I think, though a bit hard to tell on mobile
bluratro
@median veldt @frosty dock apparently it's an issue with malverk???
oh huh
it only happens if i start the game with malverk and pixel art smoothing enabled, and then i disable pixel art smoothing
I checked them in aseprite, no blurring problem whatsoever 😭
if i start the game with pixel art smoothing disabled but with malverk enabled, they show fine anyways
it also blurs vanilla jokers a bit, but it's not that noticeable
i downloaded it but i see no issues in log
type eval G.GAME.viewed_back:change_to(G.P_CENTERS.b_blue)
@wintry solar any idea why?
I have no idea, it shouldn’t touch actual draw code
what is the applied.fs shader used for?
does red deck change to blue deck
if not, that's the main problem - the method is corrupted by an unknown cause
is main.lua your entire codebase?
if it is, check the code of the other mod you installed
yes, it turn blue

The menu
This is with Malverk enabled
And this is without
@frosty dock i'm on latest DEV smods. can this be affecting how malverk works?
I'm not overly familiar with malverk, but I don't think it would
Also something I notice, is that with malverk installed, atlases load much quicker, but seems like the atlases aren't changing, but rather the resolution of the sprites and then they're rescaled, i assume?
this would explain why vanilla jokers aren't blurred much and mine is, since my atlas has a lower resolution
Malverk shouldn’t touch any atlas stuff that isn’t run through its system either
yeah. it's very weird
@frosty dock i downgraded smods to 1501a, and that """fixed""" it
so i think it's an smods issue?
I thought it only happened with malverk?
yes
with malverk enabled, but downgrading smods fixed it
then it might be caused by a smods change but is still a malverk issue
the issue only happens when i have latest smods an malverk at the same time
that would make sense
should i, for the moment, make an sprite of the same res as vanilla jokers so at least they look in line with the game?
I don't see how that affects things
.
.
the difference is probably that vanilla sprites aren't loaded through SMODS.Atlas
ah
Just speculating though, I'd have to look closer into this to say more
alr, if u want to, and when u got some time on your pc, you can look at it, it would help me :)
1501a still works with Malverk enabled?
work... in the sense that it just loads?
That it did what you expect with the sprites
oh no, actually i'm wrong
i did a bit more of testing
1501a doesn't change anything
i also notice that it doesn't even apply pixel art smoothing ON sometimes
you can tell it's still 1x, specially cause the atlases inject insanely fast
i wish it just worked. it's such a weird issue, and i'm suprising no one ever noticed this
probably much people don't test their 1x sprites with malverk installed
it's definitely a malverk issue, but idk why
is there a way to add lines to loc_txt.text during the game?
make it equal to another variable instead of predefining it
or patch your own code
it might imply reloading tho
jokers that scale do this, so you might want to look at something like hologram
Oh! Like
local someArray = {'1','2','3'}
Then in SMODS.Joker:
loc_txt = { text = someArray, ...
Then I can just add or remove from that array and itll update properly?
Maybe
I'm not sure, try it first
This depends on how SMODS handles it
that does not appear to work
how would you make a custom rank show different text
chat quick sanity check for an idea about interactions between two jokers
imagine two idols like jokers
one pick a card completely randomly, like idol does
the other goes through a predetermined sequence of card
would it be possible to make it so that if you have both of these jokers together, the random one stops being random and also starts going down the same sequence
and would you be able to make this effects the vanilla jokers, like idol, castle, etc
have you checked vanillaremade
👍
i'll probably add blinds based off ts
also i'll use my current jokerforge mod as the template
oh
but the blinds i will add myself
since jokerforge has no support for blinds
you're just gotta start actually coding for those
unfortunately or fortunately, whichever one applies
https://github.com/nh6574/VanillaRemade/tree/main/src this should have everything
oh ok
like if you need the basics of making something of a particular object type i would honestly just yoink one from here and modify it
technically everything in a mod can be in one file
but also it's going to be a pain to find things if your mod gets particularly big
ig i'm not using jokerforge anymore
i would recommend start separating code files out earlier than later but it's not required
the main "mod" folder has separate folders for enhancements, seals n whatnot
do i just make a blind folder orrr
anything you're comfortable with
because ideally it will be the structure you want to work with for the rest of the development
some people including me personally goes as far as making one file per one card so everything is fully modular but again there's upsides and downsides
what do you reccomend i use for editing .lua files
k
really it is just a fancy text file that has a bit that tells your pc to read it as code
its going to be a bit weird working without jf
so even notepad works (but also dont who in their right mind would do this)
but jf was a crutch
fun fact: i used notepad to make the Mineral text a specific color
ok
i have
if SMODS.pseudorandom_probability(self, "wheeloffortune_sailboat_blind",self.config.numer, self.config.denum) and not context.other_card:is_face() then return { .... }
how can i make the part in the return{} debuff the card
my game crashes when use my consumable
SMODS.Blind{ key = "the_sailboat", dollars = 5, mult = 2, boss_colour = HEX("a7e8d6"), atlas = 'Blinds', boss = {min = 3}, pos = { x = 0, y = 1 }, config = { numer = 1, denum = 5, }, in_pool = function(self) return true end, loc_vars = function (self) local n, d = SMODS.get_probability_vars(self, self.config.numer, self.config.denum, "wheeloffortune_sailboat_blind") return { vars = { n, d } } end, collection_loc_vars = function (self) local n, d = SMODS.get_probability_vars(self, self.config.numer, self.config.denum, "wheeloffortune_sailboat_blind") return { vars = { n, d } } end, calculate = function (self, blind, context) if context.hand_drawn and not blind.disabled and context.other_card then if SMODS.pseudorandom_probability(self, "wheeloffortune_sailboat_blind",self.config.numer, self.config.denum) and not context.other_card:is_face() then context.other_card:set_debuff(true) end end end }
would this code work
how would you make a rank show a custom message when scored
rank calculate? 👀
among other things, yeah
unfortunately it lives among the forsaken features that are best added after quantum ranks
wouldnt it be easier to build quantum ranks around that
instead of editing it to support it in the future
it's too massive as a single feature
Is there a simple way to un-redeem a voucher?
that seems like something spectrallib would add (unconfirmed)
confirmed
if you make your mod depend on spectrallib, you can just call card:unredeem(), where card is a voucher card object that you own
ok so natively there's no way to do it
not unless you wanna copy all this code into your own mod (this entire file is required for unredeeming to work and look nice)
https://github.com/SpectralPack/Spectrallib/blob/ceeaf1e1fb2667fd0ef1c3346ef4fa2cce5ee87f/Cryptlib/unredeem.lua
thanks
So Card:unredeem calls Spectrallib.update_used_vouchers(), which is definied nowhere in the whole library?
so obv it crashes
oh my god bruh
😬
i also checked cryptlib just in case, no sign of update_used_vouchers either
it's literally just like 6 lines from cryptid
i'll take care of it
tbh i think i'll just put the code in directly, it's the only place that function is called and it's small enough
-- Prion
SMODS.Joker({
key = "prion",
config = { extra = { odds = 2 } },
loc_txt = {
["name"] = "Prion",
["text"] = {
{
"Discards have a {C:green}#1# in #2#{} chance to {C:attention}destroy{} the card",
}
},
},
pos = { x = 4, y = 8 },
cost = 9,
rarity = 3,
blueprint_compat = false,
eternal_compat = true,
perishable_compat = true,
unlocked = true,
discovered = false,
atlas = "CustomJokers",
loc_vars = function(self, info_queue, card)
local numerator, denominator = SMODS.get_probability_vars(card, 1, card.ability.extra.odds,
'j_hatch_prion')
return { vars = { numerator, denominator } }
end,
calculate = function(self, card, context)
if context.discard then
if SMODS.pseudorandom_probability(card, 'j_hatch_prion', 1, card.ability.extra.odds) then
SMODS.destroy_cards(context.discard, nil, nil, true)
return {
message = "Destroyed!",
colour = G.C.RED,
}
end
end
end
})```
how would i make this work? firstly i think the wording is slightly flawed
yeah i did just replace the function call by the function's code
secondly, when i discard a card, it gives an error of "cards not defined"
wait i didnt know you have commit access to spectrallib
context.discard is not a card object first of all
o whoops
second you can just add remove = true to the return
oke
i don't, i'm just gonna open a PR
oh
hi meta i missed u
ya go ahead
hiiii how are you
wait what file is this in cryptid codebase is so ass 😭
im ok i think i need to fix prion's odds
1 in 2 chance to destroy a discarded card is absurdly good
maybe ill have that be for divine prion instead
why tf is the file called modifiers.lua
in spectrallib the function call is in Cryptlib/unredeem.lua
thanks cryptid
but yea the function itself is lib/modifiers.lua in cryptid lol
this is just after a few rounds lol
erm
unredeem doesnt seem to work
elaborate
show code
for k, v in pairs(G.vouchers.cards) do
if v.config.center_key == "v_telescope" then
print("here")
v:unredeem()
return
end
end```
hrm
when you return two things with default messages how do you only silence one of them
eh it's fine i can deal without removing the voucher
so if you have multiple jokers that have the same unlock condition, are they unlocked in the same order they're loaded?
i.e., you do ```lua
SMODS.Joker{ key = 'one', ... }
SMODS.Joker{ key = 'two', ... }
if i had to take a guess, i think the first joker that appears in a list is unlocked first
but i could be wrong
-- Green Card
SMODS.Joker({
key = "greencard",
loc_txt = {
["name"] = "Green Card",
["text"] = {
{
"Create a {C:green}Sephirot{} card",
"when {C:attention}Blind{} is skipped"
}
},
},
pos = { x = 5, y = 8 },
cost = 9,
rarity = 3,
blueprint_compat = true,
eternal_compat = true,
perishable_compat = true,
unlocked = true,
discovered = false,
atlas = "CustomJokers",
calculate = function(self, card, context)
if context.skip_blind and not context.blueprint then
return {
G.E_MANAGER:add_event(Event({
func = function()
SMODS.add_card {
set = 'Sephirot',
}
G.GAME.consumeable_buffer = 0
return true
end
}))}
end
end
})```
got an undefined ipairs error
nvm its a bad argument
i still dunno how to solve it
@frosty dock is unlock_condition undocumented? I see it commented on vanilla remade as being an equivalent for check_for_unlock function
okay, but how is it used? which arguments should be passed into it?
in my case, i only want the joker to be able to be purchased only if five of a kind is visible.
i'm already using SMODS.is_poker_hand_visible('Five of a Kind') but I can't do it for the entire SMODS.Joker function since the game hasn't been initialized yet
what is in_pool, and how should it be used?
in_pool = function(self, args) in the joker
It returns true if the joker should be able to spawn
ah alr
why is this not documented tho?
It is
where?
Its just not listed specifically for jokers
Its listed with pos, atlas, unlocked with a link to the common parameters section in some other page
question
whats up
ah alr
it actually is too, my bad
i expected it to be a parameter cause i'm stupid
oh wait right
bump
quick question
how do all of you not be stupid
it took me HOURS to get something this simple to actually work
did u watch the tutorials?
how can i make a blind destroy cards}
i assume you do it w/ context.destroy_card
playing card
still
yes i have seen tutorials?
it just takes me so long to actually figure out
how to do stuff
you can make a boss blind destroy cards w/ context.destroy_card, right?
whats the intended effect here?
You can indeed do this
i have a boss blind that does smth similar
-- The Axe
SMODS.Blind {
key = "hatch_axe",
dollars = 5,
mult = 2,
pos = { x = 0, y = 0 },
boss = { min = 2 },
boss_colour = HEX("b6315e"),
atlas = 'CustomBlinds',
loc_txt = {
['name'] = 'The Axe',
['text'] = {
[1] = 'Destroy first played card',
[2] = 'after every played hand',
},
},
calculate = function(self, blind, context)
if not blind.disabled then
if context.destroy_card and context.destroy_card.should_destroy then
return { remove = true }
end
if context.individual and context.cardarea == G.play then
context.other_card.should_destroy = false
if context.other_card == context.scoring_hand[1] then
context.other_card.should_destroy = true
return {
message = "Destroyed!"
}
end
end
end
end
}```
this may help
Blinds have access to most contexts
This is lowkey kinda janky of a solution
Because you can just check if its the first in the destroy_card check
Rather than setting a flag
How would I got about adding a tooltip about a deck? I tried info_queue[#info_queue+1] = {type = "descriptions", set = "Back", key = "b_tboj_judas", vars = {"+1","-1"}} but it doesn't show the description, just the name
yeah but what about the variables
Doing it via the center will actually call the center's loc_vars for this
Thats like the whole point of using the center
that's a very broad description
you can use context.before, which is when space joker triggers
if you want to do any scoring, you should use context.initial_scoring_step, which is immediately after space joker triggers
or you can use context.press_play, which is the instant you click the play button
if you would direct your attention to the documentation,
https://github.com/Steamodded/smods/wiki/Calculate-Functions
thx
This doesn't do anything for some reason
your for loops should use G.jokers.cards and G.hand.cards, not just G.jokers and G.hand
both of the for loops are just entirely getting skipped over
need a fresh pair of eyes
got this error
in response to this code
im unsure what i did wrong here
all the others seem to be fine
nvm lmao
do you get this error with a fresh instance of the joker
its fine i found out i didnt add the config to divine space joker
i fixed it either way
guys
any idea why non unlocked modded jokers can crash when you put the cursor above them?
[SMODS _ "src/utils.lua"]:2639: attempt to index field 'control' (a nil value)
hello
might be an error related to your code specifically. it says "control" is undefined... did you forget to add it to your config extra?
that explains a bit but
is control a parameter inside SMODS.Joker?
is control the name of a variable of yours
nope
All poker hands matter! Contribute to Renzo-MGRR/Planetarian development by creating an account on GitHub.
it happened with HilariousJoker
Try making all of the entry keys in your localization lowercase.
okay...?
but why?
Because your error is in a localization function.
same thing
isn't there a way to lock a joker with debugplus?
i ended up doing it with a save editor. now i set the unlock text to ??? on purpose
in case you need lines 20-47
SMODS.Blind {
key = "the_laceration",
dollars = 6,
mult = 1.8,
pos = { x = 0, y = 0 },
boss = { min = 5 },
boss_colour = HEX("751a47"),
atlas = 'Blinds',
loc_txt = {
['name'] = 'The Laceration',
['text'] = {
[1] = 'Destroy first played hand',
},
},
calculate = function(self, blind, context)
if G.GAME.hands_played == 0 then
for _, card in ipairs(cards) do
card:start_dissolve()
return {
message = "Destroyed!"
}
end
end
end
end
}```
You have an extra end
Also please use context.destroy_card (https://github.com/Steamodded/smods/wiki/Calculate-Functions#contextdestroy_card) or your blind will very aggressively destroy cards all the time until something is played.
do i replace card:start_dissolve with context.destroycard or
No, it would be:
if context.destroy_card and context.cardarea == G.play and G.GAME.current_round.hands_played == 1 then
return {
remove = true,
message = 'Destroyed!'
}
end
going to test it. you will be credited when V2 comes out!
istg if this is another syntax error
yes. look at the error
It is. What's your code now?
don't you have the lua extension for visual studio?
it will tell you if you have syntax errors
check the vanillaremade wiki :3
in the visual studio extensions menu (ctrl + shift + x)
get the one from sumneko
i just did
-- The Laceration
SMODS.Blind {
key = "the_laceration",
dollars = 6,
mult = 1.8,
pos = { x = 0, y = 0 },
boss = { min = 5 },
boss_colour = HEX("751a47"),
atlas = 'Blinds',
loc_txt = {
['name'] = 'The Laceration',
['text'] = {
[1] = 'Destroy first played hand',
},
},
calculate = function(self, blind, context)
if context.destroy_card and context.cardarea == G.play and G.GAME.current_round.hands_played == 1 then
return {
remove = true,
message = 'Destroyed!'
}
end
}
you must end loc_txt
loc_txt = {
['name'] = 'The Laceration',
['text'] = {
[1] = 'Destroy first played hand',
},
}
end,
That is false, because loc_txt is set to a table and not a function.
You're missing an end for calculate
ah
mb
where the hell does the game store the amount of hands you've played
G.GAME.current_round.hands_played
balatro save editors doesn't seem to find that neither on meta.jkr, profile.jkr nor settings.jkr
i'm talking about the actual file for profile stats
Oh ok
G.PROFILES[G.SETTINGS.profile].hand_usage.FiveofaKind.count codewise
i want to set my five of a kind hands to 0 so then i can test if my joker unlocks properly
omfg 💔
--The Sailboat
SMODS.Blind{
key = "the_sailboat",
dollars = 5,
mult = 2,
boss_colour = HEX("a7e8d6"),
atlas = 'Blinds',
boss = {min = 3},
pos = { x = 0, y = 1 },
config = {
numer = 1,
denum = 5,
},
in_pool = function(self)
return true
end,
loc_vars = function (self)
local n, d = SMODS.get_probability_vars(self, self.config.numer, self.config.denum, "wheeloffortune_sailboat_blind")
return {
vars = {
n, d
}
}
end,
collection_loc_vars = function (self)
local n, d = SMODS.get_probability_vars(self, self.config.numer, self.config.denum, "wheeloffortune_sailboat_blind")
return {
vars = {
n, d
}
}
end,
calculate = function (self, blind, context)
if context.hand_drawn and not blind.disabled then
for i, card in ipairs(context.hand_drawn) do
if not card:is_face(true) and SMODS.pseudorandom_probability(self, "wheeloffortune_sailboat_blind",self.config.numer, self.config.denum) then
context.other_card:set_debuff(true)
end
end
end
end
end
}```
seems like it is profile.jkr. i found one that parses played hands properly
You added an extra end at the bottom again.
and it looks beautiful btw
so if i just do SMODS.poll_edition{options = { 'e_polychrome' }} will that do just a roll for poly at the default chance of getting poly when normally rolling editions?
the boss blind had no description
Yes. You would need to specify guaranteed = true to always get an edition out of it.
but i want to roll against base or poly with the same poly chance you would expect normally
pretty sure guarantee rules out base
That's what I meant. As long as you don't include guaranteed = true it'll work how you want.
i think i'm starting to get the hang of this
in a custom back's calculate, is back:juice_up() possible? does that work to juice a back 
why would you want to juice a back?
No, it would be (G.deck.cards[1] or G.deck):juice_up()
oh yeah 
but yea, the effect you may want is to juice the first card in deck or the deck area itself
the Back object is simply sprite on the back plus some calculations
alright, i got a new puzzle i need you to help me figure out
you know how you can go up/down ranks with SMODS.modify_rank() and it wraps to a 2 when you +1 amount to an ace, and to an ace when you -1 with a 2?
what's an easy way to do this, but for suits?
you're not going to believe this
well actually you might, but
it turns out that even before i threw snake_case into the mix, i was already using a mix of PascalCase and camelCase 
i just noticed, going through one of my files 
i also have instances where camelCase_and_snake_case are mixed in individual variable names
local function modify_suit(card, amount, manual_sprites)
local other_suit
for k, v in pairs(SMODS.Suit.obj_buffer) do
if v == card.base.suit then
if amount > 0 then
for i=1, amount do
if k+1 > #SMODS.Suit.obj_buffer then
k = 1
other_suit = SMODS.Suit.obj_buffer[1]
else
k = k+1
other_suit = SMODS.Suit.obj_buffer[k+1]
end
end
else
for i=1, -amount do
if k <= 1 then
k = #SMODS.Suit.obj_buffer
other_suit = SMODS.Suit.obj_buffer[#SMODS.Suit.obj_buffer]
else
k = k-1
other_suit = SMODS.Suit.obj_buffer[k-1]
end
end
end
end
end
return SMODS.change_base(card, other_suit, nil, manual_sprites)
end
if i want to make it so that a particular range of card do not get sorted by the hand sorting function, do i have to hook the sorting function or can it be done in simpler ways
why does this error occur when i try to start a second game in multiplayer balatro? i would really like it to not crash on the second game, multiplayer compat would be ideal\
normally i ask questions for a mod here, thought was valid to put it here
If I had to hazard a guess, it's that that versions of smods and multiplayer you're using aren't compatible
1.0.7-beta is from almost a year ago
makes sense, my mod has to be on a higher verison where weights are easily modifyable (1531b)+ i think
even updated multiplayer still has similar errors tho. ah well its an annoyance, its only on the second round so you get 1 round then it crashes which is wierd
is G.C.ORANGE actually a color that exists?
its G.C.FILTER right(?)
it's a color yes
i still changed to filter just in case and it doesnt work any better
very nice, thank you. you know, this would make a great smods util function
although in that case it'd probably need to more closely mirror the behaviour parts of modify_rank so those things can translate where applicable
ok this works
remove the space after the comma
localize parsing simply doesn't work with space
Hi everyone. Do you know if this is enough to ban a joker for a deck?
G.GAME.banned_keys['j_mail'] = true
end```
it should
omg, thanks for answering.
All the _mod keys feed a custom message into a specific message return to emulate vanilla, I see you’ve found the solution but I figured a bit of context would be good to share too
sure
it just felt weird to me because as far as i knew _mod keys were to replace the message with whatever you want your message to be, didn't think it'd ignore the colour
ig it took blue instead of red because mult happens before chips and chips override the mult's red?
the weird thing was when i added remove_default_message and it still didn't work with _mod lol
but eh whatev, i found the thing that works that's all i care about lul
Wait no nvm I am getting myself confused you are correct
I have no idea why it’s blue lol
time to fix it 
Oh I know what it is
The function that actually displays messages adds colours and sounds based on certain keys being present
and completely ignores the "colour" key? 😭
wait it's specifically with chip_mod? bruh
friendship ended with _mod keys (it never started)
anyone can explain why everything is nil apparently?
function newWeapon(key, badge, cost, config, loc_vars, update_values, use, pos, can_use, replicatable, has_soul)
pos = pos or {x = 0, y = 0}
badg = nil
if badge ~= nil then
badg = function(self, card, badges) badges[1] = create_badge(localize(badge), HEX("e62314"), nil, 1.2) end
end
can_use = can_use or function(self, card, area) return true end
use = use or function(self, card, area) apply_weapon(card.ability.extra) end
if replicatable == nil then replicataable = true end
if has_soul == nil then has_soul = false end
SMODS.Consumable({
object_type = "Consumable",
atlas = "weapons",
key = key,
set = "Weapon",
config = config,
loc_vars = loc_vars,
pos = pos,
soul_pos = has_soul and {x = pos.x, y = pos.y + 1} or nil,
cost = cost,
unlocked = true,
discovered = false,
use = use,
can_use = can_use,
update_values = update_values,
set_card_type_badge = badg
})
if replicatable then -- todo: add in BookOfLifeDrop pool
end
end
newWeapon(
"soulcard_purify",
nil,
10,
{extra = {chips = 250, event = "on_joker", interations = 5}},
function(self, info_queue, card)
return {
card.ability.extra.interations,
card.ability.extra.chips
}
end,
function(self, card, area)
card.ability.extra.chips = card.ability.extra.chips * G.GAME.blind.ante
end,
nil,
{ x = 2, y = 2 },
nil,
true,
true
)
Why are you making cards like this
your loc vars return should be return { vars = { ... } }
rn you don't have the vars part
temporary just for space efficiency
oh
yea thanks that works
you could extend SMODS.Consumable
like how
idk how i just know you can ;-;
noted
revisited the patch request, i believe i done it right
Extend Consumable to give it all the defaults you need in your new type, I can find some code a little later for you
i can handle the actual uno stuff on my end, i copied over the uno consumable code
altho sure
-# i already have the atlas on my end
Sorry that wasn’t to you
awww
newWeapon = SMODS.Consumable:extend{
atlas = "modprefix_weapons", --atlas default in extending must have prefix
set = "Weapon",
}
this allows you to call newWeapon like you would SMODS.Consumable but with the set new default parameters
you can also add a cost and other stuff you want to be consistent across all the consumables
Thank
WHY THE FUCK IS IT DOING THAT
it would really help if we had any clue as to what your doing
i just hovered over my joker i believe or smth
omfg i cant even send the code because of nitro
???
I dont need to entire file just the joker definition
honestly just the config and loc_vars
oh
loc_vars = function(self, info_queue, card)
local new_numerator, new_denominator = SMODS.get_probability_vars(card, CellarGrowthSize, card.ability.extra.odds, 'j_wheeloffortune_cellargrowth')
return {vars = {card.ability.extra.CellarGrowthSize, new_numerator, new_denominator}}
end,
calculate = function(self, card, context)
if context.after and context.cardarea == G.jokers then
if true then
if SMODS.pseudorandom_probability(card, 'group_0_624dccf3', 1, card.ability.extra.odds, 'j_wheeloffortune_cellargrowth', false) then
SMODS.calculate_effect({func = function()
local target_joker = card
if target_joker then
target_joker.getting_sliced = true
G.E_MANAGER:add_event(Event({
func = function()
target_joker:start_dissolve({G.C.RED}, nil, 1.6)
return true
end
}))
card_eval_status_text(context.blueprint_card or card, 'extra', nil, nil, nil, {message = "Destroyed!", colour = G.C.RED})
end
return true
end}, card)
end
end
end
if context.cardarea == G.jokers and context.joker_main then
return {
x_chips = card.ability.extra.CellarGrowthSize
}
end
if context.skip_blind then
return {
func = function()
card.ability.extra.CellarGrowthSize = (card.ability.extra.CellarGrowthSize) + 1
return true
end
}
end
end
}```
sorry if the code sucks
i was originally making this shitty mod with joker forge
is CellarGrowthSize a global or a card attribute
if its an attribute you forgot card.ability.extra. in the SMODS.get_proability_vars
okay. it crashed again when i tried to view it in the collection mid-run
in case you need line 41
is there a way to have multiple soul_pos layers on one joker
local new_numerator, new_denominator = SMODS.get_probability_vars(card, CellarGrowthSize, card.ability.extra.odds, card.ability.extra, 'j_wheeloffortune_cellargrowth')
return {vars = {card.ability.extra.CellarGrowthSize, new_numerator, new_denominator}}```
drawSteps
No, they meant it would be card.ability.extra.CellarGrowthSize instead of CellarGrowthSize
can you elaborate
ive never understood drawsteps
me neither i just copied smods code ;-;
look into the floating sprite drawstep

last time i stole from spectrallib it didn't work 
OH MY GOD MY FUCKING MOD IS FALLING APART
how possible is it to like. give a certain rarity of cards a shader
i know nothing about shaders so i might not go this route but
very possible
how Easy
you just need a custom drawstep that checks for the rarity of the card and then draws the shader
you could copy the edition drawstep and change a few things around very simply
ok genuinely what am i doing wrong here
my only guess is k_EX but that seems odd considering the pool is bex_EX
Try k_bex_ex
kk give me a few minutes i left home
worked
omfg 💔
wait
does the code not work if there's a space before it
pretend theres a space here
--like this```
Just send the code
send the code for the specific thing thats causing the crash
wait does this work
nvm that excludes some parts
this is the complete code of the tarot card i used that caused the game to crash
Currently, this applies Polychrome to the cards in your hand and then crashes the game.
actually, follow up to this -
with modify_rank, if i want something to move one rank at a time towards a specific rank, i can lay out the ids 2 to 14 - and check both the id's value and half-2 if the amount should go down rather than up
but how do i quantify that with suits, while potentially accounting for modded suits? how do i find the shortest direction from suit A to suit B?
what's the crash
which line is 19
editionless_jokers[i]:set_edition(edition, true)
well i is your first loop's iterating value and i2 is your second loop's. is that intentional for your effect or
Yeah, because I'm specifically looking for Jokers without an Edition
you're using i instead of i2 for the second loop
if i'm reading this correctly,
(5) Lua field 'func' at file 'src/mannpower/PowerPlay.lua:33' (from mod with id mannpower)
which if i'm reading your code right, should be local editionless_cards = SMODS.Edition:get_edition_cards(G.hand, true)
...which doesn't make sense to me as i don't get why card_area would be nil in that case
To find the (jokers/cards in hand) first and then go through specifically those without an Edition
that's not what that's doing, though
you're just looking for all editionless jokers and cards in hand as many times as there are total jokers and total cards in hand respectively
the loop reads as "first joker. let's look for all editionless jokers and give them the edition. done. second joker. let's look for all editionless jokers and give them the edition. done. third joker..."
i don't know the exact effect you want for this consumable, but based on the code you've shown, don't you want something more like
use = function(self, card, area, copier)
for i = 1, #G.jokers.cards do
if not G.jokers.cards[i].edition then
G.E_MANAGER:add_event(Event({
trigger = 'after',
delay = 0.4,
func = function()
play_sound('timpani')
G.jokers.cards[i]:set_edition('e_negative', true)
check_for_unlock({ type = 'have_edition' })
card:juice_up(0.3, 0.5)
return true
end
}))
delay(0.6)
end
end
for i, playing_card in ipairs(G.hand.cards) do
if not playing_card.edition then
G.E_MANAGER:add_event(Event({
trigger = 'after',
delay = 0.4,
func = function()
playing_card:set_edition('e_polychrome', true)
check_for_unlock({ type = 'have_edition' })
card:juice_up(0.3, 0.5)
return true
end,
}))
end
end
end
anyway, bump
is there a way to make some spectrals illegal to spawn normally (like the soul)
you could add them to G.GAME.banned_keys
so for the soul, you'd do G.GAME.banned_keys.c_soul = true
and i just plop this into main.lua
no
you would have to have this happen at the start of a run
although it didn't occur to me that you might want it as a general blanket ban all the time
yeah thats what im trying to do
trying to have it appear in certain booster packs and never appear anywhere else, like the soul
hmmmmmm
Is it possible to detect if a played card will score and make something happen before scoring starts if it will
context.before?
paired with context.individual maybe?
i have my own question. how do i check if a given joker key exists at all
if G.P_CENTERS[key]
You could calculate it without triggering it but that would still trigger things that don't happen in a return.
solve the halting problem for my joker
this effect is part of a deck where the effect is simply +4 mult after all scoring. why is it that it just doesn't give any if another +mult effect triggers before the deck's?
...
trigger_effect = function(self, args)
if args.context == "final_scoring_step" then
args.mult = args.mult + self.config.mult
update_hand_text({delay = 0}, {mult = args.mult})
G.E_MANAGER:add_event(Event({
func = (function()
play_sound("multhit1", 1, 1)
play_sound("tarot1", 1.5)
attention_text({
scale = 1.4, text = "+"..self.config.mult.." Mult", hold = 2, align = "cm", offset = { x = 0,y = -2.7 }, major = G.play
})
return true
end)
}))
end
end
...
most code is copied straight from plasma if it wasn't obvious
calculate = function(self, back, context)
if context.final_scoring_step then
return {mult = 4}
end
end
speed face
you cannot be serious 😭
thanks mr. somethingcom
actually i take that back nvm
not the thank you a deleted message 💔
trigger_effect in the big 26
i saw it used on some other deck and thought "it must be common!"
guess i was wrong
anyway good night
To add an enhancement to the game do you just put the design on an empty card?
Yes.
Oh ok
I guess this means the ranks and suits are layered on top of the cards rather than being the cards themselves
that is correct
I have a deck idea but no idea of how it could be implemented:
- consumables may appear with editions
- editions don't increase buy value
Im trying to make a joker that when you sell it, the joker to its right scores a +30 chip bonus every hand kinda like the foil edition, I think there is something wrong with the hook because i cannot get it to score the bonus but i can see that the chip bonus variable gets stored in the target joker
calculate_joker is a method of the Card class, SMODS has nothing to do with it
also the hook is far from being correct in the first place
how should i do it or what resources should i take a look at, first time doing hooks
is it possible to return loc colours inside of loc vars (e.g. "{C:mult}" if something is false and "{C:green}" if true )
if so how cuz its not working
return {vars = {colours = {colour}}}
SMODS.Joker{
...,
calculate = function(self, card, context)
if context.selling_self then
-- get target joker
local other_joker = nil
for i = 1, #G.jokers.cards do
if G.jokers.cards[i] == card then
other_joker = G.jokers.cards[i + 1]
break
end
end
-- nil check in case this joker is sold while at rightmost
if other_joker then
-- use a unique key here, extra is not recommended as for some vanilla jokers this is a number, not a table
other_joker.ability.soy_chips = (other_joker.ability.soy_chips or 0) + card.ability.extra.chips_add
end
end
end,
}
local calculate_joker_ref = Card.calculate_joker
function Card:calculate_joker(context)
local o, t = calculate_joker_ref(self, context)
if context.joker_main and self.ability.soy_chips then
o = SMODS.merge_effects{o or {}, {chips = self.ability.soy_chips}}
end
return o, t
end
when doing hooks, be careful about the return values as you may discard all values starting from the second one onwards
e.g. Card.calculate_joker returns 2 values
omg, thank you so much
this is just the backend tho
it's recommended that you add a tooltip to the joker that gained chips
yeah, ill try to figure that out
bump
i'm mainly just confused because like
there's no defined "order" for suits
techniocally suits have display order (used in hand & deck), and you have SMODS.Suits with all suits
there is tho
when you sort your hand by suit it's always the same order
suit order in vanilla code actually is inconsistent
😭
it's reverse order in RNG or whatever
when using debugplus with vanilla suits, when you go "right" one rank through the full lot, it's always hearts -> diamonds -> spades -> clubs
or is it "left"
either way, the principle's still the same
In hand diamonds always last
is there like. something i can crossreference to make a drawstep that draws a shader over every joker of a specific rarity
"cycling" suits inherently doesn't make much sense
agreed
well the deck also displays an order for suits. from top to bottom, it always seems to be hearts, clubs, diamonds, spades
especially when you add modded suits to the mix (what if the modded suit isn't in the pool? what if it's supposed to be a rare suit, like optics in oblivion? what about that one mod that adds mixed suits?)
Suit have nominal which used for sorting
hmmm
and even if there was a consistent ordering internally, i'd still be against "cycling" suits in-game
that's just not how it works in vanilla, whenever you change a card's suit you're just directly assigning it
it's not intuitive to players or to coders imo
assuming mod have seals on jokers, well, does it matter that much?
huh
it's still not something I'd want to encourage
hm, maybe
btw did you seen my recent development towards ui thing?
I managed to make it work with Object:extend() and it extends properly
Not in cleanest way but whatever
haven't looked at it but that sounds cool
what's the standard text styling for exponent mult
Spectrallib emult gradient :chud :
SMODS.DrawStep{
key = 'raritykeyshader',
order = 10,
func = function(self, layer)
if self.config.center.rarity == 'modprefix_raritykey' then
self.children.center:draw_shader('modprefix_shaderkey',nil, self.ARGS.send_to_shader)
end
end
}
end
oh wow thank you
does this just. work
Yes.
when i call SMODS.destroy_cards, how can i make it play the slice sound instead?
do i have to use skip_anim?
i just did what vremade's ceremonial dagger does
destroying cards only makes the "woosh" sound iirc, so you could get away with just playing the slice sound on top of that
is there a way to like. override what poker hand the game thinks you're playing
i'm imagining i'd need to hook a function
but yk
context.modify_poker_hand iirc
theres a context for it ik
context.evaluate_poker_hand
hm. i made it set to straight flush, and then realized two things
- it doesn't add every card to the hand as a normal straight flush would (though i fixed that already)
- it doesn't actually count as a flush or a straight, only a straight flush specifically. how do i structure a poker hand table lol
is there a way to get the config values of another mod while being a lower priority (so it loads after)

