#đ»ă»modding-dev
1 messages · Page 698 of 1
it's literally just a file you create with the .toml extension
and it's just plaintext, you can edit it in notepad or whatever
or is it like items where it dsoesnt matter what name is
is there any way to code a consumable that gives +4 mult when a hand is played
if you have just the single file at the root of your mod, it needs to be lovely.toml, but if you have a lovely folder in your mod, then you can name it whatever you want
while held or after use?
kk
when held
just code it like a joker
^ you can just give the consumable a calculate function
but i also want it to give money when used
you can give it both a calculate function and a use function
it can have both calculate and use
you need this block at the top of the file (from the link i sent you)
oh ight
is the '+X extra chips' on bonus card or perma chips possible to recreate with a modded enhancement
OK, im so used to jokerforge that lua seems off
because those two stack their description to include both values
and im unsure if you can do that with a modded enhancement
Im trying to make a seal that when held in hand at the end of the round, it copies its playing card. I have the cloning part working however i cant get the message to pop up nor jokers like hologram to upgarde or mime to retrigger
version = "1.0.0"
priority = 0
[[patches]]
[patches.pattern]
target = "game.lua"
pattern = "SC = Card(G.ROOM.T.w/2 - SC_scale*G.CARD_W/2, 10. + G.ROOM.T.h/2 - SC_scale*G.CARD_H/2, SC_scale*G.CARD_W, SC_scale*G.CARD_H, G.P_CARDS.empty, G.P_CENTERS['j_smiley'])"
position = "at"
payload = "SC = Card(G.ROOM.T.w/2 - SC_scale*G.CARD_W/2, 10. + G.ROOM.T.h/2 - SC_scale*G.CARD_H/2, SC_scale*G.CARD_W, SC_scale*G.CARD_H, G.P_CARDS.empty, G.P_CENTERS['j_smiley'])"
match_indent = true```
you shouldn't be trying to manually load the toml file, the mod loading process will take care of it automatically
oh ight
how do i make a card not move when clicked/selected
still isnt putting in the custom cards into the cutscene thingy
you shouldn't have edited the pattern, only the payload
ooooh
the pattern is the original code the patch is searching for, and the payload is the replacement code (or inserted code depending on what the position is set to)
that makes sense
thank you very much
i gotta start putting some of you into the credits
it is fixed now
thank you very much
ye
what am i doing wrong?
more jokerforge issues i think? try deleting the line that's just })) after the end of the calculate function
i think this file might work
@frosty bone
assume that every single "if" statement will need a corresponding "end"
as of the three brackets, delete those. its likely a generation error
Thx
2 days left, you decease mod better be ready 
what do i need to fix for the text to appear above
yes im keeping the vremade defined in fear of it breaking something
i've been going insane trying to make a joker that essentially treats stone cards as not part of your hand size (e.g. having 2 stone cards in your hand would let you draw 2 more cards). i'm probably overlooking some really easy solution to this but i'm actually at a bit of a loss for how this would be done logically in terms of contexts and how/when you'd draw cards. "draw_card(G.deck,G.hand, 90,'up', nil)" would let you draw a card from your deck, but you'd need to loop this for the amount of stone cards in your deck. what if you then drew another stone card?
Oops! The game crashed:
[SMODS _ "src/utils.lua"]:3617: SMODS.create_sprite called with invalid atlas key: houserules_Consumable
it cant show it
i dont think that has anything to do with the file i sent you
Where to see list of Joker's attributes
tysm
How do I make it to where a joker makes cards with a specific enhancement to act as any suit?
what check should i write to detect if an Ante is changing
This isn't working help
hook the card:is_suit function
context.ante_change
(and additionally checking for context.ante_end means you only get ante changes if they're from beating the last blind of an ante and moving onto the next one)
thank you
context.main isn't a thing, did you mean context.joker_main?
oh.
local oldcardissuit = Card.is_suit
function Card:is_suit(suit, bypass_debuff, flush_calc)
local g = oldcardissuit(self, suit, bypass_debuff, flush_calc)
if next(SMODS.find_card('j_modprefix_key')) and SMODS.has_enhancement(self, 'm_modprefix_key') then return true end
return g
end
Oops! The game crashed:
[SMODS balatrohouserules "main.lua"]:259: Error processing file 'consumables/cherry.lua' for mod with ID 'balatrohouserules': [SMODS balatrohouserules "consumables/cherry.lua"]:37: unexpected symbol near ','
now what do i do?
what line does this code start at
25
maybe remove the commas in line 37 and 38
Alright, revisiting this after a while.
This snippet has where the function from engine/controller.lua is modified, but when I open the game, the Settings automatically open and all key presses are doubled.
bump
@daring fern There's nothing here that'd make it double the inputs, right?
It seems so, are you sure this is the function that's causing the problem?
I'm certain, because removing this part fully fixes the issue.
whenever i use this, it crashes
<@&1133519078540185692>
huh, did I missed something
does Balatro supports ogg
Yes, throw .OGG files in assets/sounds
thanks
This Joker's MaxSpeed value isn't working right.
Like at all.
calculate = function(self, card, context)
if context.individual
and context.cardarea == G.play then
if context.other_card:is_suit("Hearts") then
context.other_card.debuff = true
end
end
if context.joker_main then
local tmult = 0
for _, playing_card in ipairs(G.play.cards) do
if playing_card.debuff == true and playing_card:is_suit("Hearts") then
tmult = tmult + card.ability.extra.mult
end
end
return {
mult = tmult
}
end
end,
update = function(self, card, dt)
if G.play then
for _, playing_card in ipairs(G.play.cards) do
if playing_card:is_suit("Hearts") then
playing_card.debuff = true
end
end
end
end
any ideas on why the code doesnt count my debuffed cards
as in it doesnt output the mult
is_suit("Hearts", true) to count debuffed iirc
how do i get a joker to add money to a card with a specific enhancement when played
Is it possible to modify the Lucky Card enhancement when a certain Joker is held?
(Only the enhancement, not the odds in the entire game.)
what do you mean by modify
Change the odds to be guaranteed.
it is possible im sure without even hooking or taking ownership
if context.mod_probability and (context.identifier == 'lucky_mult' or context.identifier == 'lucky_money') then
return {numerator = context.denominator}
end
there it is
beautiful
what are you trying to do
Find the highest speed value over the last few seconds, while ignoring any nil values.
cursor's moving speed?
Anyone know of a way to create a deck that bans all vanilla jokers?
Yeah
local atpref = SMODS.add_to_pool
function SMODS.add_to_pool(prototype, args)
if G.GAME.selected_back_key.key == "b_modprefix_key" and prototype.set == "Joker" and not prototype.original_mod then
return false
end
return atpref(prototype, args)
end
Bless that worked, thank you !!!
how can i make a joker not move up and down when clicked on, just staying in place.
You would have to patch CardArea:align_cards
are there any example in mods you can think of? would just making it perma pinned be easier do you think
is there a way to make a joker make a card draw face down
tryna make a joker called redacted files
but i cant get the face down cards to work
oh shit i just deleted my code for the joker whoops
do you mean when you highlight the card?
when you click a card and it goes up and down
i'd just hook Card:highlight to return early under certain conditions
hook very scary tho
imagine a hook like this
replacing the function with what you want
and you grab the old function beforehand so you can control when the normal function behaviour is run
like
local old_func = func
function func(card)
-- only run normal code if condition is met
if card.area ~= G.jokers then
old_func(card) -- the function's existing behaviour
end
end```
No, they said they wanted the card to still be able to be selected but not move.
ohhh
ARGHHHHHHHHH I Hate Coding!
i'd still recommend learning hooks though, even if you don't need them right now
if the function usually returns a value, return the old_func
im going batshit insane
if context.stay_flipped and context.to_area == G.hand and condition then
return {stay_flipped = true}
end
Ok thx ill try to incoorporate thsi into msomtcoemdnikolb!
it worked, Thank you Somethingcom515 {Seals On Every}
bump
use context.playing_card_end_of_round instead
it works now, thanks!
how often is "in_pool" recalculated?
it is called directly when something is checking if it is in the pool, like when get_current_pool is called in create_card
technically could I make in_pool include a chance to return true, otherwise return false
obviously you can just use object weights
which is easier
and less stupid
And then there's the issue of it seemingly not actually scoring properly at all?
you were not the first btw
and this existed long before object weights were introduced
and the loc_vars not changing the nil values to say "Recalibrating..."
loc_vars only gets called every time the description pops up, not every frame
yeah, but it still doesn't even show up in the description
y'know, when it gets called
how would i make a seal retrigger a card a certain amount of times?
if context.repetition then return { repetitions = 420 } end
thanks
Managed to sort this out, theoretically, would it be possible for cards with one of the new suits(lets say roses) to gave an ability (probably xmult or retriggers)where it scales depending on the amount of cards with a matching suit in played hand or held in hand
Kinda like an enhancement
not directly, but you can use SMODS.current_mod.calculate to replicate that
How so?
have you wrote something with a calculate function before
No not really
Just got into this hobby
i would recommend making a joker first to familiarize yourself with that
https://github.com/Steamodded/smods/wiki/Calculate-Functions
https://github.com/nh6574/VanillaRemade/blob/main/src/jokers.lua
then you would do a similar thing but using SMODS.current_mod.calculate
Ok then cool
Thanks!!
If you want a video tutorial that goes over Calculate I have this here. The same exact principles apply to Mod Calculate https://youtu.be/1yWK09pzo0U
In this episode, I teach you how to make your first modded Jokers
Repo: https://github.com/the-Astra/ExampleMod/tree/Episode-2
Tools:
- DebugPlus: https://github.com/WilsontheWolf/DebugPlus
Resources:
- SMODS wiki: https://github.com/Steamodded/smods/wiki
- VanillaRemade: https://github.com/nh6574/VanillaRemade
Huge thanks toođ«¶
o7
ABGMBM
how do you make a crossmod joker i forgot
@viscid talon make sure the mod is installed
you can have multiple ways to do it
i do it two different ways on feli's jokeria
ah ok
dont take my function to check if a mod exists because i think theres one called next(SMODS.find_mod(""))
How would I get a list of jokers in the joker slots along with the current cards the player has in their hands
how would I remove an owned joker without destroying it?
its ok i think i figured it out
yippee first crossmod c:
can you explain the goal
I have a use button on a joker and want the joker to disappear after use, without calling smods.destroy_cards
G.jokers.cards
G.hand.cards
why not
the Joker creates an item that can create the used Joker afterwards, and since the mod has a Joker that scales each time a Joker is destroyed, you can just infinitely swap back and forth
does it use joker_type_destroyed
yeah
i think card:remove() is the only thing that bypasses that
yeah that works. thanks!
how i fix this
I'm trying to make the Standard tag give multiple booster packs, but it's creating both of these booster packs at the same time and it causes some very weird stuff to happen. How do I make it so the game doesn't create the 2nd booster pack until the first one goes away, or is there an easier way to create booster packs than this?
not really
you would need to wait for the booster to be closed to open another one and thats a bit of a pain
dang
alright i gotta get busy then
thx
how do I change the number of cards shown / number of cards to be selected in a booster pack?
I'm trying to get the cards within the play area when a round first starts after the cards flying from the deck animation. I tried hooking to new_round. But the number of cards is always 0.
local new_round_ref = new_round
function new_round()
local ret = new_round_ref()
-- print the amount of cards the player has in their hand
print("Number of cards in hand " .. #G.hand.cards)
return ret
end
I assume that function was calling before the hand was set, so I tried something similar with draw_from_deck_to_hand, but I don't see any of the print statements in the log.
local draw_from_deck_to_hand_ref = draw_from_deck_to_hand
function draw_from_deck_to_hand()
-- Do something before the original code
print("draw_from_deck_to_hand before")
local ret = draw_from_deck_to_hand_ref()
-- Do something after the original code
print("draw_from_deck_to_hand after")
-- print the amount of cards the player has in their hand
print("Number of cards in hand " .. #G.hand.cards)
return ret
end
What function should I be looking for in this context? Also I realized the animation to get the cards does not appear when you are loading a save into a round. Would I need to hook a separate function for that?
what's the aim?
I want to be able to print out all of the cards I have in my hand. So Ace of Clubs, 9 of Diamonds, 8 of hearts, etc.
I want to be able to check whenever the "state" of said hand changes. Whether that be from playing a hand, using justice on a card, doing a new run
try the first one in an event, like
G.E_MANAGER:add_event(Event({
func = function()
print(#G.hand.cards)
return true
end
}))
but honestly if you want constantly check for state you might as well do it in Game:update
Would update be too much if I want to check for multiple things such as jokers (including editions), hand levels, # of times each hand was played, money?
no, the game itself does it for some cards
vanilla has less reason to do it than you lmao
i has to check for the source of effects like that for https://discord.com/channels/1116389027176787968/1503867059698794588 but there's just too many ways to change things
the other way without update would be metatables imo
Sorry, for the boatload of follow up questions, but where exactly am I supposed to put this? I'm looking through the wiki https://github.com/Steamodded/smods/wiki/Guide-â-Event-Manager for events. And while I do see the condition property, I feel like using it gives me the same problem I am looking for now, which is checking when the hand cards length is greater than 0.
I can try to put this in update, but I would need to make sure that the user is in a game, and is in a round. Otherwise, I expect I will crash (like I did when I put this code inside my main file.) I don't mean for you to give me the answer, I'm just very noobish at this language and code
i meant in new_round
ohhhhh
you can also try
G.E_MANAGER:add_event(Event({
func = function()
if next(G.hand.cards) then
print(#G.hand.cards)
return true
end
end
}))
to explicitly wait until the hand has something but i think just an event might work
I tried doing this with small variations, but regardless of what the delay is, it seems to be printing immediately as 0
local new_round_ref = new_round
function new_round()
local ret = new_round_ref()
-- print the amount of cards the player has in their hand
G.E_MANAGER:add_event(Event({
trigger = "after",
delay = 10,
func = function()
print(#G.hand.cards)
return true
end,
blocking = false
}))
return ret
end
The closest I got was this version in which it printed 1 pressuambly bc 0 is a falsey value. If it's the same as JS
local new_round_ref = new_round
function new_round()
local ret = new_round_ref()
-- print the amount of cards the player has in their hand
G.E_MANAGER:add_event(Event({
func = function()
if next(G.hand.cards) then
print(#G.hand.cards)
return true
end
end,
blocking = false
}))
return ret
end
0 is truthy
but it makes sense because next(G.hand.cards) would be true if there's 1 card
i didnt expect it to run one at the time tho lol
i would try an event in G.FUNCS.draw_from_deck_to_hand then, like smods does for context.hand_drawn or if you are using the smods api then just check for that context
do you think i could set the payload to a pool so it picks a random joker?
No, you would have to get a pseudorandom_element from G.P_CENTER_POOLS.Joker
the pseudorandom stuff that balatro provides doesn't actually work properly outside of an actual game, because it needs a seed. i think that's the case in the vortex intro too
but yea you can set up the payload to just manually pick a random joker using math.random or whateverr
they specifically want a subset of jokers (probably ones from their own mod)
ah oki
I did some digging and I think certificate does what I want. It seems to add the new card after the animation is done. I'm not going to send the entire calculate function since it's large, but the part I'm sending is what I think I need.
calculate = function(self, card, context)
if context.first_hand_drawn then
pressumably this is where I would put the print statement
print(#G.hand.cards)
end
I'm not sure what you mean by the api calls. I'm aware of the documentation https://github.com/Steamodded/smods/wiki/API-Documentation, but I'm not sure how use them for functions in this context.
[[patches]]
[patches.pattern]
target = "game.lua"
pattern = "SC = Card(G.ROOM.T.w/2 - SC_scale*G.CARD_W/2, 10. + G.ROOM.T.h/2 - SC_scale*G.CARD_H/2, SC_scale*G.CARD_W, SC_scale*G.CARD_H, G.P_CARDS.empty, G.P_CENTERS['j_joker'])"
position = "at"
payload = '''
local jokers = {}
for k, v in pairs(G.P_CENTER_POOLS.Joker) do
if not v.original_mod then
table.insert(jokers, v.key)
end
end
SC = Card(G.ROOM.T.w/2 - SC_scale*G.CARD_W/2, 10. + G.ROOM.T.h/2 - SC_scale*G.CARD_H/2, SC_scale*G.CARD_W, SC_scale*G.CARD_H, G.P_CARDS.empty, G.P_CENTERS[jokers[math.random(#jokers)]])
'''
match_indent = true
that patch will give you any joker that is modded
if you have a specific set of jokers in mind, just put all the strings in the jokers table instead of doing the for loop
No, it gives any joker that is not modded.
v.key is the pool i want, right? or do i need to insert all of the specific jokers i want
you need to insert all of the specific jokers you want
so instead of the loop and the first line of the payload that somethingcom gave you, you'd just have this
local jokers = {
"j_smiley",
... -- whatever other joker keys you want
}
and then the last two lines of the payload can stay
bump
this happens when i hover over deck during a round
mods have a global calculate function so it would be something like
SMODS.current_mod.calculate = function(self, context)
if context.first_hand_drawn then
print(#G.hand.cards)
end
end
so even though this isn't a joker, I still want to use calculate?
yeah
thats what i did for playlog at least
and I theoretically want to use this function for all of the state data I want to grab mentioned before here #đ»ă»modding-dev message ?
do you want to grab the data every time something changes? if so there are some things that can't be done with contexts
yes
i would use update then lol
and what would that function look like?
is there a way to make the boss blind not change the background or music?
ModGlobal = { cards_in_hand = 0 }
local game_update_ref = Game.update
function Game:update(...)
if G.hand and G.hand.cards and ModGlobal.cards_in_hand ~= #G.hand.cards then
print(#G.hand.cards)
ModGlobal.cards_in_hand = #G.hand.cards
end
return game_update_ref(self, ...)
end
or something like that, checking for specific changes would be a bit more involved
if you have a specific list of what you want to check you might be able to find a function to hook for each tho
combining that with the calculate function
I do have a list. I'll send it as a file in order not bloat the channel.
Consumables means if they're used in the context of an ongoing round. Not like when you open a booster pack
ah if you want to check for the specific cards then it's a lot easier
in would recommend you check the link for my mod i sent earlier since it does all of that
Yes, the only reason why I mentioned money before was for jokers like bootstraps or shwashbuckler
since that affects their scoring value
Ok, thank you, I will check it out later. My brain is fried
sending a screenshot for context, you can probably check were i find each of these in the code
anybody know the sprite size for cardsleeves
Peak UI structure moment
No, it's 73x95
trying to make this trigger per negative joker owned much like baseball card does, how can i make this work? doesnt currently work.
oh ok
i do need help
youâre looking at the jokerâs center instead of the joker itself. try context.other_joker.edition.key
(the center is like the base definition for all instances of that joker, so it wonât have things specific to one copy of a joker like editions)
nope
oh wait yeah
its meant to act like how baseball card does btw
make sure the edition exists before getting its key
editionless cards have nil there
It should be if context.other_joker and context.other_joker.edition and context.other_joker.edition.negative
ok so what happens when i have to bump this 3 times
ok got it
unless vanillaremade is out of date i donât think editions have that?
I'm trying to modify the standard tag to open multiple booster packs, but if I just duplicate the booster pack code (or duplicate it under an add_event function), it opens all the packs at the same time and weird stuff happens. Is there an easier way to create booster packs, or how do I stop the next pack from opening until the previous one finishes? (should mention that I'm building this off of the standard tag from VanillaRemade)
they have
i just like checking the key more
iâd make the standard tag set a flag, then patch/hook the pack closing code to check for the flag: if itâs set, open another pack and unset it
i donât know where that code is unfortunately so i canât help with that
Well, preparing this kind of UI was a bit of challenge ngl
or maybe I not supposed to do all of that because back is center and I can just throw it into generate_card_ui isnt it
this has something to do with colors (specifically the color of vortexes) but idk how to fix it
nvm keep_base_colours = true was what was causing the problem
thats what i did for playlog
oh right
I stole some code from Galdur to make my life a liiiiitle bit easier xd
I was planning to extract detailed tooltips from rendered text but Eremel used solution with just checking parsed string
Is info_queue works for decks btw?
By that I mean info_queue[#info_queue + 1] = G.P_CENTERS.b_back, does it displays deck properly?
how do i implement a custom rarity
i think eremel is working on that for gladur in smods but i dont think so rn
is there anything in particular you want to know?
ijust want the template for adding in a rarity
like how to define it
oh and also how to give said rarity to a joker
hello
ah sadly nobody has made a repository with all the vanilla objects recreated..
(check vanillaremade)
rarity = "modprefix_key"
poop
is there a way I can see a giant list of all the context.types for tags?
eval
immediate
new_blind_choice
voucher_add
tag_add
round_start_bonus
store_joker_create
shop_start
store_joker_modify
shop_final_pass
i will add them to vanillaremade while im at it
tyty
I have this class in an seperate file from my main
-- game_state.lua
-- Class to hold the state that will be transferred to the calculator
local GameState = {}
GameState.__index = GameState
function GameState.new()
local self = setmetatable({}, GameState)
self.playing_cards = {} -- the playing cards in hand during a round
return self
end
function GameState:set_playing_cards(playing_cards)
local copy = {}
for key, value in pairs(playing_cards) do
copy[key] = value
end
self.playing_cards = copy
end
function GameState:print_playing_cards()
for _, card in ipairs(self.playing_cards) do
print(card.base.id .. " of " .. card.base.suit)
end
end
return GameState
When I try to call it in my main file, I get an error
-- main.lua
local GameState = require('game_state.lua')
local game_state = GameState.new()
local GameState = assert(SMODS.load_file('game_state.lua'))()
is there any way to use one of the weirder non-tag contexts with tags? (Specifically context.ending_booster)
Yes, you would have to use SMODS.current_mod.calculate and activate the tags manually.
what does that look like ;-;
ive never heard of this wizardry
is there a page on steammodded I can look at
oh nvm I found online help
tytyty
I'm trying to make an enhancement immutable and indestructible, maybe there is another way but my implementation won't work
## Make enhancement unable to be overridden; doesn't work
[[patches]]
[patches.pattern]
target = "card.lua"
pattern = '''
function Card:set_ability(center, initial, delay_sprites)
'''
position = 'after'
payload = '''
if self.config.center == 'm_lucky' then return {} end -- not even 'then return end'
'''
match_indent = true
## Make enhancement indestructable; doesn't work
[[patches]]
[patches.pattern]
target = "card.lua"
pattern = '''
function Card:start_dissolve(dissolve_colours, silent, dissolve_time_fac, no_juice)
'''
position = 'after'
payload = '''
if self.config.center == 'm_lucky' then return {} end
'''
match_indent = true
local oldcardsetability = Card.set_ability
function Card:set_ability(center, initial, delay_sprites)
if self.config.center.key == 'm_lucky' then return nil end
return oldcardsetability(self, center, initial, delay_sprites)
end
local oldstartdissolve = Card.start_dissolve
function Card:start_dissolve(dissolve_colours, silent, dissolve_time_fac, no_juice)
if self.config.center.key == 'm_lucky' then self.getting_sliced = nil; return nil end
return oldstartdissolve(self, dissolve_colours, silent, dissolve_time_fac, no_juice)
end
how do you change how much a joker takes up a slot again
Specify extra_slots_used in config.
tysmmm
I have this cod that gets the playing cards the in the hand when starting a blind
SMODS.current_mod.calculate = function(self, context)
if context.hand_drawn or context.other_drawn then
local cards = context.hand_drawn or context.other_drawn
end
end
Is there a similar way to that here when resuming a run from the main menu in this code? There's no context, so idk if it would be different
local game_start_run_ref = Game.start_run
function Game:start_run(args, ...)
if args.savetext then
print("Player loaded into a game")
end
return ret
end
G.hand.cards
if i'm trying to add a custom UI box around where the money and round counter is, would this be the area in the code i would want to inject stuff into?
how do you turn off this split screen
nvm i think i found it
just press x on tab
thank you
or, move it to right edge, also works
For some reason, this card is unusable with cards in hand despite having this as the condition
Nevermind. i put the code on the wrong fucking consumable
yeah that would do it
I've done the same thing before
you won't believe how hard it is to debug when the problem is "you're editing the wrong file"
Does anybody know what Drawstep order JokerDisplay uses for their information boxes?
it's pure UI
it's attached to the joker so they get drawn when their children get drawn
gotcha
may i know why youre asking
I want to put a button at the bottom of a card while it's selected, and order -30 was putting it behind JokerDisplay
i got around it by doing order = (JokerDisplay and 9999 or -30) to show it on top, but i wasn't sure if there was a better way
I figured since you can always see joker display even when the card wasn't selected, putting the button on top would be fine when it's selected
In Pokermon, in Smeargle's loc_vars , there's this piece of code to add a tooltip about the Joker that's being copied. Can anyone explain to me how that works in the end? There's a bug I'm trying to fix where variables in the card's name aren't being included
i don't think this should be necessary in the newest smods
hmm no i see what it's doing
copy is the card being copied btw, not smeargle itself, kinda confusing by just looking at this code
try adding vars = new_config too
and be in the newest smods dev
basically "name_text" didn't accept vars until recently, smods got around that by making tooltip names use "name" (and it also adds styling)
but adding a tooltip without the center bypasses that i think
or maybe it should be vars = other_vars.vars im not sure
i'll test both
{set = 'Joker', key = other_center.key, config = new_config, vars = new_config } doesnt work
or well, it's the same as before
what if you do vars = { "test", "test" } just to see
that's really weird
so the variables for the text are taken from config, but for the name are taken in vars
??
đ€·ââïž
Anyways thanks it works well
-- Wheelbarrow
SMODS.Joker {
key = "wheelbarrow",
config = { extra = { odds = 7, xmult = 1, xmult_gain = 0.2 } },
pos = { x = 6, y = 3 },
cost = 7,
rarity = 2,
blueprint_compat = false,
eternal_compat = true,
perishable_compat = true,
unlocked = true,
discovered = false,
atlas = 'HatchetJokers',
loc_vars = function(self, info_queue, card)
local numerator, denominator = SMODS.get_probability_vars(card, 1, card.ability.extra.odds, 'j_hatch_wheelbarrow')
return { vars = { numerator, denominator, card.ability.extra.xmult, card.ability.extra.xmult_gain } }
end,
calculate = function(self, card, context)
if context.stay_flipped and context.to_area == G.hand and SMODS.pseudorandom_probability(card, 'j_hatch_wheelbarrow', 1, card.ability.extra.odds) then
return {
stay_flipped = true
}
end
if context.press_play then -- quite literally pressing play
local count = 0 -- adds backfacing cards to table
for k, v in pairs(G.hand.highlighted) do
if v.facing == 'back' then
count = count + 1
end
end
if count > 0 then
card.ability.extra.xmult = card.ability.extra.xmult + card.ability.extra.xmult_gain
end
end
if context.joker_main then
return {
xmult = card.ability.extra.xmult
}
end
end
}
how do i make it so the joker gains xmult ONLY for played cards, not scored cards
You mean you want it to gain xmult for unscored cards?
no i want it to gain xmult for scored cards, not just unscored cards
I've been learning how to make buttons attached to cards, but how would I attach a button to the area above the deck here?
what do i dooooo
ok now it just doesnt work
How would I toggle on/off the button based on some certain condition, and would I need an SMODS.DrawStep for it?
No, you would change the visibility state of it, shown by the line below.
yall where does cryptid hide its thematic set code
Just looking at filenames, lib/gameset.lua I'd assume
-# you should probably look at spectrallib code for the same thing though to avoid dealing with cryptid codebase
trying to make paperback recognize vortexes as a light suit but its not working
yeah im looking for it
What is your mod's priority?
only reason why i didnt do that is because i believe that icons are neither a light or dark suit
oh no.
37
oh it works now, i think it was the priority because i changed it recently
How come the 2 text elements are next to each other horizontally despite being inside a column node?
How can this be fixed to always debuff 2 random cards for each discard
The cards must be currently held in hand or in the deck
calculate = function(self, blind, context)
if context.pre_discard then
blind.effect.discarding = true
end
if context.hand_drawn and blind.effect.discarding then
blind.effect.discarding = nil
local cards = SMODS.shallow_copy(G.hand.cards)
for k, v in pairs(G.deck.cards) do
table.insert(cards, v)
end
for i=1, 2 do
local card, index = pseudorandom_element(cards, self.key)
if card then
SMODS.debuff_card(card, true, self.key)
table.remove(cards, index)
end
end
end
end,
disable = function(self)
for k, v in pairs(G.playing_cards) do
SMODS.debuff_card(v, false, self.key)
end
end,
defeat = function(self)
for k, v in pairs(G.playing_cards) do
SMODS.debuff_card(v, false, self.key)
end
end,

you need to put both in row nodes
SMODS.Joker {
key = "celestine",
atlas = "CelestJokers",
pos = { x = 1, y = 0 },
unlocked = false,
rarity = 2,
blueprint_compat = true,
cost = 7,
config = { extra = { blind_percent = 5, suit = 'celestin_Vortexes' }, },
loc_vars = function(self, info_queue, card)
return { vars = { card.ability.extra.blind_percent, localize(card.ability.extra.suit, 'suits_singular') } }
end,
calculate = function(self, card, context)
if context.individual and context.cardarea == G.play and
context.other_card:is_suit(card.ability.extra.suit) then
return {
xblindsize = 1 - (card.ability.extra.blind_percent / 100)
}
end
end,
locked_loc_vars = function(self, info_queue, card)
return { vars = { 20, localize('celestin_Vortexes', 'suits_singular') } }
end,
check_for_unlock = function(self, args) -- equivalent to `unlock_condition = { type = 'modify_deck', extra = { count = 20, suit = 'celestin_Vortexes' } }`
if args.type == 'modify_deck' then
local count = 0
for _, playing_card in ipairs(G.playing_cards or {}) do
if playing_card.base.suit == "celestin_Vortexes" then count = count + 1 end
if count >= 20 then
return true
end
end
end
return false
end```
the unlock condition is failing to appear and idk why
Anyways, how would I get this to work properly?
extra = { message = "something", extra = { message = "", extra = {...}}}}
Is that comma at the end supposed to be there or is it a mistake
It is supposed to be there, because Lua supports trailing ,s.
Alr
is this legit the only way to do that
that scares me
yes but if you want it to look nicer you can make all the tables separately and then use SMODS.merge_effects to make the extra chain for you
ah, i see
how does the copy_card function work
im trying to make it so you cant remove a card and if u try to it just comes back but it does not work so im pretty sure im using it wrong
you need to do a couple more things, check DNA's code
or wait for the smods one that handles all of it for you
what does G.hand:emplace do ive never seen it before
it puts the card in that area
I'm trying to check when jokers are added to the area above, whether that be through spectral, tarots, or buying them from the shop. However, the code I have now seems to being getting planets, spectrals, and tarots as jokers as well. I thought I got over this by checking the joker area, but ig not. What do i need to fix in my conditional?
SMODS.current_mod.calculate = function(self, context)
-- get when a joker is added to the slot
if context.card_added then
local card = context.card
if not card then return end
G.E_MANAGER:add_event(Event({
func = function()
print(card)
if card.area and card.area.config.type == 'joker' then
game_state:add_joker(card)
game_state:print_jokers()
end
return true
end
}))
end
the consumable area is also of type joker
card.ability.set == "Joker" would work
So I should remove the two conditions I have as well?
nah, this is going to be just for vanilla
then that should be enough
without the emplace it just puts a card on screen that can be moved around but not selected but with emplace it just force closes the game but i need to put the card in the deck somehow so its not just floating on screen but i dont know how emplace works
G.deck:emplace(card)
question
how do i make a joker destroy an adjacent joker
(either a joker to the left or a joker to the right)
look at vtemade dagger
does anyone know how to fix this from saying ERROR when trying to make it apply all previous stakes
nvm dont answer that i figured it out
Is there an event/hook/function for when the player presses the main menu button?
G.FUNCS.go_to_menu
what file is that in? Follow up question, is there a way to open all the game code into vs code so I don't have to open one file at a time?
im using winrar
In your mods folder, the folder lovely has a dump of the game's code that is modified by all the mods you've enabled
Alternatively just extract the game exe like it's an archive file
functions/button_callbacks.lua
what's the difference between dump and game-dump
Nothing, but game-dump was supposed to also contain unpatched files.
Am I missing something here in order for this to work properly? I tried this without the self, but that didn't seem to make a difference
local go_to_menu_ref = Game.go_to_menu
function Game:go_to_menu()
print("go_to_menu before")
local ret = go_to_menu_ref(self)
print("go_to_menu after")
return ret
end
this is in my main file
that function doesn't exist
somethingcom said G.FUNCS.go_to_menu
is it possible to spawn a desired consumable inside of a pack for testing purposes
you can use debugplus to transform a card in the pack into it
oh, i see. I thought Game. and G.FUNCS. were used interchangebly
or do you need it to appear
i just want to test their usage inside of a pack
Game is the general game object while G.FUNCS is where the code for buttons and other ui is stored
eval dp.hovered:set_ability("c_key") while hovering a card on the pack
thanks
mwah
Unsure what the issue is now
local go_to_menu_ref = G.FUNCS.go_to_menu
function go_to_menu()
print("go_to_menu before")
local ret = go_to_menu_ref()
print("go_to_menu after")
return ret
end
function G.FUNCS.go_to_menu(e)
i feel dumb
Aren't we all
Dull white stake: Jokers have a 1 in 10 chance to be replaced by the default Joker when created.
are there any playing card template?
how would i make a spritesheet with all my custom jokers in it?
using aseprite to make them and im not sure how to do so
A grid of 71x95.
yeah but what i mean is putting all the jokers i've made into one spritesheet
is there an event/hook/function for when the player clicks a card and it is selected?
Card:highlight
...you just put them next to one another, keeping in mind the 71x95 per Joker in mind. Or use https://pinetools.com/bulk-batch-merge-images ?
local oldaddhighlighted = CardArea.add_to_highlighted
function CardArea:add_to_highlighted(card, silent)
if condition then return nil end
return oldaddhighlighted(card, silent)
end
how do i check if the selected blind is small blind specifically
context.setting_blind and context.blind.config.blind.key == 'bl_small' iirc?
config.blind
are there any playing card template?
you mean like this?

what does it do if an info_queue isn't tied to a center?
Shows it as-is
like attached to the card still or in an extra card area
I haven't tried the scrolling tho
can it do both ways (vertically and horizontally)
yes

that is such a nice way to satisfy both topics in a conversation
is there a list of tag contexts?
gotta make my own then ig
huh, why does discord keep stray forwarding message from a previously cancelled forward
welp, at least it's a separate message I can delete
how do you only add the scrollbar when it's needed
You'll not believe it, manual checks
how would i check if a playing card has any enhancement on it?
much appreciated
My peak checks for enhancement
what is context.source and why would it not have a set?
Because it's not calculate context
It's custom info context
It holds info_queue source, ability table, info_queue in various forms, to process it and display in separate UI in various forms
Like, serious shit is happening right here xd
if it has ability table, it has ability.set though, no?
Wouldn't their set still be not "Default"?
Yes but it's equal to check is key is not "c_base" isnt it
it is
Also this is like 
It's a check for card which created to display edition sticker etc in collection
Because, when card with seal in collection generates ui, it first adds a seal to info queue, and then somewhere inside this enigma it converts it into main description
If I'm not doing this result looks like this
what smods version?
1606b
is there a difference vs. having no oixel_size specified?
do the buttons alighting properly?
align
wgat about display_size
Display_size shorten the pixel size doesnt it ?
Not at all
trrue oops
Its fine
is there a function called when a tag is created within the tag
or should I use my mod calclate with the tag added context
im struggling to understand the smods api docs quite a fair bit,
been looking around trying to figure out how to make things like custom blinds & tags but to no avail
are there any good tutorials on this or is there anything im able to use as a template to learn from?
https://github.com/nh6574/VanillaRemade/tree/main/src vanillaremade here has Everything from vanilla recreated using smods
thanks a lot
@radiant spire G.UIDEF.run_info()
Thank you so much! You're the best
function CardArea:add_to_highlighted(card, silent, ...)
if true then return nil end
return StayTheStill(card, silent)
end```
how can i make this only work under a specific joker?
or just making one joker, i know true needs to be replaced but im not sure what with
i want one joker to not be highlighted when clicked, it doesnt matter that it cant be sold, because it destroys itself on click anyway
despite this card's atlas stating itself as px 71, py 67, and the card itself stating that it's px 71, py 67, the card displays stretched. why?
the hitbox is smaller, so at least that's working
do you have both pixel_size and display_size set on the card?
for whatever reason i cannot get this seal to work
no matter what i do it refuses to show up anywhere
the game and the file itself load fine, no crashes
i dont know what im doing wrong
do you know it's loading fine? is this your main file?
did you save the file
can you put a print statement in the file to ensure its loaded
^ that and if it doesnt work show the main file and your file structure
here
why r u sanity checking SMODS.Atlas
also
you have to put () after the assert()
its assert(SMODS.load_file(path))()
np
sorta just getting used to the smods api a little
still learning
How crazy would be to ask add mod badge in collection for seals, edition, stickers, etc?
i made a note about that the other day lol
I managed to extract them for my needs but have them in collection would be nice too
Editions actually have them, but stickers and seals is not
And blinds
But mainly seals and stickers
Question. What naming for info_queue process will be better: before -> individual -> after or pre -> individual -> post?
before and after probably
consistent with hand scoring
I was gonna say, whichever is used more often in other areas
Another question: better have separate classes for before/individual/after processed, or use smth similar to SMODS.DrawStep, where there's list of cases to trigger on and then you manially filter them
nvm I will follow SMODS.DrawStep example
Technically I can name it all calculate_ui and this will be funny but I more like it call processing
Glossary.InfoQueueProcessor let's go
how do i make a hook only work for a specific joker
What is the goal?
I this pure bullshit or is actual code? (My first time coding a joker)
You're setting the global variable xmult instead of scaling the card, also you should be using SMODS.scale_card
oh
i am trying to hook CardArea:add_to_highlight in order to prevent one joker from being highlighted, so the goal is preventing a joker from becoming highlighted in the joker cardarea
how i change it then?
so... how i scalate the card then?
whats the full code of the joker? in a txt file
and whats the joker trying to do
gimmie a sec
i already messed up the code i think TwT
if card.config.center.key == 'j_modprefix_key'
ty so much
SMODS.scale_card(card, {
ref_table = card.ability.extra,
ref_value = 'xmult',
scalar_value = 'xmult_gain',
no_message = true
})
where i put this
sorry if i make too many questions
whats the joker you have trying to do?
You put it where you want to scale the card.
every 6 scored heart cards, gains x0.2 Mult, starts at x1
What is the event called for when the r key is held to reset a run
Idk what i am even making
SMODS.Joker {
key = 'YourJoker',
loc_txt = {
name = 'YourJoker',
text = {
"{X:mult,C:white} X#1# {} Mult, Gains",
"{X:mult,C:white}X#2#{} Mult every {C:mult}#4#[#3#]{} Hearts Scored",
}
},
config = { extra = { Xmult = 1, XmultScalar = 0.2, Count = 6, CountOriginal = 6 } },
loc_vars = function(self, info_queue, card)
return { vars = { card.ability.extra.Xmult, card.ability.extra.XmultScalar, card.ability.extra.Count, card.ability.extra.CountOriginal } }
end,
rarity = 1,
atlas = 'YourAtlas',
pos = { x = 0, y = 0 },
cost = 1,
calculate = function(self, card, context)
if context.individual and context.cardarea == G.play and context.other_card:is_suit("Hearts") then
card.ability.extra.Count = card.ability.extra.Count - 1
end
if card.ability.extra.Count <= 0 then
card.ability.extra.Xmult = card.ability.extra.Xmult + card.ability.extra.XmultScalar
card.ability.extra.Count = card.ability.extra.CountOriginal
end
if context.joker_main then
return {
Xmult_mod = card.ability.extra.Xmult,
message = localize { type = 'variable', key = 'a_xmult', vars = { card.ability.extra.Xmult } }
}
end
end
}
there
you just made the code?-
indenting got lost in transit, but i tested and it works correctly
yeah
simple stuff
thank you!
youll learn after, good things take time
Np
at least now i know how it works... i think
No, you shouldn't be using Xmult_mod
No, you should be using xmult
is there a difference?
Yes, xmult adds the message automatically.
i see. i just copied some old code from my mod, didnt know there was a real difference
make sure to change the atlas part to your atlas for your sprites, and the key and name to the things you want
yeah
ngl, i was messing around with a friend's jokerforge mod (she let me do it) and i was trying to fix and optimize a joker with like 300 lines that didnt even work
jokerforge in their prime
jokerforge is kind of bad tbh, i couldnt figure out the gui too well and i only got things working when i stopped using it
i used it for a really basic mod and did work... then everything else kinda sloppy
because my mod were just jokers
when you touch anything more complex that "X happens, + 5 mult", it breaks
init_game_object techinically not the right one, but good enough
Can someone explain to me what .toml files are, and how to use them in this context? In my main file, I want to call a function when the wheel applies an edition to a joker. I'm looking at this code which is printing out the line in the screenshot. Kinda hard to see but it says "The wheel has applied Foil to Oops! All 6s" (https://github.com/nh6574/PlayLog/blob/6ae5f80776057377c2291dbb59d78d112dd9c27f/lovely/logging/consumables.toml#L78-L105)
My confusion is I don't see consumables being called anywhere in the repo, nor am I sure if I will be able to call the function I want since it comes from a metatable. Here is the pseudocode if that explains this better
-- in main.lua:
-- create custom object when mod is initialized
-- when wheel is used, call function from custom object
All toml files in a lovely folder are automatically loaded.
so if I do something like the first for my main file, and the second for my toml, I shouldn't get any errors, and the toml will know what game_state is?
local game_state = GameState.new() --custom object
[[patches]]
[patches.pattern]
target = "card.lua"
pattern = "eligible_card:set_edition(edition, true)"
position = 'before'
match_indent = true
payload = '''
game_state.print()
'''
No, because game_state is a local variable that only exists in that file.
Damn I finally did it
I've tried a few combinations of different randomization methods and lines to define variables, and yet, it won't debuff one single set, rather debuffs whatever the hell it feels like.
How do I force it to only randomize the number ONCE and use that to determine what set gets debuffed?
do it in context.press_play and save it to blind.effect.rank or something
and don't use math.random, use pseudorandom
if you want one for the whole round do it in context.setting_blind instead
so even this won't work if I refactor the game state to be a global singleton bc it's is also local in main?
-- game_state.lua
local GameState = {
playing_cards = {},
jokers = {}
}
function print()
print("a")
end
return GameState
-- main.lua
local GameState = assert(SMODS.load_file('game_state.lua'))()
[[patches]]
[patches.pattern]
target = "card.lua"
pattern = "eligible_card:set_edition(edition, true)"
position = 'before'
match_indent = true
payload = '''
GameState.print()
'''
[SMODS WildcardCollection "components/blinds.lua"]:444: attempt to index a nil value
correct
but there's nothing stopping you from just making a global table by removing the "local", although i'd recommend naming it after your mod's name just in case another mod makes a global "GameState" for whatever reason and they clobber each other
it should just be playing_card:flip()
oh also that print function that you define isn't even in the GameState table, so your usage in the patch wouldn't make sense even if GameState was a global
Right, it needs to be GameState.print
So somehow:
No cards debuffed
Every click randomly flips some cards
Can't even play a hand (Not Allowed! message appears)
Tables are difficult to wrap my head around when majority of languages you have worked with are oop
You need a context check.
Well, this solved the crash issue and the Not Allowed! issue.
But now there's no debuffs or flips.
You can't return debuff = true in context.hand_drawn, you have to use SMODS.debuff_card
That'd make sense tbh
what was wrong with my suggestion..
Well, I have a very bad case of "Oooh this makes the blind even harder, let's do THAT"
well but. if you don't know how to do one effect i would try to learn before doing another one you also don't know how to do đ
You are also correct there. But no one ever said I was a good developer.
anyway, what's the new effect
Either flips or debuffs the card.
i can see that but when
on draw
then yeah I would use SMODS.debuff_card there but you need to remember to rebuff them after
also this will debuff and flip cards that were already debuffed or flipped before
is there a function called within the tag object when its added to your current tagd
No, but there is add_tag
SMODS.debuff_card(playing_card, true, self.key)
Well, it fixed it for a bit, but it returns the same crash after a few hands. Still won't debuff cards.
Wait, which do I have to apply that to?
Both or the one in defeat
You would change both but the one in defeat would be false instead of true
We making the Shitfuck 78 with this one
yes , do you know playing cards font?
they always were
the only new multibox thing is main_start and main_end support
Oh wait shit I got confused
Gotcha
FUCK YEAH
Finally I dont have to die making ui for my stupid legendary idea
So I've been looking an looking, but can't find an answer anywhere
How do I make a Joker retrigger itself, until a random generated number is 2?
if context.retrigger_joker_check and context.other_card == card then
return { repetitions = 1 }
end
if context.joker_main then
baller = pseudorandom('baller', 1, 2)
print(baller)
if baller == 1 then
return {
message = 'Balling!',
Xmult_mod = 2,
repetitions = 1
}
end
end
end ```
I have this code but I cannot find out how to do this
if context.retrigger_joker_check and context.other_card == card then
local repetitions = 0
local number = pseudorandom('seed', 1, 2)
while number ~= 2 do
repetitions = repetitions+1
number = pseudorandom('seed', 1, 2)
end
return {repetitions = repetitions}
end
It still doesn't retrigger? (I have retrigger_joke = true above the calculate)
only one, I've tried both separately
here it is with both
Try putting it on a normal sized atlas and putting it at the top of the sprite and using pixel_size
pixel_size = { w = 71, h = 77 }
whilst the actual atlas itself is still 71x95 aligned.
ah, i'll give that a go
yay thanks ^^
nvm fixed it, I misunderstood the optional feature thingi đ
what does the base game use as a context for an end of round effect?
egg and rocket, when i played with them in comparison to my modded jokers, always triggered before my end of round effects
also, is it possible to fix the shader of Foil having the center of the shader offset from the middle of the joker if the joker isnt 71x95
context.end_of_round
i mean rocket's scaling effect
it triggers before any of my jokers
even though they also use end_of_round
Yes, they use SMODS.scale_card instead of returning a message.
is there any reason to ever use context.blind_defeated over context.end_of_round
to be honest I do not know what I did, but it broke and I do not have a clue why đ
if context.retrigger_joker_check and context.other_card == card then
local repetitions = 0
local number = pseudorandom('seed', 1, 2)
while number ~= 2 do
repetitions = repetitions + 1
number = pseudorandom('seed', 1, 2)
end
return {repetitions = repetitions}
end
if context.joker_main then
return {
message = 'Balling!',
Xmult_mod = 2,
}
end
end ```Here is the code
(I have this at the top:```SMODS.current_mod.optional_features = function()
return {
post_trigger = true,
retrigger_joker = true,
quantum_enhancements = true,
object_weights = true,
cardareas = {
discard = true,
deck = true
}
}
end```)
Remove the if repetitions > 0 check.
Oh thanks! that fixed it
how would you level up a target poker hand once
every example ive tried to find is either hardcoded or uses a mod's custom API
SMODS.upgrade_poker_hands({hands = 'modprefix_key'})
@sour rivet i think you need to make a loop
everything is a key (cards, jokers, etc) and you would need to loop through #G.hand.highlighted (i think) and check if the card's id is 2 or lower
i have a joker thats very similar that ill show you
you loop through context.scoring_hand or context.full_hand
G.hand.highlighted doesn't have anything during scoring
Right! Admittedly even these terms are a little foreign to me still, as this is my third(?) time touching lua scripts, but I think I can understand some logic..
-- Seven Sisters
SMODS.Joker {
key = "sevensisters",
pos = { x = 7, y = 0 },
config = { extra = { xmult = 3.5 } },
cost = 9,
rarity = 3,
blueprint_compat = true,
eternal_compat = true,
perishable_compat = true,
unlocked = true,
discovered = false,
atlas = 'HatchetJokers',
loc_vars = function(self, info_queue, card)
return { vars = { card.ability.extra.xmult } }
end,
-- Code by Somethingcom515
calculate = function(self, card, context)
if context.joker_main then
local passed = true
for k, v in pairs(context.full_hand) do
if v:get_id() ~= 7 then -- if even one card is NOT 7, its false. ~= is the lua equivalent of !=
passed = false -- the local "passed" variable is set to false
end
end
if passed then
return { xmult = card.ability.extra.xmult }
end
end
end
}```
ah i see
but yeah that code is basically it
i got super sevens mixed up with wheelbarrow đđ
but yeah
check through context.full.hand or context.scoring.hand
a local variable (you can name it whatever you want) will check if every card is ONLY 2 (or less)
and if it isnt, it will return a false value, and the joker will not trigger the xmult
here are some notes i made
k = key
v = value
the code above runs a loop for each corresponding key within the table.
everything within a table (whether its cards, blinds, etc) is assigned a key.
everytime the loop runs in the code, [k] is the index within the context (your full hand) while [v] is the card object itself. think of [k] as a search string and [v] as the card object. your loop is checking each card's ID. if even one of them ISNT a 7, the code will not run, hence why its set to false
credit to Somethingcom515, Meta and notmario for teaching me!
lua is a strange language where roughlyneverything has a table
I tried replicating this 1:1 (aside from changing a 7 to a 2) to see what happens - I feel like seeing it trigger will give better context here. In the "play around and find out" phase..
So that's what k and v mean!!!!!
(again, my coding experience is not a lot so pretty much everything is new. Feels like I need to learn to breathe here)
i would also recommend not naming them k and v and picking more appropriate names for each table you loop through
like in this case i would name them index, playing_card
Probably something distincitve enough in that'a'case, yes-
Would 'k' and 'v' cause problems with other cards trying to use them?
no because the variables only exist in the loop
So it's moreso a matter of legibility?
yes
Aha!
conflicting info đ
?
Another question! Can I possibly vary the pitch of a potential sound file used?
'Stead of going play_sound("modpack_soundbyte", 1, 0.7),
, have the program, say, pick a random value between 1.1-0.8 for pitch, then 0,7 for the volume?
I assume you can specify a little further above that, in this instance, "k" will be replaces with the term 'index' and 'v' with 'playing_card'...
via hooking, yes, easily
like, when you play it or when vanilla/any mod does?
The card makes a sound once it realizes the hand only contains 2's, but it repeating the same sound effect over and over can get grating-
yeah you can just use math.random() for it
I am also struggling with timing a little. The sound plays a little earlier than I'd like. I'm skimmign through the documentation to see if i've missed anything
instead of using play_sound you might want to return sound = "key" so it plays at the appropriate time
you would need a message too tho
you shouldn't call functions in the return
write it like this instead
In my defense I took it from another mod that is doing things a little differently it seems-
I'll keep that in mind!
card = card doesn't do anything btw
B-But it's funny.
sanity check
smh
But realtalk, I thought the card just needs to be punched with a "card=card" sometimes to make sure it doesn't forget what it is. But if it's not necessary I'll remove it to ease clutter
it's a remnant from old code that is used in vanilla but not smods, and it leads to people believing they should change card = something when they want to change where the message is displayed instead of using message_card
This is good to know! Thank you!
i know its just, k and v is what i was told to use in the past and its what the vanillaremade code says
it doesnt matter either way
if its only for one loop, who cares right?
I feel like it's a matter of taste!
i don't think it's taste necessarily, naming variables appropriately is very important
i made sure most of the vremade code uses actual names
I think it's common to teach programmers to use arbitrary variable names in for-loops, like in Python they might show for i in range(...): or for x in list: - or in JavaScript: for (i = 0; i < arr.length; i++) {...
But in practice it ends up leading to difficult-to-follow code. In particular, the Lua extension for most code development environments is often not smart enough to mark the data type/class that objects in an iterated table are. Hence, naming variables, especially in for-loops is important
This is one of those things you, uh, kinda have to unlearn
I personally think it's fine for numbers, i still use i a lot but even in python when I'm iterating through a list I also try to use proper names
relevant:
https://youtu.be/-J3wNP6u5YU
It's hard to come up with good names in code, but its also easy to get wrong. By looking at some examples, we can get 80% of the way there. Access to code examples, discord, song names and more at https://www.patreon.com/codeaesthetic
0:00 Introduction
0:31 Variables with a single letter
1:08 Never Abbreviate
2:06 Types in your names
2:36 Units...
Yeah there are a few cases where using single letters is fine, like numbers or indices - its common enough to use i for integer indices
(A more proper variable name, in a sense, would be index, but bleh)
nice
Probably multiple pages is not happening because it creates difficulties in terms of reloading ui
So big scrolling only way to save us
This is not what I envisioned the glossary to be but I guess itâs sort of useful
How does the vanilla standard pack choose some cards to be enhanced? I'm looking at the VanillaRemade code but it doesn't return enhancement like I assume it would. I'm wanting to modify the chance that a card is enhanced.
enhanced_poll is what you need
so if I wanted any card created to have the modified rate, I would hook the function to modify it?
any card in both shop and boosters?
any card anywhere yes
have you checked the code for the Illusion voucher?
you could do the same but with enhancements and also checking for modify_booster_card
SMODS.Joker {
key = 'galacticnova',
atlas = 'StarterPackJokers',
pos = { x = 2, y = 1 },
rarity = 1,
blueprint_compat = true,
cost = 2,
discovered = true,
loc_vars = function(self, info_queue, card)
local numerator, denominator = SMODS.get_probability_vars(card, 1, card.ability.extra.odds, 'j_stpk_galacticnova')
return { vars = { card.ability.extra.mult, numerator, denominator } }
end,
calculate = function(self, card, context)
if context.using_consumeable and not context.blueprint and context.consumeable.ability.set == 'Planet' then
card.ability.extra.mult = card.ability.extra.mult + card.ability.extra.mult_mod
return {
message = localize { type = 'variable', key = 'a_mult', vars = { card.ability.extra.mult } }
}
end
if context.joker_main then
return {
mult = card.ability.extra.mult
}
end
end
}```
trying to make it so that it has a 1/10 chance to be destroyed at the end of the round like gros michel, BUT gain mult like constellation, except it's mult and not x mult
what's the problem
it's a separate context so just have it as a separate if condition
haiiiii so i'm trying to figure out CanvasSprites on UI
i have this code, but:
- the canvassprite doesn't appear
- changing its w and h does nothing to the size of the box
can anyone help me learn how to use these? it's my first time, sorry
is it possible to change language color formatting ({X:attention,C:white}#7#) through local vars? I would like text to change color based on a number defined in local vars
How can I get and modify the calculated score?
before its added the current score, but after chips and mult are multiplied
okay, i know this is a complicated question, im mostly just looking for a little direction:
does anyone know how cryptid does the thing where you select the specific type of deck by clicking on it? specifically with a vanilla deck? or, alternatively, could someone point me to how i could do a "tainted characters" kinda thing for decks? pressing a button and switching to a variation of the deck, basically
cryptid likely hooks card:click to pull up a context menu
it does in fact do that
(bump)
you would need to patch the part that does that in G.FUNCS.evaluate_play
thx
there isn't like a final final scoring step because then it would have the same problem as final scoring step where it wouldn't really be the final thing lol
do decks use info queues differently?
cause i copied and pasted this from my spectral and it crashes
loc_vars = function(self, info_queue, card)
info_queue[#info_queue + 1] = G.P_SEALS["baggutro_blackseal"]
end,
decks do not use info_queue at all currently
i dont think there is a way to add a seal tooltip for a deck without galdur
or until galdur in smods
How would I add Text Motion Modifier 1 (the one that makes the word "probabilities" bounce around on oops) to a text UI element? I think it's possible, since every joker's name when hovering has Modifier 2 applied to the text
pretty sure you would have to use G.UIT.O with a DynaText object, not sure how the effect would be applied from there but i cant imagine its that complicated
you could probably look at how vanilla localization handles creating the dynatext
there will be in the next smods version... well, also assuming no galdur in smods before then
What function would I need to hook to get when a tag is clicked, since Tag.click seems to be nil
this is because tags are evil and entirely backend objects
you'd want to patch into Tag:generate_UI and set tag_sprite.click
is this gonna a conflict with other mods?
for slightly more compatibility, you can do a double hook
hook Tag:generate_UI and inside of that hook, hook self.tag_sprite.click if it exists and create it otherwise
i'm looking at a source dump that has cryptid for some reason, so I have no clue if the function actually exists by default. i don't think it does though
i think click should be there because it extends Node but idk
got an "unexpected symbol near }" error here (line 102) and i have no clue why
function CardArea:add_to_highlighted(card, silent, ...)
if self.config.center.key == "j_Krypton_LiamCat" then
return nil
end
return StayTheStill
end
what am i doing wrong to make this hook not work properly? i am trying to make a joker not become highlighted, and it just crashes with this error
yeah the tag when I do dp.hovered has a .click
yeah that makes sense
you can just hook it without caring about if it exists or not
-# the rare double hook
self is the cardarea here not the joker
the joker would be card
you also need to pass the arguments to the StayTheStill call
so in sync
function CardArea:add_to_highlighted(card, silent, ...)
if card.config.center.key == "j_Krypton_LiamCat" then
return nil
end
return StayTheStill(self, card, silent, ...)
end```
this?
that looks correct
okay next qeustion lol
how do I tell if the tag is in the collection
so i fixed that issue and a new one came up
send code
i did
probably by hooking Tag:init to actually save for_collection somewhere
or rely on the fact that set_ability isn't called for collection tags, not sure how that would look like though
oh that makes it easy i'm alreadyusing set ability
delete the end above if raised_card....
and likely move it to the bottom
raised_card is a local variable
if raised_card == context.other_card is out of scope
so raised_card will always be nil
Im trying to fix the flickering sticker in cryptid(currently does nothing lol)
calculate = function(self, card, context)
if not card.ability.flick_tally then
card.ability.flick_tally = 5
end
if card.ability.set == "Joker" then
if context.post_trigger and context.other_joker == card then
...other code
end,
The main problem seems to be that you need to fix other_joker to other_card but then the issue becomes that it triggers everytime the joker retriggers
and also doesnt trigger for jokers that activate on blind select(and maybe others i didnt test much lol)
Is there an easy way to fix this?
so just move raised_card out of the if?
What jokers did you test with?
hanging chad just counts as 3 triggers
jokers that give you something on blind select like burglar certificate etc just doesnt work
yeah
ight trying this
no that isn't your problem at all
i did your thing too
you don't need to move anything else
so its functional, apart from the part where it does something
currently it does nothing, but it doesnt crash
what's it supposed to do?
frick
change local temp_ID = 15 to local temp_ID = 0
oh yeah that makes sense
you're starting your highest value as something higher than any card
did this, still nothing
can you post your updated code?
SMODS.Joker {
key = "spotlight",
atlas = "CelestJokers",
pos = { x = 2, y = 0 },
rarity = 2,
blueprint_compat = false,
cost = 6,
config = { extra = {suit = 'celestin_Vortexes' }, },
loc_vars = function(self, info_queue, card)
return { vars = {localize(card.ability.extra.suit, 'suits_plural') } }
end,
calculate = function(self, card, context)
local raised_card = nil
if context.individual and context.cardarea == G.hand and not context.end_of_round then
local temp_ID = 0
for i = 1, #G.hand.cards do
if temp_ID <= G.hand.cards[i].base.id and not SMODS.has_no_rank(G.hand.cards[i]) then
temp_ID = G.hand.cards[i].base.id
raised_card = G.hand.cards[i]
end
end
if raised_card == context.other_card then
if context.other_card.debuff then
return {
message = localize('k_debuffed'),
colour = G.C.RED
}
else
return {
SMODS.change_base(v, card.ability.extra.suit)
}
end
end
end
end
}```
woah code wall moment
kinda ripped all this from raised fist
oh woops, i ripped it from something that used v
how can I differentiate between creating a tag when loading a save and creating a tag normally
i'm seeing self.from_load in tag:load but its not appearing in the object i see on the screen
so do i add something like not context.retrigger to stop it from triggering?
context.check_retrigger iirc
oh okay but then what about like jokers that activate on blind select is there also some context for that?
context.retrigger_joker indicates if you're being retriggered
i see yeah
that's not a thing, is it?
what would be the best way to load everything in a folder at once instead of having to do this for every line
idk i don't mess with joker retriggers
i vaguely remember seeing it like 3 months ago
i would recommend loading everything in a folder manually for more control
so do i just keep doing this
but you can use SMODS.NFS iirc to get directories and the folders within then
PPU probably has somethign
you could also make helper functions
how would i do this
my guy this is basic coding đ
hmmm yea adding not context.retrigger_joker didnt do anything
i have a function that does this if thats what you mean
i mean something more like this
ah
also do things like seals have to be in separate scripts or can i merge them into one
you can use any amount of files as long as it fits lua syntax
I have all of these for example
bump
Yes, tag.from_load is only for Tags, not HUDs or Sprites.
is there a way to differentiate or should I use ability
From the Sprite you could do sprite.config.tag.from_load
already tried that
assuming sprite is what is given by dp.hovered
this is where it needs to be checked
Yes, the tag there would have from_load when it's loaded and added.
it doesn't though
bruh it froze
when it reloaded the run I had another banana
cuase the on_obtain function was called again
You need to check before you call the old add_tag
ah
SMODS.Consumable {
key = "Krypton_GrindStone",
set = "Tarot",
object_type = "Consumable",
loc_txt = {
name = "Grindstone",
text={
"{X:attention,C:white}#2#X{} the {C:chips}Chip Value{} Of",
"{C:attention}#1#{} Selected {C:inactive}Stone{{} Card(s)",
},
},
config = { max_highlighted = 1, Multiplier = 2, enhancement = "m_stone" },
loc_vars = function(self, info_queue, card)
info_queue[#info_queue + 1] = G.P_CENTERS.m_stone
return { vars = { card.ability.max_highlighted, card.ability.Multiplier } }
end,
pos = { x = 1, y = 0 },
atlas = "TarotAtlas",
unlocked = true,
cost = 3,
use = function(self, card, area, copier)
local increasechips = math.ceil(G.hand.highlighted[1]:get_chip_bonus() * (card.ability.Multiplier - 1))
if increasechips > 0 and SMODS.has_enhancement(G.hand.highlighted[1], card.ability.enhancement) then
G.hand.highlighted[1].ability.perma_bonus = (G.hand.highlighted[1].ability.perma_bonus or 0) + increasechips
end
end,
can_use = function(self, card)
if #G.hand.highlighted <= card.ability.max_highlighted and SMODS.has_enhancement(G.hand.highlighted[1], card.ability.enhancement) then
return true
end
end,
in_pool = function(self, args)
for _, playing_card in ipairs(G.playing_cards or {}) do
if SMODS.has_enhancement(playing_card, 'm_stone') then
return true
end
end
return false
end
}```
how can i make my tarot card not crash the game when highlighted without a card highlighted?
You would check that G.hand.highlighted[1] exists before you use SMODS.has_enhancement with it.
Wait so if it checks context.post_trigger then does retrigger dont matter or something? Do i change it on trigger maybe idk
sick thx
infinite banana glitch has been patched
does pinned pin a joker to a slot? if so, can i make it always pin a joker to the 3rd slot over
leftmost
how does the base game hide the poker hand, level, and base chips/mult when one of the cards is face down
and can you replicate that
any idea why the tags set_ability isn't being called
how do i check if a planet card actually has a hand_type
im trying to level up the hand_type that a certain planet card has, but planet cards that dont have a hand_type just level up literally every hand_type
i want you to think about what you just asked đ
what hand_type do modded jokers that dont directly upgrade a specific poker hand have
you'd have to look at them individually
checking some of them, in cryptid at least, they just dont have one
i have no clue where to start with this so im asking here, how would one go about making a like "tainted characters" kinda thing for decks? like, press / click a button and the deck select screen changes and theres new decks there?
hook Card.click to open up a overlay menu
then modify some global that is used when starting a run with your deck
if card.ability.consumeable.hand_type
alright, thank you for the direction given, lets see how far i get lmao
i see that cryptid has "hand_types" as a config for some planet cards
is that a base smods thing or something they added
i would recommend waiting a tiny bit for smods to get a new deck select screen soon
it will have ways to add screens to customize decks
they added it
mine also has that but i use joy_hand_types :3
something that ive noticed with the Foil shader, and likely other shaders, is that on jokers with a pixel size other than 71x95, the "center" of the shader gets offset from the center of the sprite
is there any way to fix this on the side of the joker or is this a shader issue
the base game has the issue so i assume its probably not possible to fix
yea i'd imagine it's a shader issue, probably hardcodes the center's position rather than determining it on the fly based on the card's dimensions
someone knows what variable or something use so a joker show the initial deck size (Like erosion)
G.GAME.starting_deck_size
i put that in the text?
put it in your loc_vars
https://github.com/Steamodded/smods/wiki/Localization#loc_vars (loc_vars documentation)
thanks
again, send your loc vars code
i hate jokerforge code
that should be crashing, no?
your only returning 1 variable
your loc_txt requests 2
please go read this
.
.
.
.
yes?
1 sec
the #1# and #2# (image 1) point to positions within the vars table that you return in loc_vars (image 2), however because you only have one value in the vars table of loc_vars, #2# is returning as nil
ohhhh
Peak balala modding