#💻・modding-dev
1 messages · Page 651 of 1
this would work but I kind of want to make it so that only the SHOP cards are limited this way
Is there any way to make it play a custom sound or nah?
(so not packs or tarot-made ones)
P_CENTERS is not an array btw
i dont think so without patching the destruction functions i think
Ah ok
pairs
for k, v in pairs(G.P_CENTERS) do
local ranks = {}
for _, playing_card in ipairs(G.deck.cards)
if not SMODS.has_no_rank(playing_card) then
local r = playing_card.base.id
ranks[r] = (ranks[r] or 0) + 1```
Depending on how you want it changed...
ok so will if G.P_CENTERS[i].rarity != 1 still work?
yes
v.rarity ~= 1 and G.GAME.banned_keys[k] = true
could you just change the spawn rates for the rarities?
yeah that would be better if I can do that
Ideally I want the other rarities to still be available outside of shop
spawn rate changing would probably be most Ideal
and then rare skips would still function
@loud summit circle what shoud be changed.
G.GAME.rare_mod = 0
G.GAME.uncommon_mod = 0
oh shoot i forgot to add the "do" and "end" s
add "do" after the ipairs call
debuff_hand = function(self, cards, hand, handname, check)
for k, v in ipairs(cards or {}) do
if SMODS.has_no_rank(v) then return false end
end
return true
end
as example.
and two "end" after the ranks[r] line
this #💻・modding-dev message plus you would need to get the other rarities if you want to support mods
still doesnt add the bonus :(
well no they have to find the most common rank first
may i see
Don't think context.main_scoring fits for this, then.
-# Actually, exhausted, that's me done for now- 😵💫
Ok, I might have made a mistake but did I do ok?
wait you need to put that in a function
I would personally recommend doing something simpler to get a better grasp on lua first
Where?
hey i have some prior knologment of codding and i wanted to create a deck is there a video or tutorial where i can learn how to do it?
...yep. 
Not really, you can find resources here tho https://discord.com/channels/1116389027176787968/1349064230825103441
it seen i dont have the permition to see that channel
ok
You tell me @loud summit ||man this is going to be a wreck.
||
uh
under pos put calculate = function(self, context)
and put another end after the last one
This is what it looks like now.
Ox I bet.
uea
yea?
ya
...I regret doing this early. Give me a hint.
do you understand context blocks
This is my first rodeo at lua.
so function() opens a context
and everything between it and a end statement is in the function
for [] do ... end is also a context
if [] then ... end is also one
everything in the ... is considered part of that for or if statement
there's not much hint that can be given if you don't understand basic lua
Guess I have to insert "playing card" or "rank"
what
Was I correct?
I would really recommend doing a simpler thing, anything else is just asking someone to code it for you or spend a lot of time on speed teaching you the basics
Better get some hour of code thing at some point. Right now doing this is like playing The Lost without the Holy Mantle and having tears that move in a drunk motion.
the red squiggly lines aren't aesthetic
they indicate syntax errors in your code
I know.
what does glass_trigger do
It is used to detect if a card was destroyed because it was glass and it shattered.
Is it possible to have the game play a sound when some specific Jokers are held?
Is there any way to make it so certain cards are added back to deck after discard/play?
You mean you want to play a sound when a specific joker is obtained?
Well, 3 Jokers, but yeah.
Yes, you would put a check in each of the three joker's add_to_decks that checks if the other 2 jokers are held and then play the sound.
And that won't trigger the sound 3 times if they're all held?
Yes, because the other two would already be added to deck.
Fair enough. Thanks
how can I make a card have a 1 in 2 chance to not score (including from jokers and editions)
can i use it to other types of card?
What is the goal?
If you want it to be when the card scores instead you'll probably want to hook something tho. Maybe multiple things, depending on what exactly you're doing?
I kinda want to look into how cards score now lol
gotcha
how do i make custom tooltips, vanillaremade only shows how to append a existing card's description
Negative consumable tooltip
How are hands on this screen sorted? Could I somehow get position of a played hand on it?
Yes, G.GAME.hands[context.scoring_name].order
Ty
You think this is good or should I change with where the cards flip back
Also thinking of adding random enhancements
how do i take_ownership of an object in order to remove it? i swore at some point i've seen something along the lines of SMODS.<type>:take_ownership('name'):remove()
SMODS.Type:take_ownership('classprefix_modprefix_key', {no_collection = true, in_pool = function() return false end})
Add smal description what kind of issue in each message, clicking on messages and wait it to load sucks
Why does a word appear in the corner when you hover over a tooltip? Doesn't happen with tooltips from vanilla decks. Is this a bug?
yeah that's not supposed to happen. it's what we call orphaned text and it's fairly easy to accidentally cause
might be a smods bug, I'll have a look
My mod is the only one loaded in this clip so maybe a smods thing
And this happened with several other mods I've played, though I can't tell you which specific ones
does negative nancy have a tooltip for negative usually?
Yep
my guess is that it's trying to create that but it can't so the dynatext object is just stuck there
Sounds plausible
Thats just an issue with recursive tooltips in general for decks iirc
There was a mod that included playing card objects in a tooltip, and those playing cards would just spawn in the corner
Hex on ghost deck also does that
And they'd spawn infinitely if you kept hovering over the tooltip
funny
Just checked, nope
there's an old-ish issue that claims it does, but that seems to be untrue now
might be specific to things that these tooltips don't handle in vanilla
anyways what are you even doing if you're not using galdur
there was an issue of some tooltips flashing for a bit that i pr'd a fix for
Would that even affect this issue lol
yes actually
because these tooltips aren't hover tooltips when you use galdur
they're just plain old tooltips attached to the main infobox
Oh interesting
I just saw this text in the corner fairly frequently when playing various mods and I never knew what caused it
Sometimes it would say nil or just like a random word related to the mod
But now I made my own deck and it's clear that it's an info queue thing I guess
not necessarily, it's just a dynatext that's orphaned other mods can have that issue for other reasons
in this case it's probably because of the info queue tho since smods changed them to have name styling
ok i think i see what's happening
this specific display is handled somewhere in vanilla code smods has never touched
that code, of course, having no reason for it, doesn't support additional info boxes
But it also doesn't ignore them completely?
the DynaText still gets created, it still runs a full generate_card_ui after all
it just doesn't tell the UI to render them anywhere
because that's the default
And it's not like completely stuffed in the corner, there's spacing
that's 0,0 i think
Funky
of course there's spacing
the UI element has spacing around it
as it would otherwise have too
the only difference is that we didn't tell it where to go
so it went to the corner instead
it's not fully inside the corner because both locations are based on top-left corners, i think
Interesting :P
anyhow I'll track this as an issue on the smods repo for now
not gonna be top priority since it only occurs when you for some reason don't use galdur
Lol good to know, thank you
also i guess i can close #1010 now, which I didn't notice before
card.context.after is after scoring right
right right
idk why i typed card here
whats the order of activation between context.after and context.joker_main
between those context.final_scoring_step
they should be ordered in the contexts page
and the game ends after that
scoring? yes
after context.after
yeah thats the last context in scoring
ok cool
Isnt context.destroy_card after that too
destroy_card is just before after iirc
I dont think so?
I use context.after to mark cards to be destroyed for stuff that destroys random cards
And that works
how can i juice up the deck?
yes
you can juice up the top card
so G.deck.cards[1]:juice_up() ?
yeah
let's see
if it doesnt exist you can do the area itself too
but it looks bad when there are cards
Interesting lol
If I have a deck that starts you with a joker by specifying jokers in config, how can I guarantee that it won't have an edition?
i dont think you can
damn.
You could do that, but it would be better to create the joker in apply
Just generally or is using jokers in config okay?
No, I mean if you want the joker to never have an edition you would create it in apply instead.
Yeah makes sense
Hey, is there a way for me to check what rarity a joker has? I want to make a consumable that gives a joker of the same rarity of the joker you have selected, but I cannot find a way to check the selected joker’s rarity.
SMODS.add_card({set = 'Joker', rarity = G.jokers.highlighted[1].config.center.rarity})
Thank you very much!
Why does get_current_pool('Edition') also return UNAVAILABLE as an edition? Is there another way to get a list of editions?
get_current_pool always does this
things that cant spawn get replaced with UNAVAILABLE
It doesn't do this with "Enhanced" or "Seal" as the argument though
When I run it in the DebugPlus console at least
yeah because all enhancements and seals can always spawn in vanilla
So then what's this fifth edition that can't spawn? Base?
but edition has e_base (no edition) in the pool as well and that cant spawn from edition generation
yeah
Interesting
if you want all of them theyre in G.P_CENTER_POOLS.Edition
Let's see
im trying to make a joker that gives money at the end of round equal to its sell value, im 99% there but i cant figure out how to access the jokers sell value, does anyone know how?
joker.sell_cost
i tried that but it crashes
this is my code
SMODS.Joker{
key = "myfirstjoker",
config = { },
pos = { x = 0, y = 0 },
rarity = 2,
cost = 6,
blueprint_compat = true,
eternal_compat = true,
unlocked = true,
discovered = true,
effect = nil,
atlas = 'myfirstjoker',
soul_pos = nil,calculate = function(self,card,context) if context.end_of_round then ease_dollars(joker.sell_cost) end end, loc_vars = function(self, info_queue, card) return { } end}
joker would be card in this instance
ahh
also do you want to give money during round eval?
before eval
ah ok
it gave me money but instead of the sell cost (3), it gave me ~50
you're missing context.end_of_round and context.main_eval
does running table.unpack on an empty table act as returning nil
asking because im putting a table.unpack output into math.min and the table can be empty
seems like it
wait i forgor
i can just put it as the last argument and then it doesnt matter because there wont be nils in the middle
why the fuck is table.unpack a nil value
oh thats a 5.2 thing
silly me
yeah its just unpack
if you just want to delete the UNAVAILABLE entries, there's SMODS.get_clean_pool()
it's relatively new; i don't recall whether it's in the latest release yet
Oh whaaaaaat
Yeah I don't have it in the latest release
So I guess for now I'm removing the UNAVAILABLEs myself lol
-# or you could do a little SMODS.get_clean_pool = SMODS.get_clean_pool or <copy of SMODS.get_clean_pool from dev>
I looked and my code is already basically exactly that lmao
It's fine
card:set_edition("edition_key") (where card is the relevant card object and is probably called something different than card)
and yes, the key for negative is e_negative
and they're even (mostly) bug-free as of the latest release!
I've been trying to make exponential chips but I keep getting the crash error that I'm performing arithmetic on global 'chips' (a nil value)
I basically copied what I did with my exponential mult jokers which work just fine so I'm not sure what's different for chips
How do you change the name of a vanilla joker?
it's hand_chips to access the current chips
iirc you should be able to just add a localization entry for a vanilla joker in your mod's localization files
might need to take ownership of it? not sure
yup that fixed it. Thanks!
ok so what you can do is have a custom localization entry for it with a different key
then take ownership of the vanilla joker, and in the new loc_vars function, if the config option is turned on, add key = "different_key" to the return table (where "different_key" is the key you used in your custom localization), and it'll use your custom entry only when that key is returned
im using joker forge [im not good with code] and idk how to use the trigger for a 1 in 16 chance to gain a negative blueprint when a card is destroyed
i found out how to give but idk the modprifx for blueprint
im kinda new to this
its just j_blueprint
it should be lowercase, theres a list for the keys in the menu on the left
do i just type in blueprint
try it idk
type j_blueprint
if you’re using a modded joker then it’s j_(MODPREFIX)_key
ie. “j_ocstobal_somethingevil”
ocstobal being mod prefix
and somethingevil being the key
left menu > more > keys reference
found it
whats the variable for the current round?
or where would one find it
im rusty on finding stuff in balatro source code
how do i have dynatext constantly call a function for its text value...
strings = { { ref_table, ref_value } }
as usual
note that dynatext does make own text smaller when longer text appears and there's no space, but not makes it back
wgat
DynaText({
string = {{ ref_table = G.GAME, ref_value = 'dollars' }},
colours = { G.C.MONEY },
scale = 0.3
})
uh
this is the function i was calling
number_format(collectgarbage("count")*(G.GAME.round_resets.ante or 1)*card.ability.extra.per)
ok one second
DynaText({
string = {{
ref_table = setmetatable({}, {
__index = function()
return number_format(collectgarbage("count")*(G.GAME.round_resets.ante or 1)*card.ability.extra.per)
end,
}),
ref_value = "doesnt matter"
}},
colours = { G.C.UI.TEXT_LIGHT },
scale = 0.3,
})
thankerss 😇
does this joker like. Make Sense to read
it checks your score at the first end of round, then gives you money at future end of rounds if you score less than that score
I think it's more interesting if the condition is always based on the previous round, rather than the very first round you played with the joker
thats a good idea
I'm working on making my first joker and this is what I have at the top of the smods.Joker object:
loc_text = {
name = 'Bottom Half Joker',
text = {
"{C:mult}+#5# {} Mult",
"For each empty slot",
"In scoring hand"
}```
which to my understanding is what defines the name and the description, however the image is what shows up in game. Where did I go wrong?
OH, thank you
What's a good way to test it without resetting until I get it in the first shop?
Debugplus
install debugplus and hold Tab in-game to see all the shortcuts
(including spawning jokers from the collection at will)
Ok cool, thank you so much
do vouchers support calcuate....
yes, and observatory uses it in vanillaremade
Is there a way to check when a joker is triggered?
context.post_trigger
would this work to make a card immutable from what ive seen in previous messages? idk
i think it needs to be outside config
but i dont know how cryptid works
hey guys is there a way to change the blind description mid-blind? changing the loc_vars doesn't update the text
sorry😭
Ok
you can return { key = "some_other_key" } in loc_vars and it uses that key in the loc vars instead of the default one
could you explain? i'm making a blind that debuffs a random rank each hand, and when it changes the rank, the description doesn't update
blind looks like this
the description says the rank is 2, but whenever the rank changes, the description doesn't
SMODS.Blind {
name = "boss_calculator",
key = "boss_calculator",
atlas = "zbsblindatlas",
pos = { y = 0 },
dollars = 5,
mult = 2,
boss = { min = 1 },
loc_txt = {
name = {"What is diddy blud doing on the calculator"}
text = {
"Random rank debuffed",
"each hand",
"{C:inactive}(Currently {C:attention}#1#{C:inactive})",
}
},
boss_colour = HEX('0e1330'),
config = {rank = 2, rankstring = "2", canredorank = false},
loc_vars = function(self, info_queue, center)
return { vars = {self.config.rank or 5, self.config.rankstring or ":33", self.config.canredorank or false}}
end,
calculate = function(self, blind, context)
if not blind.disabled then
if context.before then
self.config.canredorank = true
end
if context.hand_drawn then
if self.config.canredorank then
self.config.canredorank = false
local ranks = getRanksInDeck()
print(":3", self.config.rank)
if #ranks > 0 then
self.config.rank = pseudorandom_element(ranks, pseudoseed("calculator"))
end
print(":33", self.config.rank)
for i, v in ipairs(G.playing_cards) do
G.playing_cards[i]:set_debuff(self:debuff_card(v))
end
end
end
end
end,
debuff_card = function(self, card)
print(self.config.rank, card:get_id())
if self.config.rank and card:get_id() == self.config.rank then
return true
else
--return false
end
end
}
idk how to do the code thing style like the above posts
dunno how to solve your issue but you shouldnt save things to self
they wont get saved between reloads and they will persist between runs
oh ok
what the hell am i doing wrong.
Oops! The game crashed: [SMODS _ "src/utils.lua"]:228: Attempted to insert object "j_ecattos_element0" into an empty pool.
key = "handmade",
default_weight = 0,
badge_colour = HEX("707A86"),
pools = {["Joker"] = true},
get_weight = function(self, weight, object_type)
return weight
end,
}
function ishandmade(rarity, bool)
if (not bool) and SMODS.current_mod.config["disable_nonfunctional_cattos"] then
return "ecatto_handmade"
end
return rarity or 3
end
local elements = {
--Atomic number, Symbol, Name, Pronouns, Base Mass, Calculate
{0, "Mu", "Muonium", "hse_ehr", 0, rarity = 3, functional = false},
--blah blah blah
}```
use blind.effect.rank
"pronouns" 😭
can we see the joker
its weird and
local n = v[1] + 1
if v[4] and CardPronouns and not CardPronouns.badge_types[v[4]] then
v[4] = "ecatto_" .. v[4]
if not CardPronouns.badge_types[v[4]] then
print("ElementCatlatro | Not found pronouns for key "..v[4])
end
end
if type(v.loc_vars) == "table" then
v.loc_vars = elementcattos.simpleLocVars(v.loc_vars)
end
--[[if not v.rarity then
print("ElementCatlatro | Not defined rarity for "..v[1].." "..v[3])
end]]
local j = SMODS.Joker({
key = "element" .. tostring(v[1]),
loc_txt = {
name = v[3],
text = {"{C:inactive}Symbol: "..v[2]..", Atomic number: "..tostring(v[1])}
},
atlas = "elements",
pos = {
x = n % 8,
y = math.floor(n / 8)
},
pronouns = v[4] or "she_her",
cost = v.cost or 1,
atomic_number = v[1] or v.atomic_number,
element_symbol = v[2] or v.element_symbol,
in_pool = inpool,
pools = {
ElementCattosCommon = true,
ElementCattosUncommon = true,
ElementCattosRare = true
},
rarity = ishandmade(v.rarity, v.functional) or 3,
config = v.config,
loc_vars = v.loc_vars,
calculate = v[6] or elementcattos.defaultJokerCalculate,
element_base_mass = v[5] or v.element_base_mass
})
--[[if v[6] then
topuplib.ezcalc(j, v[6])
end]]
if not elementcattos.atomicnumber[v[1]] and v[1] > 0 then
elementcattos.atomicnumber[v[1]] = j.key
end
end```
no idea
make sure the rarity is actually 3
wait i misread
make sure it is "ecatto_handmade"
maybe the prefix is wrong
Hi, I don't wanna bother on this chat, or to interrupt anything, so I'm gonna be quick.
I am doing a retexture mod where the clubs are green. The thing is that the text in game when mentions "clubs" has blue color.
Is there any way to change the base color text for specific concepts like the different suits and else?
thank you :)
If this retexture is automatically applied with the mod, you could simply edit the G.C.SO_1.Clubs and G.C.SO_2.Clubs color definition, I suppose?
-# Just my two cents on thought.
it should be.
I'll try, thnx
it worked :)
am i able to take ownership of modded objects? i want to modify/replace objects in another mod (make a mod for a mod)
Yes.
sweet!
does order work anymore? it doesn't seem to affect when the joker appears in the collection like in this
SMODS.Joker {
key = "a_dragonfruit",
name = "Dragonfruit",
config = {
extra = {
nommed = false
}
},
pos = { x = 5, y = 0 },
cost = 1,
rarity = 3,
order = 1,
...
and then this
SMODS.Joker {
key = "a_blueberry",
name = "Blueberry",
config = {
extra = {
perma_bonus = 6,
perma_bonus_mod = 1
}
},
pos = { x = 0, y = 0 },
cost = 5,
rarity = 1,
order = 2,
...
dragonfruit seems to appear after blueberry in the collection
as far as i can tell order was never an argument for jokers in base smods
i must've been cryptid-pilled then
at least it's not in the lsp definitions
yea manually setting order isn't a thing in smods, it's just ordered by load order
ohhh you have to put a if
let me show you how i did it for lily's joker
µ
is this the best way of counting rares, or is there a better way?
function count_rares()
local count = 0
for _, v in ipairs(G.jokers.cards) do
if v and v.config and v.config.center and v.config.center.rarity == 3 then count = count + 1 end
end
return count
end```
Yes, change the if to if v:is_rarity('Rare')
thanks ^^
When I make a seal and put in the en-us file name+text in the Others table, the seal wouldn't show anything. I account for the mod prefix like I do for my stickers, but it doesn't seem to work like them
what key did you use?
for the seal? normal lowercase word
still doesn't work
which of the 2 info boxes reads better?
I like the 2nd one, I'd add some color on 'retrigger'
Code?
Remove the "thens" from the second one and second one probably the best
Short simple easy to understand
Lua file:
SMODS.Seal {
key = 'stone_seal',
badge_colour = HEX('99A2B3'),
pos = {x = 5, y = 0},
atlas = 'seals',
discovered = true,
loc_vars = function(self, info_queue, card)
local odds = 4
local numerator, denominator =
SMODS.get_probability_vars(card, 1, odds)
return {vars = {numerator, denominator}}
end
}
En-us:
(in descriptions>Other)
CTEH_stone_seal = {
name = 'Stone Seal',
text = {
'Permanently gain {C:chips}+40{} chips',
'when {C:attention}changing Enhancement',
'Discard to turn into {C:attention}Stone'
}
},
(in misc>labels)
CTEH_stone_seal = 'Stone Seal',
It should be cteh_stone_seal_seal in the localization file.
well even if I remove the _seal in the seal definition file, it still wont work
the effect should be identical
Are you 100% sure that you didn't misplace Other
misplace? it is in the Other table alongside my stickers' descriptions which work like supposed to
Huh
I use the Other table for my sticker descriptions too
do i write scored_card:set_ability('m_glass', nil, true) to transform a scored card into glass?
yes
have you tried all lowercase
I dunno man, I copied your code (except for the label part cus lazy) and localization works just fine
Their prefix IS in caps tho
and
in the code i see everything gets lower'd
yeah lowercase works on the mod prefix
which docs
i read the conversation
i said also
smods.seal
that case sensitivity inconsistency throws me off. I could just make my mod prefix lowercase, but ah well
Oddly this inconsistency is caused by being consistent with vanilla
Bump
why does this crash :(
calculate = function(self, card, context) if context.individual and context.cardarea == G.play and context.other_card:is_suit("Diamonds") then return { chips = card.ability.extra.chips, card = self } end end,
because self isn't a card in this context
and how on earth did i mess up pasting that lol
just delete that line
is self the joker
it works now thx
card is the individual joker object, when you need that
does anyone have an example of a deck that has boosted chance for jokers from your mod
yes, i have one and paperback has one
may i see it
https://github.com/wingedcatgirl/MintysSillyMod/blob/main/backs/silly.lua
https://github.com/wingedcatgirl/MintysSillyMod/blob/main/lovely/silly_deck.toml
it requires lovely patching get_current_pool()
right, tysm
(my code is basically a carbon copy of paperback's, just copied and edited to add the sleeve effect :v )
how would i make an enhancement copy another card's enhancement
like permanently replacing the enhancement or behaving more like blueprint?
the second one probably requires quantum enhancements
local eval, post = eval_card(other_card, context)
local ret = {}
for k, v in pairs(eval) do
if type(v) == 'table' and (k == 'playing_card' or k == 'enhancement' or k == 'end_of_round') then
if not v.card then v.card = card end
table.insert(ret, v)
end
end
return SMODS.merge_effects(ret)
ty :3
is this supposed to be a hook
or does it go in the calculate func
wait yea it would i'm dumb
do u know why the 2nd-last card is the one being juiced?
also it's copying the chips not just the enhancement
Try changing if not v.card to if not v.card or v.card == other_card
now it's the 3rd-last card
here's the full calculate func
calculate = function(self, card, context)
local pos = 0
if (card.area and card.area.cards) then
for i, v in ipairs(card.area.cards) do
pos = v == card and i or pos
end
local c = card.area.cards[pos+1]
if card.area.cards[pos+1] then
-- thanks to @somethingcom515 for the code
local eval, post = eval_card(c, context)
local ret = {}
for k, v in pairs(eval) do
if type(v) == 'table' and (k == 'playing_card' or k == 'enhancement' or k == 'end_of_round') then
if not v.card or v.card == c then v.card = card end
table.insert(ret, v)
end
end
return SMODS.merge_effects(ret)
end
end
end```
Does anyone know why this code causes the first two pools to become copies of sealpool?
local enhpool = get_current_pool('Enhanced')
local edipool = get_current_pool('Edition')
local sealpool = get_current_pool('Seal')
-- Remove invalid items from each pool
for _, pool in ipairs{enhpool, edipool, sealpool} do
repeat
local restart = false
for i, item in ipairs(pool) do
if item == 'UNAVAILABLE' then
table.remove(pool, i)
restart = true
break
end
end
until not restart
end
ive had this issue before and i couldnt tell you what causes it
i think you just need to create and then use each pool one by one to prevent this
they use G.ARGS.TEMP_POOL im pretty sure
im seeing that in the code but i cant see it directly setting _pool as a reference to it
I've removed the first for ipairs() do part and just copypasted the repeat until thrice, nothing changed, so it's not that
here's the three resulting tables...
you need to make shallow copy of each pool before pool another one
because it returns same object every time but with different content
Huh.
what does this mean?
you can use SMODS.shallow_copy(table)
SMODS.shallow_copy(get_current_pool(...))
why does it do that anyway
because localthunk decided this
G.ARGS shoult not exist in theory, sounds like bad pattern
it stores too much stuff inside
I was investigating the properties of balatro's RNG, and I wrote a short lua script to attempt to dump a whole bunch of random numbers to stdout to use with random number test suites. But I'm having some trouble getting the random numbers to... be random?
require "functions/misc_functions"
-- init the game object so that the pseudoseed function can work.
G = {GAME = {pseudorandom = {}}}
G.GAME.pseudorandom.seed = arg[1]
seed_name = arg[2]
while true do
rand_value = pseudorandom(seed_name, 0, 4294967295)
print(rand_value)
print(tprint(G.GAME.pseudorandom, 2))
-- string_value = string.format(
-- '%c%c%c%c',
-- bit32.band(rand_value, 0xff),
-- bit32.band(bit32.rshift(rand_value, 8), 0xff),
-- bit32.band(bit32.rshift(rand_value, 16), 0xff),
-- bit32.band(bit32.rshift(rand_value, 24), 0xff))
-- io.write(string_value)
end
This script calls into the balatro RNG to pull random values. But the values I get are all identical. (I also patched the pseudorandom function to print out the current seed after it sets it.) The output when I invoke with randomness_test.lua TUTORIAL Tarot starts with:
pseudoseed: 0.42662880480655
random: 1693861772
{
seed= "TUTORIAL",
Tarot= 0.8532576096131,
}
pseudoseed: 0.3028680272979
random: 1693861772
{
seed= "TUTORIAL",
Tarot= 0.6057360545958,
}
pseudoseed: 0.08946579143175
random: 1693861772
{
seed= "TUTORIAL",
Tarot= 0.1789315828635,
}
pseudoseed: 0.22149368274415
random: 1693861772
{
seed= "TUTORIAL",
Tarot= 0.4429873654883,
}
pseudoseed: 0.4491510049583
random: 1693861772
{
seed= "TUTORIAL",
Tarot= 0.8983020099166,
}
As you can see, the pseudoseed and the stored value in the pseudorandom object are both changing, but the number output by the pseudorandom function is locked to a single value. Has anyone come across this before?
do not post same message twice, specifically this big
I'm deleting it from the other channel, because it's in the wrong place
Yeah this did the trick:
local enhpool = SMODS.shallow_copy(get_current_pool('Enhanced'))
local edipool = SMODS.shallow_copy(get_current_pool('Edition'))
local sealpool = SMODS.shallow_copy(get_current_pool('Seal'))
That's so weird lol
blame thunk
What does pressing B actually do
Is it just a faster version of holding R?
mine does nothing
I think it's a debugplus thing
I'm just concerned if it's a proper restart and it's safe to use for testing rng stuff
it is a proper restart
Sweet!
oh ok its because i have the ctrl setting
originally, I was running this under lua 5.2, but then I looked at the love documentation and they use lua 5.1, so I downloaded PUC Lua 5.1 and tried it there, but it didn't help. New error with the integer version of things, (saying my range is empty), and additionally the floating point version still emits the same number over and over. That being said, I booted up balatro for a sanity check and it does seem to work there.
i was going to ask the version but then i thought it wouldnt matter
balatro is specifically luajit
I haven't touch modding in a while and the calculate function page has updated to include SMODS.scale_card, should I change my cards to have these for mod compatibility even if I don't plan to need it myself?
it would be good to do so, yes
it's up to you
ok, I don't think I've implemented many scalers yet anyhow so shouldn't be too big a deal, although maybe it's because I'm not used to it, it seems a tad more complex
it is one of the less important things to update imo
thats crazy lol i wonder why
my guess is that it has something to do with how puc lua passes the value to the C implementation of randomseed. My hypothesis is that (because the value is a floating point) it truncates it, effectively setting it to 0, each call.
whereas luajit simply pushes the raw bytes around, essentially reinterpret casting it to an int.
I'm trying to make this joker effect where it takes the +chips and +mult from an enhanced card and adds it to itself
I'm just running into the issue of how to actually see how much +chips and +mult to add
I was thinking of trying something similar to how to get joker keys (using .config stuff or whatever) but I haven't been able to come up with anything that works
it depends on how you store them but they should be in wooden_card.ability.whatever_chips_or_something
Could someone help me understand what this means in the steamodded api
card_key: Used to create keys for playing cards, formatted like S_R, where S is the suit's and R is the rank's card key. Your mod prefix gets prepended by default."
I'm trying to make a new suit and ranks
How do you get the base blind score for boss blinds?
I just had to add .extra after .ability but after that, it worked!
in vanilla it would be like H_A for an ace of hearts
for your rank or suit it would be [mod prefix]_[suit card_key]_[mod prefix]_[rank card_key]
it can just be the same as the key
Is there any way to animate card positions with events? I have two cards I want to move together before they create a new Joker, and I know how to get their midpoints, but accessing their transformations has kept crashing for me
if card in cardarea, then card's position dictated by cardarea
So you need remove card from cardarea and then you can mve it by changing card.T.x and card.T.y
And make sure to make card not collideable, so player cannot grab it
gotcha, I'll see what I can do
yuri achieved
YURIIIIII
does this work?lua if G.GAME.current_round.hands_left == 0 then card.ability.extra.mult = card.ability.extra.mult * card.ability.extra.powerup card.ability.extra.mult = card.ability.extra.mult * card.ability.extra.powerup SMODS.calculate_effect({ message = "X" ..card.ability.extra.powerup, colour = G.C.GOLD}, card) end
wanna hop on with mod dev, what do I need to start
how do you check for, "if round is beaten in one hand"
i believe smods has a flag for this, though i don't recall its name
SMODS.last_hand_oneshot i think
well, its for if the previous hand did the entire blinds score
but you can just check if only 1 hand was used in the round additionally
how about "if round is beaten by first played hand"
i already described that
last_hand_oneshot tells you if the previous hand did it
if you want to see if it was done in the first hand, just check for SMODS.last_hand_oneshot while also seeing if only one hand was used this round
is there a joker that uses SMODS.last_hand_oneshot
i'm gonna see how they work
or how SMODS.last_hand_oneshot works
it is a value and you check for it (preferably in context.after) to determine if the last hand oneshot the blind
if context.after and SMODS.last_hand_oneshot then
SMODS.add_card{...}
SMODS.calculate_effect{...}
end```
yea looks good
it creates 2 instead of 1lua calculate = function(self, card, context) if context.after and SMODS.last_hand_oneshot then SMODS.add_card{set="Infinity"} SMODS.calculate_effect({message = "+1 Infinity Card", colour = HEX('FFB570')}, card) end end
I added this object and now the game is crashing, any idea where I went wrong?
key = "head",
card_key = "head",
pos = { x = 0 },
nominal = 0,
loc_txt = {
name = 'Exodia The Forbidden One'
},
face = true,
strength_effect = { ignore = true },
in_pool = function(self, args)
return false
end
}```
The error message is game.lua:1893: bad argument #1 to 'ipairs' [table expected, got nil]
i made an items folder with the jokers lua inside, but now the jokers file is looking for atlas in the folder it's in, how do i fix that ?? (prob a dumb question but i'm pretty new to this ...)
you could maybe try clarifiying the path when you create the Atlas object?
but how would that work ? like with the 1x and 2x folders
oh thats a good point, idk then, hopefully someone else can help you
alr, thanks anyways
how do i make it so that ```lua
"{C:blue}Blue Seal{}, {C:blue}Bonus{}, {C:blue}Foil{}, and{} {C:blue}Club{} Cards",
"{C:attention}always score{} and give {C:white,X:chips}X#1#{} Chips"
for the "always score" part, check how Splash works in vanillaremade
for the "give Xchips" part, that's just basic context.individual stuff
yes
you can adapt the code for splash in vanillaremade to include those checks
if you don't know how to make those checks, that should be documented on the vanillaremade wiki
(extra detail- the context that splash uses runs once for every individual card in the played hand, much like context.individual)
so i don't need to use context.individual?
you need it for the "and gives Xchips" part, but not for the "always scores" part
you do understand that you can interact with multiple contexts in your calculate function, right
how do you check for if a card has blue seal
if you don't know how to make those checks, that should be documented on the vanillaremade wiki
welp, time to test it out```lua
calculate = function(self, card, context)
if context.modify_scoring_hand and not context.blueprint then
for _, bluecheck in ipairs(context.full_hand) do
if context.individual and context.cardarea == G.play then
if
bluecheck:is_suit("Clubs") or
(bluecheck.edition and (bluecheck.edition.foil)) or
SMODS.has_enhancement(bluecheck, 'm_bonus') or
(bluecheck.seal and bluecheck.seal == 'Blue')
then
return {
add_to_hand = true
}
end
end
end
end
end
this will not work
if card:get_seal() == 'Blue'
first of all, like i already said, modify_scoring_hand behaves like context.individual. you don't need to embed individual inside modify_scoring_hand, and in fact that will make nothing calculate
second of all, modify_scoring_hand behaves like context.individual. as per the calculate functions wiki page on smods, it directly gets context.other_card
so make them separate?
modify_scoring_hand for the always scores and context.individual for the xchips?
yes
calculate = function(self, card, context)
if context.modify_scoring_hand and not context.blueprint then
-- always scores code
end
if context.individual and context.cardarea == G.play then
-- xchips code
end
end
i need to make a local to use for checking blue cards
how about this?
local bluecard = context.other_card:is_suit("Clubs") or
(context.other_card.edition and (context.other_card.edition.foil)) or
SMODS.has_enhancement(context.other_card, 'm_bonus') or
card:get_seal() == 'Blue'
if context.modify_scoring_hand and not context.blueprint then
if bluecard then
return {
add_to_hand = true,
}
end
end
if context.individual and context.cardarea == G.play then
if bluecard then
SMODS.calculate_effect({xchips = card.ability.extra.xchips})
end
end
end
this won't work because context.other_card isn't guaranteed to exist every time the calculate function is run
and for the xchips part you can literally just return { xchips = card.ability.extra.xchips }, you don't need to do SMODS.calculate_effect
but yes you're much closer
do i replace bluecard with the complete check?
yea
oh also it should be context.other_card:get_seal()
but once you've done all that it should work
if context.modify_scoring_hand and not context.blueprint then
if context.other_card:is_suit("Clubs") or
(context.other_card.edition and (context.other_card.edition.foil)) or
SMODS.has_enhancement(context.other_card, 'm_bonus') or
context.other_card:get_seal() == 'Blue' then
return {
add_to_hand = true,
}
end
end
if context.individual and context.cardarea == G.play then
if context.other_card:is_suit("Clubs") or
(context.other_card.edition and (context.other_card.edition.foil)) or
SMODS.has_enhancement(context.other_card, 'm_bonus') or
context.other_card:get_seal() == 'Blue' then
SMODS.calculate_effect({xchips = card.ability.extra.xchips})
end
end
end
i pray in the name of lord ruby this works
bruh...
i'm certain this is supposed to work with cryptid
.
i assume the calculate_effect function is crashing
because you aren't giving it a card to calculate on
huh... that worked?
i guess you're right
sometimes return is good
it works
time to update the mod
No, return is always good.
fair enough
i keep hearing that SMODS.calculate_effect is almost always better
where are you hearing that???
jamirror iirc
there's a couple of other peeps who agree so he's not exactly the source
it's only good for getting other cards to animate with a message when smods doesn't already handle it for you
smods handles it for you in context.individual
No, you're only supposed to use SMODS.calculate_effect where you can't return or in a func of a return
I'm not sure how to exactly search for it, so I'll ask here; is there a way to make a joker mod-dependent? i.e. this joker won't even be in the game if this mod isn't enabled
(this is for a custom joker, not a base-game joker)
I'm so inexperienced in programming that i was about to say "can't you just use an if statement?"
hey, you never know, that might be the actual solution
yes
dependencies = {"mod_id_here"} in your joker definition
oh
note that including this will also make it display the other mod's badge when you hover over it
thank you!
in addition to the dependency I was curious if you could enable/disable it with a boolean since I made a config for enabling cross-mod jokers for my mod
for that - i would recommend putting all of them in one file/folder and only loading stuff in that file/folder based on the setting
e.g. if modname.config.crossmod then ... end
it means itd require a restart to toggle on/off but i think that's the best solution youd get
this was still true
for sure
Hi all, I'm trying to create my first mod, which aims to add various card enhancements as seals, and I have managed to get Bonus, Mult, and Lucky working flawlessly, but I am having issues with Glass. It for the most part works, but I cannot get it to proc Glass Joker, which is strange because the Lucky Seal can proc Lucky cat without issue. Attached is the code for the Glass seal. Apologies if it's a mess.
Yes, shatters = true only works for enhancements.
If you want to scale Glass Joker with the seal, you may need to hook SMODS.calculate_destroying_cards and manually add .shattered to a card that has .glass_trigger set?
No, they should hook SMODS.shatters
-# Or that-
how do you make it so that the first shop always gives you cavendish?
as in all the slots in the rerolls
WHY does this return a number 
# is the lenght operator
alternately, make their in_pool check this config
then it won't require a restart
how can I implement Cobblemod's Foresight? By copying the related code?
I don't know what that is but most devs are ok with using their code with credit
context.joker_type_destroyed and context.selling_card
<@&1133519078540185692>
i also won that

if context.joker_type_destroyed and context.card == "j_cavendish" then
end
if context.selling_card and context.card == "j_cavendish" then
end
context.card is the card object not the key
man, I tried and it failed
hey , are there any planet card template???
oh uh
how do i check if the card being sold/destroyed is cavendish then
context.card.config.center.key
local key = "j_cavendish"?
You don't need a local
I mean you can have it
But like context.card.config.center.key == "j_cavendish"
ok hold on
only if your next line looks like if context.card.config.center.key == key
if context.setting_blind or context.forcetrigger then
SMODS.add_card{key = "j_cavendish", edition = "e_negative"}
if context.joker_type_destroyed and context.card.config.center.key == "j_cavendish" then
SMODS.scale_card(card, {
ref_table = card.ability.extra,
ref_value = "emult",
scalar_value = "emultmod",
colour = SMODS.Gradients["busterb_eemultgradient"]
})
end
if context.selling_card and ontext.card.config.center.key == "j_cavendish" then
SMODS.scale_card(card, {
ref_table = card.ability.extra,
ref_value = "xmult",
scalar_value = "xmultmod",
colour = G.C.RED
})
end
end```
oh wait
i see the problem wiht my code immediately
it's in setting blind wtf
also "ontext"
saw
it crashed
fixed it asap
i don't like this method of scaling
also does joker_type_destroyed actually work
Why, didn't work for you?
think so
test it with the knife and/or investigate the code
it says upgrade
so the context works
oh wait
my fault
i never wrote the updating text
how do you add an enhancement to card like say I wanna make a joker make a random card a glass how would I do that
I see hwo to check if a card has an enhancement
but I can't find how to add one to a card
Card:set_ability(enhancementkey)
Would be weird if setting an enhancement was complex
there are both benefits and drawbacks to
code
it's not that I was digging around the tarots
trying see how they did it
but it looked more complicated than it actually was
Oh tarots do that differently
working on a command for twitch intergration to let chat randomly make cards enhanced
just like #G.jokers.cards
gonna assume #G.hands.cards does the same
as the number of cards in your hand
hand
just hand or G.hand
G.hand
ok
G.jokers G.hand G.consumeables(why the fuck) are areas themselves and the .cards is the table of cards in the area
it doesn't
Oh
Then ig you do a loop and apply the enhancement to each card?
```lua
for k, v in pairs(G.hand.cards) do
v:set_ability('m_stone')
end
Ye
Yeah it worked
I really need to learn how thefor k, v in pairs work
I see it done alot but I just can't get it to click in my brain yet
tip of the iceberg thunkism
because cardareas contain other information like the card limit, their position on-screen, etc
Pretty much all you'll need to know is that it goes through each object in the table and v is the object it goes through
also that the order can be pretty much anything
if you want to loop though a list with numerical indices (aka an array), in order, use ipairs
I know that I've been in this shit for some time already
"Why the fuck" was addresed to consumeables being spelled like that, it's been half a year and I'm still confused about that
caino is funny
so like, crowd control?
just need to figure how to make it were more random
instead of just making every card the same
for key, value in pairs (arbitrary keys, arbitrary order), or for index, value in ipairs (numeric index, numeric order)
this took me a while to figure out too
the index is just table[index] = value
```lua
for k, v in pairs(G.hand.cards) do
v:set_ability(SMODS.poll_enhancement({guaranteed = true}))
end
holy shit ur a god
Somethingcom is very smarts
also relevant, tables of the form {value1, value2, value3} are implicitly numerically indexed
it's the same as { [1] = value1, [2] = value2, [3] = value3 }
how can I add raw round score before the round starts?
What
like, 100 points
Blind requirement?
Oh that
The number must be manually updated I think
```lua
if context.setting_blind then
return {func = function()
G.E_MANAGER:add_event(Event({
func = function()
ease_chips(100)
return true
end
}))
end}
end
ok
softlocked my game.
ok no its just that I suck
how do you add a message though?
just add a message in your return table
return { message = 'blah', func = ...}
Put SMODS.calculate_effect({message = 'message', instant = true}, card) in the event then put delay(0.9375) after the event.
right, timing stuff
like this?
inside func
hey, what is the name of planet font?
```lua
return {func = function()
G.E_MANAGER:add_event(Event({
func = function()
ease_chips(100)
SMODS.calculate_effect({message = 'message', instant = true}, card)
return true
end
}))
delay(0.9375)
end}
thanks!
uhm...
you didn't specify a card in the calculate effect
so whats the fix
card = card?
but when I added another flip it would mes up
wrong
}, card)
see
well, youre wrong, card = card worked
No, they both work.
well that's odd
Well not really
smods does a lot of work to make card = card unnecessary
No, it doesn't, effect.card is used when effect.message_card and effect.juice_card and scored_card don't exist when evaling a message.
sooth your chips
I don't want to
is there an option in jokerforge to affect mult?
Elaborate
like i want to male a joker's effect be "+[mult] or x[mult]"
make*
soothing chips
@subtle hawk
Why do you want me to sooth chips
i would like to see soothing chips
also you mean put your mod names in the display anme?
???
when you said "you should try it"
when i asked for a name of the busted baffoons mod
@subtle hawk
also when im done do i just export the whole thing
like from jokerforge into my mods folder
My brain is being fried at the moment can you not ping please
ok
how can i make a joker use a localisation key other than its own?
Add key = "..." to the loc_vars return
cool thx
You can additionally return a set to change which localization category it uses
If needed
I'm having issues issues with patching card.lua. I added a "Rank_bypass" function call to any Joker ability that checks the rank of a card (even steven, cloud 9 etc), so that if a certain joker is in play, face cards always pass the check.
```
function rank_bypass(playing_card)
if G.jokers and G.jokers.cards then
for i=1, #G.jokers.cards do
if G.jokers.cards[i].config.center.key == "j_hft_gwynplaine" and playing_card:is_face() then
return true
end
end
return false
end
end
like this
```
if self.ability.name == 'Hack' and (
context.other_card:get_id() == 2 or
context.other_card:get_id() == 3 or
context.other_card:get_id() == 4 or
context.other_card:get_id() == 5 or rank_bypass(context.other_card)) then
return {
message = localize('k_again_ex'),
repetitions = self.ability.extra,
card = self
}
end
```
However, this seems to cause strange behaviour on some of abilities. Cards like Hack, 8 Ball and Idol now give mult on top of their original ability. It seems to be equal to whatever card.ability.extra value they have (Hack -> +1 mult due to 1 repetitions, 8 Ball -> +4 mult due to 1 in 4 chance to trigger, Idol -> +2 mult due to 2 xmult)
Does anyone know what might be causing this behaviour? All I did was inject a Boolean returning function into the if statement of these Jokers.
I'm having a bug where when you load up a run in progress, if you previously used one of the consumables, the game would softlock like this
SMODS.Joker {
key = "diver",
blueprint_compat = false,
rarity = 1,
cost = 4,
atlas = 'Joker',
pos = { x = 9, y = 2 },
config = { extra = { levels = 0, maxlevel = 6, chips = 0, mult = 0, xmult = 0, h_size = 0} },
loc_vars = function(self, info_queue, card)
info_queue[#info_queue + 1] = { key = "fnaf_bug", set = "Other" }
return { vars = { card.ability.extra.levels, card.ability.extra.maxlevel, card.ability.extra.chips, card.ability.extra.mult, card.ability.extra.xmult, card.ability.extra.h_size} }
end,
calculate = function(self, card, context)
if context.using_consumeable and not context.blueprint and context.consumeable.ability.set == 'fnaf_item'
and not (card.ability.extra.levels == card.ability.extra.maxlevel) and context.consumeable.config.center.key == 'c_fnaf_clearance' then
card.ability.extra.levels = card.ability.extra.levels + 1
card.ability.extra.chips = 100 * card.ability.extra.levels -- 1
card.ability.extra.h_size = math.max(0, card.ability.extra.levels - 1) -- 2
card.ability.extra.mult = math.max(0, 5 * (card.ability.extra.levels - 2)) -- 3
card.ability.extra.xmult = math.max(1, 1 + (0.125 * (card.ability.extra.levels - 3))) -- 4
-- 5
-- 6
if card.ability.extra.levels >= 2 then
G.hand:change_size(1)
end
end
if context.joker_main then
return {
chips = card.ability.extra.chips,
mult = card.ability.extra.mult,
xmult = card.ability.extra.xmult,
}
end
end,
remove_from_deck = function(self, card, from_debuff)
G.hand:change_size(-card.ability.extra.h_size)
end
}
SMODS.Consumable{
key = 'clearance',
set = 'fnaf_item',
atlas = 'TarotFnaf',
pos = {x = 0, y = 1},
cost = 4,
loc_vars = function(self, info_queue, card)
end,
use = function(self, card, area, copier)
end,
can_use = function(self, card)
return next(SMODS.find_card("j_fnaf_diver"))
end,
in_pool = function(self, args)
return next(SMODS.find_card("j_fnaf_diver"))
end
}
It's a card where when it's used a joker gets a progression point, where it gets some buffs
No, you should do quantum ranks like this until the quantum ranks SMODS pull request gets merged: https://github.com/Somethingcom515/SealsOnJokers/blob/dev/lovely/multirank.toml
Is the game full frozen or does the game still run correctly except that you can't do anything?
still run
I can still press stuf
It just soft locks
I'll take a look, ty
how do you remove a seal from a playing card via code
and would it be a problem if i try to make a seal remove itself
go my rendering issues
hepl this is crashing when the break chance triggers i know im dfoing it wrong so how do i do it right
maybe try making the first argument of the pseudorandom function card instead of self?
no still crash :(
All instances of self in your probability calls should be card instead
youre returning true in the top context check
which uhhh
you shouldnt
is there some way to have a dynamic amount of lines in a description? other than having an alt key for each one. Tried using a linebreak in a loc var but that doesnt work
You would have to hook generate_card_ui
hmm sounds spooky, maybe I'll just hardcode 4 different description keys
is there a color loc var tag like {V:1} for background color?
Yes, it's B
is there a way to make a hand not score randomly? (basically if SMODS.pseudorandom_probability hits the hand doesn't score)
do you want to skip all scoring (like how boss blinds block hands from scoring), or just make the playing cards not score?
how boss blinds block scoring so like the eye and the mouth
```lua
if context.debuff_hand and not context.check and SMODS.pseudorandom_probability(card, 'seed', 1, odds) then
return {debuff = true}
end
ok ill try that rq
I'm looking at VanillaRemade for reference and I'm curious if there's a slightly less invasive way to ensure or append a card to a booster pack without taking ownership, assuming that it would no longer default to vanilla from there
I'm making a joker that ensures a specific Tarot shows up in Arcana packs; is there a way to do that without completely taking ownership for the sake of compatibility? i.e.
-- rough pseudocode
create_card = function()
if has_joker and i == 1 then
return card
end
return create_card
hook the create card function? you can also hook in a take ownership
take_ownership_by_kind was the example I'm working off
I'm basically asking if I have to re-implement vanilla behavior on top of the additions
i.e. stuff with omen globe and such
well you would need to do it individually but you can hook each
(and you can just do it in a loop)
you know sometimes i forget what i've modded
what would that look like?
note to self don't do plasma deck when testing this and accidentally clear the blind first try
-- somewhat pseudocode cuz phone
for key, prototype in pairs(SMODS.Boosters) then -- i dont recall if this exists or it's just P_CENTERS
local ref = prototype.create_card
SMODS.Booster:take_ownership(key, {
create_card = function(...)
-- code
return ref(...)
end
})
end
awesome, thank you so much!
ok, works
might've killed the run but works
i made an items folder with the jokers lua inside, but now the jokers file is looking for atlas in the folder it's in, how do i fix that ?? (prob a dumb question but i'm pretty new to this ...)
i had asked yesterday but no answer was given so i am asking it Again!
that's not how it works, you must have your code or folder set up incorrect. Can you share your code that tries to create the atlas, and a screenshot of where you atlas is in your mod folder with a folder path visible?
this is what creates the atlas (1st image, this is in the jokers.lua file, which is inside the items folder), but what i think is happening is that the jokers.lua file looks for the assets in the folder it's in
it does not
ah
what is actually going incorrectly?
you've described what you think the cause is, but you haven't said what the actual problem is
... actually, random question. what's the top of your jokers.lua look like
i'm pretty sure that IS the cause (i might be wrong tho), because what i did was place a temporary copy of the assets folder inside of the items folder .. this prevents it from crashing but when i remove it this happens
it is not
you know what. i can just barely see it in the first image. it's the steamodded header, isn't it
you didn't create a second file in the same mod, you created a second mod
use SMODS.load_file() in your main file
also consider switching your metadata to json, the header has been outdated for very long...
i had done something like that i think ..
I didn't realize "take_ownership" actually added it to the additions to your mod
is there a way for that to not happen
correct
outside of the table, yes
do i remove the steammodded header too
yes
the header will be dead soon also
kinda surprised we collectively kept it this long
people want early 2024 mods to still work with new mods
it just stuck around for back compat afaik
that worked !!! thank you all
but I believe zip loading doesn't work with it or something
thanks!
they all stopped working by now when smods made some random change!
you can say that every two months and it will be true
super-quick follow-up to taking ownership of a booster pack; does this allow you to change how many cards it has to start?
wtf how could they kill Jelly Mod
does anyone know of something i could reference for adding an additional counter alongside hands/discards/whatever in the bottom left
i tried looking at entropy but i just couldnt find it
how do I get the current blind size?
G.GAME.blind.chips
ty!
I have a bug right that when you use a spectral card I made that creates a card of a 5th suit and custom rank (which are kept out of the pool) they are added to the deck, the total deck counter goes up accurately but the remaining cards goes up inaccuratly. For example it starts 44/52, use the spectral card then it goes to 46/53, when nothing was added to the hand, only the deck. Any ideas?
How do you make it so a Blind detects if a Joker is triggered?
context.post_trigger
Oh thx
seems like you're adding them twice. code?
``` use = function (self, card, area, copier)
if #exodiaLeft ~= 0 then
local nextExodia = table.remove(exodiaLeft, 1)
local new_card = create_playing_card({
front = G.P_CARDS[nextExodia],
center = G.P_CENTERS.c_base
}, G.deck)
new_card:add_to_deck()
G.deck:emplace(new_card)
end
end```
theres the use function for the spectral card
try replacing this for SMODS.add_card { set = "Base", front = nextExodia, area = G.deck }
I've created an object type, but when I hover over a card of that type the game crashes because it's trying to localize the object
I can't find in smods' doc how to localize a new object type, if it's explained anywhere to begin with
The Binding of Jssac
ah you also extended center
jimbo
that makes more sense
yeah i'm trying to make cards that go in a new card area
they should be under descriptions.tboj_active iirc
the gist of it is reusable consumables, but if I code them as consumables then it has many side effects (because I don't want them to actually be consumables)
That worked, was the way I did it originally having both new_card:add_to_deck() and G.deck:emplace(new_card) messing it up?
probably
oh ok, thank you
That worked, thx!
N' fr the goat rn
play joyousspring
now to figure out how to make them spawn in the shop lol
add it to this table
the rate should be defined in G.GAME.tboj_active_rate right?
like joker_rate tarot_rate etc
it can be anything since its custom
not unless you make a consumabletype
inserted that with a patch (with 100 as the val so it's supposed to be very common) but it doesnt seem to be working
oh i need to change total_rate too
in the evaluate function for poker hands is the variable hand a table of all cards in the scoring hand?
most likely
so the card appears in the shop, i can buy it, it gets emplaced properly but it's not being drawn
any idea of what i'm missing?
the type of the area is probably wrong
it was "active" so yeah it was wrong, but I changed it to tboj_active and it still doesnt show
it has to be one of the vanilla ones
oh
like 'joker' i think
also theres a function to initialize areas now you dont need to patch
yup thx
oh cool thx
i copied it from multiplayer and they're patching
might be an old version of mp, idk
the mp devs are not very active around here so i just assume theyre not on top of smods features
also theyre always a version behind
Can you make it so a Joker can bring played cards back to hand?
theres functionality for that in the next smods version
Hey I might be a top 10 idiot but forever ago I made a mod that had jokers that did ^ mult, and now it just... doesn't work. upon research it might require stuff like talisman now, so how do I.... do that.
with talisman (I actually recommend Amulet now) you can just return emult = number where you would normally return mult or chips
okay it's emult, cool
is there a chips variation that's just
echips
yes
okay lets see if this works
Holy I will be using this thank you
< 3
Is there a way to make it so a playing card can not be affected by tarot cards?
i can think of a fairly easy way to handle tarot cards that specifically target the card, but not a single general way to do it for tarot cards that affect the whole hand/random cards (which doesn't exist in vanilla balatro, but something like familiar or sigil if it was a tarot card)
even if it specifically targets the card i would think there are many cases it would break modded tarots
i mean i was thinking of hooking whatever G.FUNCS function handles whether you can use a card to make it just flat out disable the use button if you have the relevant card highlighted
yeah i was thinking that but its kinda bad if the tarot doesnt have anything to do with the card
or maybe you have a tarot that upgrades selected poker hand or something
i would maybe do something more like the inmutable thing astra PR'd
API that allows cards to not be modified via set_ability, set_seal, set_base, copy_card, etc. Works similarly to SMODS.is_eternal where it runs a context context.check_immutable and returning immut...
ooh that's interesting
Ok, ill take a look at that
the idea is that it is exodia from yugioh, so if you play all 5 you instant win the blind, and adding things like enhancing the card and changing the suit break it
it might be easier to change what I have so enhancing it etc. doesn't break it then just preventing that from happening
you can just prevent those by hooking the respective functions
oh ok
does context.after happens before context.repetition?
no
i fixed the crashign but now the seal is destroying itself before its effect activates
and then the effect happens anyway
sounds like timing things, you probably need to put the destruction in an event
Ok, really weird question, but:
Is there a way to play sounds whenever things like a new run is started, lost, or won?
Preferably without having to use Jokers.
yeah you would just need to hook or patch the places with the correct timing you want
im learning about making mods, whats the best mod for like a debug menu to spawn in jokers and stuff? i wanna test my first joker!
debugplus
tab in a run, it also has all the shortcuts
to spawn in jokers you just open the collection & press 3 over the joker
ah, thank you!
welcome to modding 
i have to head to bed, but i tried this and it did not work. i was able to spawn in the jokers as mentioned by slimestuff, but no menu came up when i pressed tab
but i had to pull myself away from my pc, i was enjoying modding too much
