#💻・modding-dev
1 messages · Page 667 of 1
card:add_sticker('modprefix_key', true) and card:remove_sticker('modprefix_key', true)
sweet
local new_card = copy_card(G.playing_cards[pseudorandom(pseudoseed('felijo_ins_revo'), 1, #G.playing_cards or 1)])
if card.ability.extra.count >= 5 then
new_card:set_ability(superior_enhancement)
end
G.E_MANAGER:add_event(Event({
delay = 1,
func = function()
new_card:start_materialize()
new_card:add_to_deck()
G.deck:emplace(new_card)
return true
end
}))
so it adds the card to an effective "deck" and i can't see it in the full deck view (53/52)
How can i add the card properly to the deck? (53/53)
if that's the final description, I think it's slightly unclear, I think mentioning X0 chips (if that's what it does?) makes more sense than "doesn't grant base chips" /lh /nf
i'm creating a card using Card(). how can i give it a button that appears when selecting it?
or does it not work like that?
u have to hook function G.UIDEF.use_and_sell_buttons(card) i believe
ah grand
i have one of those already, so i'll modify that
thanks!
how do i make a created card selectable?
i'm creating my own collection, but the cards can't be selected
wait i think i misunderstood
-# iirc Cryptid lets you "highlight" cards in the collections... so a Card:click() hook?
-# And/or Card:highlight(is_highlighted).
trues
bump
local function better_copy_card(card, new_card, area)
if not card then return nil end
local area = area or (new_card and new_card.area) or card.area or G.jokers
local cardwasindeck = new_card and new_card.added_to_deck or nil
local copy = copy_card(card, new_card)
if new_card and cardwasindeck then copy:remove_from_deck() end
if card.playing_card then
G.playing_card = (G.playing_card and G.playing_card + 1) or 1
copy.playing_card = G.playing_card
G.deck.config.card_limit = G.deck.config.card_limit + 1
table.insert(G.playing_cards, copy)
end
if (new_card and cardwasindeck) or not new_card then copy:add_to_deck() end
if not new_card then area:emplace(copy) end
return copy
end
better_copy_card(card)
hey yall, so i'm trying to make a blind that (similar to The Wheel) has a 1-in-7 chance of debuffing each card in your hand
loc_vars = function(self)
local numerator, denominator = SMODS.get_probability_vars(self, 1, 7, 'v_rainbow')
return { vars = { numerator, denominator } }
end,
collection_loc_vars = function(self)
return { vars = { '1' } }
end,
calculate = function(self, blind, context)
if not blind.disabled then
if context.to_area == G.hand and
SMODS.pseudorandom_probability(blind, 'v_rainbow', 1, 7)
then return { debuff = true }
else return { debuff = false }
end
end
end,
check vremade for the wheel perhaps?
i wanna use this for ease bg color but idk how
looks like it should work, though i've never made a blind
here's the vremade code for the wheel's calculate:
calculate = function(self, blind, context)
if not blind.disabled then
if context.stay_flipped and context.to_area == G.hand and
SMODS.pseudorandom_probability(blind, 'vremade_wheel', 1, 7) then
return { stay_flipped = true }
end
end
end,
not sure exactly what i'm missing in my case. either way, it's not doing anything on when testing, the cards all stay undebuffed
whoopsie
what is this btw
calculate = function(self, blind, context)
if not blind.disabled then
if context.stay_flipped and context.to_area == G.hand and SMODS.pseudorandom_probability(blind, 'v_rainbow', 1, 7) then
SMODS.debuff_card(context.other_card, true, 'v_rainbow')
end
end
end,
disable = function(self)
for k, v in pairs(G.playing_cards) do
SMODS.debuff_card(v, false, 'v_rainbow')
end
end
lemme try this
idk whata i'm doing here```lua
BustB.easebg = function()
ease_background_colour { new_colour = G.C.WHITE, special_colour = HEX('b00b69'), tertiary_colour = G.C.BLACK, contrast = 2 }
return (
#Cryptid.advanced_find_joker(nil, "busterb_Grandiose", nil, nil, true) ~= 0
) and 100.000
end
if you get the joker and the joker has this rarity, the background changes, but i don't fucking know how to make that happen.
seems like it works! thank you! it doesn't even need context.stay_flipped.
Now, say I wanted to debuff the cards in hand randomly each Discard and Play (so a card may be debuffed at one point, but then not the next instance of drawing cards). How would I go about this? Would I need to work with drawn_to_hand instead of calculate?
or would i need to use recalc_debuff?
i need the ui used for the consumables page of the collection, but i can't find the definition for it — where is it?
you should keep context.stay_flipped because that's the main context check, it just happens that to_area is only used by it but it could be reused and break the effect in the future
this one is used for all cards
https://github.com/Steamodded/smods/blob/a34d04b5ca927e1522037f7c5e471cccfd90542c/src/ui.lua#L2157
AltTexture({
key = 'joker',
set = 'Joker',
original_sheet = true,
localization = false,
path = 'joker.png',
})
TexturePack({
key = 'watson',
textures = { 'watson_joker' },
loc_txt = {
name = "Watson as Lucky Cat",
text = { "My cat, Watson,", "as Lucky Cat" }
}
})
any way to make it where its only lucky cat
keys?
it works!
here's the texture pack
oh i mean this one
ah no wait i think i found it
G.UIDEF.consumable_collection_page
thanks ^u^
How do I check each cards rank?
calculate = function(self, card, context)
if context.cardarea == G.play and context.main_scoring then
end
end,
https://github.com/nh6574/VanillaRemade/wiki#how-do-i-check-if-a-playing-card-has-a-specific-suitrank
i dunno what this calculate function is for, but you should only be using context.main_scoring for playing card modifiers fyi
My coder told me he can't directly do ÷mult, can someone help with code to solve that
Is it impossible to do ÷1.2 mult, should I just have it do X0.833 mult instead
Send X0.833 and change mult_message to however the fuck you were planning to stylize ÷
Alr
xmult_message sorry
How do I fix this, my coder was unable to themself
Jumbo rekoj is too small when turning a wee joker into them
They're the size of a regular joker when jumbo rekoj is supposed to be 30% bigger
Does that happen when Jumbo Rekoj is turned to Wee (Idk if that's in the video discord won't load shit for me)
Regardless my best bet is just setting Jumbo's T.h and T.w manually
Wee joker is the size it's supposed to be when jumbo rekoj is converted, however jumbo rekoj isn't
Interesting, might be something with how display_size is handled idk :/
Okay, I think I found the formulas for setting the size
H and W are probably locals in card.lua but I'm not home so can't check
I think it's still understandable, you would just have to use G.CARD_H/W
self.T.h = H
W = W*(center.display_size.w/71)
self.T.w = W```
what tools exist for mod testing? i want to be able to spawn in specific jokers or other cards to test that they're working as intended without needing to play until i find them
fast question:
how can I debuff a number card (like queen example) when you have a certain joker?
Is this the code already completed or something to punch the numbers into
Uhhh show that message to your coder they'll hopefully understand
iirc theres a function for debuff checks you could hook into?
might be thinking of something else
Run a check to see if you have the joker
That's all I got
if context.debuff_card and context.debuff_card:get_id() == 12 then
return {debuff = true}
end
thanks 👍
why are the cards not retriggering?
it didn't like not context.cardarea == 'unscored' 
how would I change rates for each of my custom consumables individually, and not by simply modifying the shop_rate value in the SMODS.ConsumableType definition?
oh, i would like to know how to do that too
don't think there's a specific easy way
but you can have each consumable set its in_pool function to only return true if a random number is greater than some arbitrary value
e.g. a fairly common one would check if pseudorandom("seed") > 0.2 while a rarer one would check if pseudorandom("seed") > 0.7
you can also set up rarities for the consumabletype, if that serves your purposes better than controlling every single consumable's weight uniquely
G.GAME.consumabletypekeybutlowercase_rate
oh wait
sorry i thought you meant modifying the rate overall midrun
i need to learnhow to read
would I be able to modify how rare each "rarity" would be? or am i locked to the standard "common, uncommon, rare" options? Both that, and the pseudorandom idea together might be just what I need then
yea you can set custom rarities
i haven't toyed with this personally yet so i can't help much further than just this documentation
How can you check what booster pack type you are currently in?
i think there's a context for that but i dont remember off hand
I think I found it, its SMODS.OPENED_BOOSTER.config.center.kind for future refrence
oh nice. thanks for sharing
Thx
Lmfao
I’m thinking of just making it state that the cards are worthless
ok so i managed to fix the scale with the delay_sprite arg, but i can't get the undiscovered floating sprite to go away when the item is locked
it would be nice if taking control of a joker's calculate wipes out the vanilla calculate entirely... needing to also use lovely to disable the vanilla effect is kinda weird
No, you can just redefine the name
does setting it to the same string not still let it see it's vanilla code?
No, you would redefine it as something else.
but i dont want to change its name
name is different from the localized name.
name is a property that most vanilla calculations check for instead of the joker's key
setting it to an empty string will (in most cases) make the joker not activate as normal
note that it won't work on all jokers
okay, does name go inside config or in the base take_ownership space? i dont see it in the documentation
inside the config
like SMODS.Joker:take_ownership("joker", {name = ""})
i meant the config field. your code snippet suggests i should do it like this:
config = {
extra = {
odds = 3,
seal = 'Gold',
},
},
okay, ill try this
it does not go in the config table, that's for values the joker uses like mult, etc
hmm, im still getting a crash, so ill post some info and hopefully i can get help figuring out what's happening
my code for rough gem:
{ -- table of properties to change from the existing object
name = '',
config = {
extra = {
odds = 3,
seal = 'Gold',
},
},
loc_vars = function(self, info_queue, card)
local numerator, denominator = SMODS.get_probability_vars(card, 1, card.ability.extra.odds, 'vb_rough_gem')
return {
vars = {
numerator,
denominator,
}
}
end,
calculate = function(self, card, context)
if context.before then
local suits = 0
for _, scored_card in ipairs(context.scoring_hand) do
if scored_card:is_suit('Diamonds') and not scored_card:get_seal(true) and
SMODS.pseudorandom_probability(card, 'vb_rough_gem', 1, card.ability.extra.odds) then
suits = suits + 1
scored_card:set_seal(card.ability.extra.seal, nil, true)
G.E_MANAGER:add_event(Event({
func = function()
scored_card:juice_up()
return true
end
}))
end
end
if suits > 0 then
return {
message = localize('k_upgrade_ex'),
colour = G.C.MONEY
}
end
end
end,
},
true -- silent | suppress mod badge
)```
the crash log. it's still trying to use ability.extra as a single number that rough gem has in vanilla
currently no other jokers are affecting this. rough gem i have it's name set differently and i even commented out its original code in a lovely toml
im using almost identical code in context.pre_discard and it works fine
Did you start a new run?
since when?
since you introduced this changed rough gem
if you didn't, it will still have the original ability values
it's the first time the joker has triggered in this run. does it not update the code of the joker calculate if i update the mod and load into the saved game?
the config values are default ability values
they don't get reapplied mid-run
that would ruin scaling jokers pretty bad
code does update, but those values don't
it's ability values should be what my code says. the mod was there before the run started
try replacing it with a new copy of the joker anyways
uh, okay. ill have to dig one up. do we have a debug tool for just giving specific jokers?
this documentation is very sparse. how do i actually use this to spawn a joker?
press 3 (or ctrl+3) on a joker while hovering over in it in the collection to spawn it
holding tab reveals all debug commands also
i see. okay. thanks. wish that was in the read me on the github. it doesn't even show up in the help text in console. okay. new rough gem in a new run functions as expected. ill keep that in mind going forward for testing
for reference, in the readme there's a convenient link to a list of keybinds
oh i missed tab for menu when i read it before. i was pressing 3 on the blind select screen thinking i might get a pop up or something asking me what i wanted to spawn. lawl
fair nuff, it's indeed a bit imprecise
now i know. thanks for y'alls help
np
How come when I try to insert this consumable (and all others under it) into my set, it gives this crash, despite the others above being inserted just fine?
My only thought process is that all the others above were copies of tarot cards, while these are copies of planet cards. . . not sure if that makes a difference but it clearly did something
It should be fuku_cards not fuku_Cards
is there a way to disable the current fps and base event queue text in the top corner when using debug plus?
yeah, there's a setting for it in DP's mod page
How do I change a single consumable's text at the bottom to be unique to the whole set, like how base game does with Planet X or pluto?
(and ik that's the joker page but it applies to consumables too. all centers iirc)
when using SMODS.poll_enhancement is there a way to exclude m_stone from its pool?
maybe like, do get_current_pool("Enhanced") and remove m_stone from the pool and pass that as args.options? i just dont know how to do that
so uncommon?

Is there any way to force redeem a voucher?
Card:redeem()
Specifically stone or any enhancements that replace the card?
Well commands are in a cooldown
1 min by default
But can be changed
i'd still recommend uncommon anyway lol
I should be having an alpha ready soon
just cause rare cards basically dont show up at all in shops
Just putting on finishing touches
based
if only i had a twitch, i'd play it :3
that's demonically funny, i love it
does it gameover you if you lose
also if i can make a suggestion, idk how doable it is
what about a blind that forces TwitchChat Plays? so it's the chat that has to help the streamer instead of just the streamer playing
why? because it's funny
ooooooo
Maybe for a release build
Backseat Gaming
But that sounds like a final boss thing
fair
stocks finally has art
i mean, so many streamers already do it for most games anyway lmao
lol!
command that force selects a playing card a la cerulean 
that'd be fucking evil
do it
Have a command that destroys a random card in hand
even better lol
May or may not keep it depending on how the alpha run goes
once this last joker is implemented alpha probably be available on github
one of the jokers is just a straight up copy of bull
so def need to change that
might make it a rare and give it a xchip mult for certain amout of money
Hello, does anyone know why this tag isnt doing anything? It just sits there doing nothing.
Tags don't calculate with joker contexts.
Ah; do you know a fix?
Wait, I think I know some workaround - thank you!
hm no this prob doesnt work
im getting a Unexpected <exp> error, is there something I forgot to close?
SMODS.Joker {
key = 'CurtainCalls',
atlas = 'Joker',
loc_txt = {
name = "Curtain Calls",
text = {
{
"Random Joker is retriggered"
},
{
'{C:inactive} Number Go Up{}',
'{s:0.8,C:inactive} Infinite jesters still get curtain calls.{}',
}
}
},
pos = { x = 0, y = 0 }
}
# Lemon Joker
no wait, # isnt comment, isnt it
comment is --
ive been using python a lot
This doesn't seem to work with vanilla vouchers, as they don't have a redeem function
Oops, must be Card:apply_to_run(center) then
That's where most of the voucher stuff is done it seems
I dont remember where i read it but I remember reading that I could mak my own one of these, how could I do that
thank you
evil cerulean bell be like
question: which command should I use for rounding divisions?
math.floor to round down, math.ceil to round up.
aight, thanks!
also nice to see ya again Ali!
To round to nearest integer, math.floor(num+0.5).
I made an enhancement that gives Xchips of the half of the current total $ if played.
And that gives $ of the half of the total chips scored in the current played hand.
There are 2 problems that I'd like to solve.
- the $ counter in the label text box doesn't update whenever I get new money
- for some reason the Mime joker's ability doesn't work on this enhancement
How can I fix both problems?
Hi fazzie
Eyo Sushi!
anyone?
We put a special command in the twitch mod for devs, mods, a vips of twitch channels
It's the text command
To display text on screen
Was originally gonna be a whitelist but we felt that that would make whitelisting easier without have to manually put usernames in
bump
- wdym $ counter here?
- for Mime to work, you have to evaluate within
context.individual,context.afteris mainly for jokers
wait, hold on
- basically I mean the number value of the half of the current total money that gets updated
kind of like stone joker's value in the text gets updated when you get more or less stone cards
You should probably just calculate the number each time in loc vars
Instead of repeatedly setting a value in the config
Just calculate what the value should be as you are now
that's how you do held-in-hand effect for enhancements
Except dont set to the ability table
so I should get rid of "dollars" in the config?
You dont need the config at all
oops
Would really move the death note logo down a few pixels
Because the chips amount will be 0 usually
Just so the sticker doesn't cover it
-# i mean that's where it is on the actual thing
How do I get a card ID from its base.value again? i.e. convert "King" into 13
SMODS.Ranks[key].id
thanks :>
so like this?
just return math.ceil(hand_chips/2) directly in loc_vars and calculate for the dollars
Instead of setting it in card.ability
so like this then:
remove the card.ability.extra.Xchips in loc_vars since that doesnt exist anymore
and leave the local variable current_money?
Yea
how do i pass arguments into create_option_cycle?
and, what do those arguments look like when the opt_callback gets them?
i have:
create_option_cycle({ options = consumable_options, w = 4.5, cycle_shoulders = true, opt_callback = 'phanta_deathnote_your_collection_consumable_type_thing', current_option = 1, colour = G.C.RED, no_pips = true, focus_args = { snap_to = true, nav = 'wide' } })
received by:
G.FUNCS.phanta_deathnote_your_collection_consumable_type_thing = function(args)
is args an empty table
usually the object gets passed
ah lemme check
this is what gets passed
ah i see
wait i don't get it ;u;
okay so args.cycle_config is passed in
ah ^^ okay i see
lemme try something then
it works now, thank you!
bump - anyone got any ideas? floating_sprite:remove() and floating_sprite = nil don't work
Use that new function I made and can’t remember the name of
SMODS.clean_up_children or something
SMODS.theNewFunctionEremelMadeThatTheyCantRememberTheNameOf()
i think clean_up_children is the name, but i call set_ability which calls that. i guess i'll try adding more calls in my code to see if that changes anything
It is possible they undiscovered flags aren’t adjusted in set ability
I can't understand why but my custom booster pack keeps placing multiple of the same joker inside when opened...
This is the pool for it:
SMODS.ObjectType({
key = "lamodSpawnable",
default = "j_lmd_multprint",
cards = {},
rarities = {
{key = "Common", weight = 0.5},
{key = "Uncommon", weight = 0.2},
{key = "Rare", weight = 0.25},
{key = "Legendary", weight = 0.05}
},
inject = function(self)
SMODS.ObjectType.inject(self)
end
})
And this is the booster code:
SMODS.Booster {
key = 'booster_lamonmod',
group_key = "k_lamonmod_booster_group",
atlas = 'jokers_lmd',
pos = { x = 0, y = 0 },
discovered = true,
draw_hand = false,
config = {
extra = 3,
choose = 1,
},
loc_vars = function(self, info_queue, card)
local cfg = (card and card.ability) or self.config
return { vars = { cfg.choose, cfg.extra } }
end,
weight = 1,
cost = 5,
kind = "LamonmodPack",
create_card = function(self, card, i)
ease_background_colour(HEX("ffac00"))
return SMODS.create_card({
set = "lamodSpawnable",
area = G.pack_cards,
skip_materialize = true,
soulable = true,
})
end,
ease_background_colour = function(self)
ease_background_colour_blind(G.STATES.BUFFOON_PACK)
end,
select_card = 'jokers',
in_pool = function() return true end
}
It keeps spamming the default joker, even when I only have 1 or 2 of the ones in the pool (There are 9 inside the pool)
it rolls rarity first so if there's nothing from that rarity it will get the default too
Ohh, is there any way to avoid that?
you would have to manually determine the rarity in the boosters create_card probably
I'll try making my own polling then, I guess. Thanks!
is Game:main_menu() called when returning to the main menu after winning/losing a run?
Yes, it's called whenever you go to the main menu.
You're calling math.min without a first input.
how comes the crash log say about line 57 then?
it doesn't know exactly where the error is so sometimes it will say surrounding lines
also if you knew the error was in line 57 it could have helped if you said what that line was when asking help lol
Because that's the line where you call math.min without a first input.
oh sorry thats my bad i didnt realise it wouldnt do the line numbers
okay thank you
I'm tryna apply a shader that tints these cards blue, anyone able to help?
Is there a rank variation of context.debuff_card:is_suit like ...:is_rank?
card:get_id() gets the id of the rank
but there's no get_rank
you can also use card.base.value for the key
Yeah, but I wanna avoid having the same issue of having to throw a true for an argument like the is_suit to have the Blind work
i think get_id counts debuffed cards normally
I pray it does.
-# Also, is the context for when a hand is played context.before?
depends on what you mean when a hand is played, any scoring context including before is technically when a hand is played
Then that'll work.
And finally:
What formats of video can Balatro play? I know .OGV is on the board, but can .MP4 work?
https://love2d.org/wiki/love.video.newVideoStream Just .ogv is supported by the engine itself.
Ah.
So how does one get a .OGV?
Nevermind, VLC can do it.
Ok, new issue:
It flickers. It doesn't even play the file.
Do balatro profiles check how many consumable cards you sold?
I want this for a joker unlock condition where you have to sell a certain amount of consumables.
Is there a context for when a card's rank changes?
change_rank
thanks!
We didn't even ping the mods
my card is supposed to not trigger if the scored card has a seal, but still does anyway??
i dont know what to do, im pretty sure i did everything right
It should be if not scored_card.seal
...i am BEYOND stupid ;w;
It should only be get_seal when you're not checking if it has a seal to apply a seal.
bump, anyone got any further insight into this?
so far i've been trying combinatinos of floating_sprite:remove(), floating_sprite = nil and SMODS.clean_up_children() but it still persists
actually, why don't i just remove undiscovereds from that pool altogether
crash on startup 
all i was doing was making manual edits to my mod config file via debugplus
you can just delete the saved config
doing that just causes my game to randomly CTD shortly after starting
well its probably not the same error
unless youre still saving something weird to config
oh it's because i'm copying a recursing table 
how do i distinguish between a keyed table and indexed table in code
oh i could just do #table > 0, right?
and if it is, it's indexed
well that won't detect tables that are both but probably good enough
yea there's not much of a distinction between keyed and indexed tables in lua
indexed tables are just keyed tables where the keys are the natural numbers in order
steammodded version is 1501a, and here's the code!
i did use jokerforge at first for the general mod structure, but moved to coding by hand cause jokerforge's pretty limited
hmm no idea, I'm guessing this is some problem with stone cards removing ranks that needs a more manual approach but i couldn't tell you rn
no worries, honestly i'm happy that my very first joker is actually working exactly as intended, even if it's visually messesd up :D
and yet, lua keeps keying my car 
opened an issue for this
it's essentially vanilla behavior (Vampire reveals the card front before sucking Stone), smods tried to "fix" it but failed I assume
iiinteresting, makes sense
this didn't work
therefore bump
local oldcenterdrawstepfunc = SMODS.DrawSteps['center'].func
SMODS.DrawSteps['center'].func = function(self, layer)
local thunk
if condition then
thunk = self.config.center.discovered
self.config.center.discovered = true
end
local g = oldcenterdrawstepfunc(self, layer)
if condition then
self.config.center.discovered = thunk
end
return g
end
is there a context for a card in hand being triggered? i want a joker to react to that. whether its gold or steel cards or a parking joker or whatever
no dice
No, you would have to patch SMODS.score_card
and something here is causing CTDs when starting a new run or continuing one
You should be calling oldStartRunBtn not G.FUNCS.start_run
The video only flickers instead of playing. Is it due to it being only 3 seconds in length?
oh i never changed condition 
having discovered result in true won't actually discover the card itself, right? since it's supposed to be locked
Yes, because it will change it back.
...what do i make condition, then?
not self.config.center.unlocked?
oh no, it'd need to be self.config.center.unlocked == false to account for nil
which would be everything that's locked
it's not specific to one item, it's all locked things
alright that seems like it works, thanks 
Here's the code I have currently. I don't get why it's doing this
anyone know what's going on with my scaling values here?
is this what you had before the new smods update?
me or them
you
this is what i'm writing because of the new smods update
then idk
Is there a way to make a joker detect the current ante level
G.GAME.round_resets.ante
Like I know it's possible to just make it update when defeating a boss blind or when a voucher is used but I also regularly do it with debug+ for testing purposes
I want it to give +3 mult depending on the ante level (ante 1 = 3 mult, ante 4 = 12 mult, etc.)
Would that still work there
G.GAME.round_resets.ante * 3 would do that, yes
So something along the lines of + mult = G.GAME.round_resets.ante * 3 or something
yes
Ok
ok so im making a joker that states that if the hand you play only contains cards of a certain suit then the hand is counted as a flush
return { vars = {card.ability.poker_hand}}
end,
calculate = function(self, card, context)
if context.evaluate_poker_hand and context.scoring_name == 'Three of a Kind' or context.scoring_name == "Five of a Kind" then
return {replace_scoring_name = 'Flush'}
end
end
}```
is this a good place to start?
thats how you change a hand, yes
have you tested that?
you would need to replace the check for 3oak and 5oak for one that checks suits
yeah i have and it works
ok gonna try that then
My coder is having difficulty lowering the cost of rerolls by $2
As part of a rekoj
It also increases the price of everything else by $1 but that part works fine
It's just the lower reroll price
G.GAME.round_resets.reroll_cost = G.GAME.round_resets.reroll_cost - 2
G.GAME.current_round.reroll_cost = math.max(0, G.GAME.current_round.reroll_cost - 2)
Thank you
loc_vars = function(self, info_queue, card)
return { vars = {card.ability.poker_hand}}
end,
calculate = function(self, card, context)
if context.evaluate_poker_hand and playing_card:is_suit('Spades', nil, true) then
return {replace_scoring_name = 'Flush'}
end
end
}```
ok i tried this but oops all crashes
playing_card is not a thing there
you want to loop through context.scoring_hand and check each card in that table
im in context.before and context.cardarea == G.hand and i need to check if specific other jokers exist. what's the function for checking if a joker is in hand?
if next(SMODS.find_card('j_modprefix_key'))
yes, that one. thanks
loc_vars = function(self, info_queue, card)
return { vars = {card.ability.poker_hand}}
end,
calculate = function(self, card, context)
if context.scoring_hand and not context.other_card:is_suit(card.ability.extra.suit) then
return {replace_scoring_name = 'Flush'}
end
end
}```
tried a thing with this but no dice lol
if context.evaluate_poker_hand then
local passed = true
for k, v in pairs(context.scoring_hand) do
if not v:is_suit('Spades', nil, true) then
passed = false
end
end
if passed then
return {replace_scoring_name = 'Flush'}
end
end
it says unexpected symbol near if
like the top if
wait hold on
ok it works
i messed up a line
thank you!!
how do you get discord to color the code block like that?
```lua
-- Code
```
._. how would i make this still allow straight flushes?
i tried to do and not context.scoring_name == 'straight flush' next to evaluate poker hand
but that didn't seem to do the trick
and context.scoring_name ~= 'Straight Flush'
ohhhhhhhhhhhhhh
the reason this doesn't work is because it evaluates it as (not context.scoring_name) == 'Straight Flush' which is always false
does anyone know how to add custom messages like the "extinct" message
I've been trying on my own for awhile and having no luck
sorry if this is like a stupid question
return {
message = "text",
}
wait that's it
all the resources online said to use stuff like "localize"
Thank you though
if you don't plan to localize your mod, returning plain text is fine
this is actually the choice of a lot of monolingual modders
making a mod is child's play
making a good mod requires real talent and knowledge
bro hitting me with the wisdom
in context.after can i check how many chips the hand just played is worth?
SMODS.calculate_round_score()
is that for just the one hand and not the entire round?
Yes.
makes sense
Is there a way to control what side of a card a tooltip appears in?
Nvm I found a way, I can override Card:align_h_popup()
candycane told me "you could just hook the function to change the swirls and have that loop through G.jokers"
i was asking about trying to ease bg color when a joker of a specific rarity is obtained
cause i don't know how to make a joker rarity affect the bg color when obtained
hook Card.add_to_deck
for the joker rarity checking?
local add_to_deck = Card.add_to_deck
function Card:add_to_deck(from_debuff)
add_to_deck(self, from_debuff)
if self.ability.set == "Joker" then
G.E_MANAGER:add_event(Event({func = function()
ease_background_colour_blind(G.STATE)
return true end }))
end
end
for the general call
you then patch ease_background_colour_blind to include rarity checking
actually, this is a bit complicated
payload = '''
if self.ability.set == "Joker" and self.config.center.rarity == 2 then
'''
...nah
No, it would be self:is_rarity('Uncommon')
then i replace G.STATE?
with new_colour = G.C.WHITE, special_colour = HEX('b00b69'), tertiary_colour = G.C.BLACK, contrast = 2?
also how do you want to modify bg colour based on rarity
rarer ones override more common ones?
Currently, this just works one rarity, but I plan to make it work when you obtain the higher rarities.
The whole thing just looks like this.
Idk what I’m doing bruh
[[patches]]
[patches.pattern]
target = "otherfunctionalities.lua"
pattern = "ease_background_colour_blind(G.STATE)"
position = "at"
payload = '''
if self:is_rarity('busterb_Grandiose') then
ease_background_colour_blind({ new_colour = G.C.WHITE, special_colour = HEX('b00b69'), tertiary_colour = G.C.BLACK, contrast = 2 })
end
'''
match_indent = true```
i'm a brainlet
I feel like I could use Cryptid.advanced_find_joker to check and then change background but idk how to implement it
for what reason might my added cards not be displaying their text?
-- in localization
c_vb_inverted_fool = {
name = 'The Inverted Fool',
text = {
"Reroll {C:attention}Rank{} of",
"#1# selected cards",
},
},
-- in main.lua
SMODS.Consumable
{
key = 'inverted_fool',
set = 'Tarot',
atlas = 'inverted-arcana-tarots',
pos = {x=0, y=0},
config = {
max_highlighted = 3,
mod_conv = 'rnd_rank',
},
loc_vars = function(self, info_queue, card)
return {
vars = {
card.ability.max_lightlighted,
}
}
end,
}```
figured it out. was declaring the mod in two places and it wasn't seeing the tags correctly
how do you get a Joker to retrigger a consumable?
You mean when you use a consumable it would trigger twice?
mhm
there's no general case for such thing
ah. damn
joker retriggers only work on consumables that has calculate, not use
unfortunate
however, for a specific set of consumables, you can do it within their use
local olduseconsume = Card.use_consumeable
function Card:use_consumeable(area, copier)
if condition then
G.GAME.modprefix_retriggering_consumeable = true
else
G.GAME.modprefix_retriggering_consumeable = nil
end
local g = olduseconsume(self, area, copier)
if not G.modprefix_consumeableretriggering then
G.modprefix_consumeableretriggering = true
if condition then
SMODS.calculate_effect({message = localize('k_again_ex')}, self)
G.E_MANAGER:add_event(Event({
func = function()
G.GAME.modprefix_retriggering_consumeable = nil
return true
end
}))
local ok, err = pcall(self.use_consumeable, self, area, copier)
if not ok then sendErrorMessage(err, 'MODID') end
end
G.modprefix_consumeableretriggering = nil
end
return g
end
ah yay, thanks!
wait catastrophic blunder
these consumables use calculate for effects
USE makes them active
;u;
sorry
i'll save that code, it looks very useful
so joker retriggers would work for that right
You would also need to hook CardArea:unhighlight_all and not call it if G.GAME.modprefix_retriggering_consumeable is true.
Yes.
Some days ago, N' helped me to make a consumable (that I made lots of time ago) have its "USE" button become active when you select 2 cards with a specific enhancement.
How can I make it that it activates if the 2 cards selected have different enhancements (while maintaining this condition?)
can_use = function(self, card)
if #G.hand.highlighted == 2 then
local chemical_list = {}
for _, playing_card in ipairs(G.hand.highlighted) do
if SMODS.has_enhancement(playing_card, "m_SM_red_chemical_card")
or SMODS.has_enhancement(playing_card, "m_SM_blue_chemical_card")
or SMODS.has_enhancement(playing_card, "m_SM_green_chemical_card") then
table.insert(chemical_list, playing_card.config.center_key)
end
end
return #chemical_list == 2 and chemical_list[1] ~= chemical_list[2]
end
end
so you're making a list of the highlighted cards and then in the return you make a condition that checks if the 1st one if different than the 2nd?
imma try this out rn
aight
it works now!
thx Huy!
how do you get this lil info flyout to appear? i thought the info_queue would do it, but it's not working for me
config = {
max_highlighted = 1,
mod_conv = 'e_polychrome',
extra = {
odds = 3,
},
},
loc_vars = function(self, info_queue, card)
info_queue[#info_queue + 1] = G.P_CENTERS.e_polychrome
local numerator, denominator = SMODS.get_probability_vars(card, 1, card.ability.extra.odds, 'inverted_wheel_of_fortune')
return {
vars = {
numerator,
denominator,
card.ability.max_highlighted,
localize{type = 'name_text', set = 'Edition', key = card.ability.mod_conv}
}
}
end,
pretty sure info_queue does that, probably that G.P_CENTERS.e_polychrome is wrong
hmm, i pulled that from the VanillaRemade code...
should work fine
the flyout just doesn't appear
is there a way to just make a lil message appear like how it happens when scoring cards, but i can just do it whenever i want focused on any given card?
SMODS.calculate_effect({message = "text"}, card)
i need to check something in context.repetition. my joker may return 0 here. how can i prevent a warning from being logged when 0 is returned?
(i realise this may be an XY problem)
ah icic ^u^ thank you
(for reference: https://en.wikipedia.org/wiki/XY_problem)
damn no preview
The XY problem is a communication problem encountered in help desk, technical support, software engineering, or customer service situations where the question is about an end user's attempted solution (X) rather than the root problem itself (Y).
I mean the root problem is returning 0, not the warning resulting from it
so yes it's an XY problem
👍
hey guys idk if anyone else has noticed this but why does dt behave like the game is running at 15fps this is really stupid
if youre game in 15fps then yes
1/dt should say 0.016 for 60fps
1/dt would say 60 for 60fps
dt would be like 0.006 or whatever
ok then how can i check game speed...
it's dt okay makes sense
how do i force a card to spawn with a certain edition?
(within the card itself, if possible)
what kind of card
consumable
...wouldn't set_ability be also present for defining consumables?
can you use G.real_dt?
thats a thing?
yeah
but also ive got a way of doing it with game speed accounted for
card.ability.extra.counter = card.ability.extra.counter + (dt/G.SETTINGS.GAMESPEED)
which works good
right but i'm not sure where to call it
set_ability = function(self, card, initial, delay_sprites)
-- do stuff here
end
This, I meant.
welp, if anyone ever needs it... heres how you detect whether the date has been changed if your joker requires on the date... LOL
add_to_deck = function(self, card, from_debuff)
card.ability.extra.month = tonumber(os.date("%m"))
card.ability.extra.day = tonumber(os.date("%d"))
card.ability.extra.t1 = os.time{year=tonumber(os.date("%Y")), month=tonumber(os.date("%m")), day=tonumber(os.date("%d")), hour=tonumber(os.date("%H")), min=tonumber(os.date("%M")), sec=tonumber(os.date("%S"))}
end,
update = function(self, card, dt)
if next(SMODS.find_card('j_jammbo_jam_santa')) then
card.ability.extra.counter = card.ability.extra.counter + (dt/G.SETTINGS.GAMESPEED)
if card.ability.extra.counter >= 1 then
card.ability.extra.seconds = card.ability.extra.seconds + 1
card.ability.extra.counter = 0
end
end
if card.ability.extra.seconds == 5 then
card.ability.extra.seconds = 0
card.ability.extra.t2 = os.time{year=tonumber(os.date("%Y")), month=tonumber(os.date("%m")), day=tonumber(os.date("%d")), hour=tonumber(os.date("%H")), min=tonumber(os.date("%M")), sec=tonumber(os.date("%S"))}
local difftime = os.difftime(card.ability.extra.t2, card.ability.extra.t1)
if difftime < 3 or difftime > 7 then
SMODS.destroy_cards(G.jokers.cards)
SMODS.calculate_effect({message = "Naughty!"}, card)
end
card.ability.extra.t1 = os.time{year=tonumber(os.date("%Y")), month=tonumber(os.date("%m")), day=tonumber(os.date("%d")), hour=tonumber(os.date("%H")), min=tonumber(os.date("%M")), sec=tonumber(os.date("%S"))}
end
end
SMODS.Joker {
key = "relay",
in_pool = function(self, args)
return true
end,
blueprint_compat = false,
rarity = 1,
cost = 4,
loc_txt = {
name = "Relay",
text = {
"Each scored card gains Chips",
"equal to the previous card's Chips",
"if it has a higher rank",
}
},
atlas = "test_atlas",
pos = { x = 0, y = 0 },
calculate = function(self, card, context)
if context.joker_main and context.scoring_hand then
print("---- RELAY DEBUG START ----")
print("Scoring hand size: " .. #context.scoring_hand)
local previous_card = nil
for i, scored_card in ipairs(context.scoring_hand) do
local rank = scored_card:get_id()
local base_chips = (scored_card:get_chip_h_bonus() + rank) or "nil"
print("Card " .. i)
print(" Rank: " .. tostring(rank))
print(" Base Chips: " .. tostring(base_chips))
if previous_card then
local prev_rank = previous_card:get_id()
local prev_chips = (previous_card:get_chip_h_bonus() + prev_rank) or "nil"
print(" Previous Rank: " .. tostring(prev_rank))
print(" Previous Chips: " .. tostring(prev_chips))
if rank > prev_rank then
print(" CONDITION PASSED (higher rank)")
local chips_to_add = (previous_card:get_chip_h_bonus() + prev_rank) or 0
print(" Chips to add: " .. tostring(chips_to_add))
else
print(" CONDITION FAILED")
end
else
print(" No previous card")
end
previous_card = scored_card
end
print("---- RELAY DEBUG END ----")
end
end,
}
I was wondering what context to use to make this work as the print is all correct
Also if you know of any other way to get the chips of the previous card that would be easier plz lmk
use context.individual, which evaluates each scored card separately and store the previous card (as evaluated) in either an ability value (that you should clear after scoring as not to mess with saving) or an upvalue
if it should properly work with retriggers, you'll have to consider that for the logic of changing the previous card (delay the change until all triggers are done), if not you should exclude retriggers
get_id() doesn't get you the card's scored chips either, and get_h_bonus() is for chips when held
you're copying the card but never adding it anywhere
Love it when that happened when I was devving sandcastle
do something like this
just make sure to not insert them into G.playing_cards while you're looping
Deb8ing if I want to develop this joker idea I've been thinking of
okok
why when i use get_current_pool("Tag") i get a bunch of UNAVAILABLEs? isnt get_current_pool supposed to return only working stuff?
it is to keep randomization consistent
it does
UNAVAILABLE is how it excludes items that aren't in pool atm
oh
i think latest release had a wrap function for getting the clean pool
ye smods has a new SMODS.get_clean_pool function that should remove the unavailables
SMODS.get_clean_pool() strips the unavailable entirely, if you want that for some reason
pog
Consider: Plural Joker
On spawn, does a bunch of numerical rolls to determine the odds for the joker for the rest of its existence
Then, every hand or so, it'll do a couple rolls.
- Develop a new ability?
- Which ability? Original or steal from an existing joker?
- Switch to a different ability?
- Which ability?
Idk if it's worth the effort
i think it would be really cool for a challenge run but maybe inconsistent enough for a high stake run
Hmm.
first thought, define a whole buttload of random minor abilities, then when it spawns it picks like 12 of them to shuffle between at the end of each round
depending on how minor the abilities are, the joker could have multiple active at once
it would definitely be hilariously complicated
should I required smods 1501a or 1503a since I need 1501a to work but 1503a is a bug fix ?
i would require 1503 personally but i don't think it strongly matters
Yeah, perhaps. That was the idea for the "original" abilities. Just from a huge list of minor abilities
Oh yeah and on spawn another roll to determine how many it starts with
I'm deb8ing if its worth the effort
I have it all planned out
1503
oh if eremel say it, I do it
It fixes quite a critical bug, and people will try and find 1501 is you specify that one because they are silly
How do I generate a joker image by using several other joker images dynamically?
For example, choose a hat, a costume and a background depending on the jocker's stats
you can use drawsteps
Where can I find documentation or examples on that?
Thanks, i'll give them a look!
What do you all think?
yeah
add tag tag tag
bro wants to add a tag 💀
the taglerrrrrr
event manager: add event (event)
yesssss
can't you do add_tag(tag) now?
that would be cool
pk;joker new
ok so I never did this before but, I made some booster packs of the same type (like the normal arcana packs) but I'm not sure how should I change the background when I buy one of them.
May someone please explain me how to do so?
bump
ohh
did you check vanillaremade boosters
from what I saw, each one of them has an ease background colour and a particles function with a plethora of built-in variables
i think I'm gonna check out what does each one of them
this is what i do in my mod
Is there an easy way to tell that a patch hasn't influenced the code, other than just making it break the game? Also any tips and tricks to how yall approach when a patch doesn't work as intended? I normally check if the target file is the right one or nested in the correct directory, then primitively copy-paste check if SMODS has made any adjustments
noticed that the Game object seems to lack an attribute describing how many discards have been used in total in the current run. is there a way to alternatively get this value for the purposes of an unlock condition
You can just check the dump files to make sure that the code you’ve tried to patch in is there
doesn't the garbage tag have something for that?
ohh it is unused
trading card and burnt have something that check if it is the first discard, maybe it is a counter that helps
I know the hands have a counter because I've worked with them
that's Game.current_round
you can up a counter in context.pre_discard probably
in the mod's calculate
can you do that in an unlock condition?
G.GAME.current_round.discards_used
no, you would need to do that globally and then use that value in the condition
^
yeah, so end of round you could take the value of that variable
how would i set up a global calculate
omg that is actually so helpful
does the dump always get updated to the latest run?
wow, reverse engineering +100
I mean, I first have to navigate the spaghetti of the base code, but if I link the dump folder to the navigation menu I guess that's as effective
i mean because if smods is patching it you will miss it, and sometimes smods just replaces stuff entirely
I guess if I do not know what causes the patched files to look what they look like there might be some dependencies, like I just found some function FNSJ.simulate_lucky_cat
I wanted to make it so both lucky procs update the cat
i doubt i implemented the variable and mod calculate properly
does anyone have a wireframe for this? api docs doesn't seem to help much here
can i see the code
SMODS.current_mod.calculate = function(self, context)
like i wrote it
it is described at the beginning of that page i linked
also it's not a good idea to make random globals, specially because it wont save bewtween reloads
fixed the G.Game casing too
where should i store it then
G.GAME
wait i can just add variables to G.GAME
yes
?
G.GAME.farts, ye.
peak
add the prefix so it doesnt clash
this crashes the game on boot G.GAME.pemonlist_discards_used = 0
don't do it outside the function
you don't need to
G.GAME.count = (G.GAME.count or 0) + 1
also i just realized your code will count more times than it should
you just check context pre_discard
idk how to type
you can, but G.GAME does not exist during load so you need to do so later
but you also dont need to intialize numbers anyway because lua
or 0 ah
+= does not exist in lua
sadly
i mean there is a good reason
what i thought it did
hmm
wrong reply?
i suppose my only other experience with lua is p8
yeah meant this
im assuming
this does not activate
iirc current round starts at 1, not 0
does round increment before or after setting blind
also if you want to do things once at the beginning of a game, reset game globals is better
tbh that context could be replaced with a context.game_start if it exists
it doesn't
but you dont need to initialize the value
it will be deleted in a new run
try printing that value to the debugplus console and see what it gives you
G.GAME.current_round is a table containing values related to the current round
is this just print "message"? haven't done prints in normal lua before haha
yeah
i mean usually you write print("message") but string calls do exist so the brackets are optional
that but i meant doing it in the console in-game which would be eval G.GAME.blahblah
got it working, thanks
am i fetching a custom loc_txt property incorrectly? im getting nil back
is adding these custom loc_txt properties even allowed?
localize expects a key in a localization file
yeah thats not how localize works
loc_txt is only for text tied to the object and does not allow for arbitrary localization fields
i see
you need to use a localization file, loc_txt in encounters are for the choices and descriptions
idk how it works in the library since i only used the hotpot one
yeah i should use the localization file
are custom fields allowed in the descriptions? im getting nil anyway
custom categories are not loaded by default
yes
then the issue is probably just the fact that the text is within another table
is it the wrong table? self.set returns enc_Step, or is game object set different from descriptions set
no i mean like
theyre within st_map_rps_play
and i dont think localize works with that unless the encounter mod changes that
is there a way to make that it should change the background color to a specific one?
I saw the ease_background_colour method but not much was explained about it
text does get fetched by the mod automatically
text is a field of the mod, it might be because my fields are custom
<@&1133519078540185692>
free money pog
yes, like in the screenshot lol
i just pick a random one between 2 but you can just use 1
mr beast one bililion dolar !!!!!
gun react?
one beastillion dollar
discord is being slow
oh there it goes
bro why do people not want other people to get free money?!? society would be fixed if everyone got free money
but this also returns nil, so i guess im just using localize wrong 
print(localize({ type = 'text', key = self.key, set = self.set, vars = { } }))
I'm kinda confused here
what does the ease_colour do in the line 39
and what is the difference between new_colour and special_colour?
(also do you know if I can find a doc reference to what both of those methids do?)
there are no docs
ease_color changes the rest of the ui like blind colours iirc
saddest story in 4 words
special colour is the other colour for the background twirl iirc
....I think I may understood what you mean
honestly, the best way to understand is to try it and tweak it lol
not saying asking questions is bad but it's not like i made the game so any knowledge i have i got it that way
aight, thanks still for the help!
i guess i could use this to have different descriptions for the some object
_
ive updated to the newest smods and lovely and now this happens in my mod when cards are created
the cards function fine, and they even look fine in the deck
how are you creating the cards
they even go fine when changing the enhancenemt my god
didnt know that was a thing
how can i change how much a joker costs to buy, during runtime? i want to make a joker with a semi-randomised cost
change card.ability.extra_value or whatever egg uses
if you want more precise control, hook Card:set_cost and change card.cost
wow thats bad
somethings broken somewhere!
@wintry solar :3
wait what about self.cost, can you change the cost of future rolled cards this way?
no, you would change it as the card is created
you could change future cost by modifying the prototype but that's bad practice
Huh
ohhh i havent realised that SMODS.GameObject is a prototype pattern... really cool structure...
does changing the prototype only affect that instance of the card? i was thinking of adding an additional set_ability function to cards, with scaling args to try and more neatly resolve the scaling issue that came out of my menu_cards migration and maybe also solve the extant thing with collections, too
Set ability works correctly?
yes
Interesting
How do I replace the title screen logo?
key = 'balatro', -- The key MUST be balatro, unsure if case-sensitive
path = [your asset path here], -- Starts in ...\assets\1x and ...\assets\2x
px = 333,
py = 216,
prefix_config = { key = false } -- Required
}```
godsend 🙏
the prefix config should still be needed, yes
otherwise the game just sees an atlas called modprefix_balatro, and the original logo's atlas isn't overridden at all
ah
How do you fix this happening above a joker
That’s sprite bleeding
How fix
2 pixel buffer between sprites
Basically some cards on your spritesheet are too close together
like this
They're all 2 pixels apart with a 1 pixel margin on the edges for the 1x atlas and double it for the 2x atlas, same as the vanilla atlas
check that card specificly
It happens with a lot of the jokers actually
hmmm
I only just noticed
Make sure the gap from the top of the file is also in check
?
there should be 1 pixel between the top of the file and the cards
same for all sides
Yes, everything is the same space apart as the vanilla atlas
Is the atlas size too tall?
I’m talking about the SMODS.Atlas
bruh
I'm not the coding guy
can you send the atlas code?
Where is the atlas code found
No
it depends on your mod
that's where mine is so im guessing ;-;
Having an individual atlas file is very nonstandard I’m ngl
But if it works for you then cool
There is no atlas.lua anywhere in the mod
Ask your coder where they are then
is your mod public on github yet or no
Yes but a very primitive build, I have yet to update the github zip
I can send the most recent one
could you send a link
It's untested however
I just need to look through the files
not actually run anything
oh
Like I said I have yet to update the github upload
weird its fine
nothing wrong here
the inconsistent spacing is killing me but there isn't anything wrong
69x93 with a buffer of 1px of transparency on all sides, hence 71x95
yeah, but the buffer makes it 71 95
When did 93+1=95?
both sides
Oh
93+1+1
trying to achieve an effect but dont even know where to start
want to make a joker that changes cards to clubs suit if they are adjacent to a clubs suit card while scoring
before or after cards are scored
after i would like
heres what I would do
during the after scoring context
iterate through each played card
check neighbors if clubs
make played card clubs if so
how would i check neighbouring cards?
for i, card in ipairs(G.play.cards):
if i ~= 1 then
local left = G.play.cards[i - 1]
end
if i ~= #G.play.cards then
local right = G.play.cards[i + 1]
end
end
return { vars = { localize(card.ability.extra.suit, 'suits_singular') } }
end,
calculate = function(self, card, context)
if context.after and not context.blueprint then
if i ~= 1 then
local left = G.play.cards[i - 1] == v:is_suit('Clubs', nil, true) then
local scored_card = context.other_card
G.E_MANAGER:add_event(Event({
func = function()
assert(SMODS.change_suit(scored_card, nil, "Clubs"))
scored_card:juice_up()
return true
end
}))
end
end
if i ~= #G.play.cards then
local right = G.play.cards[i - 1] == v:is_suit('Clubs', nil, true) then
local scored_card = context.other_card
G.E_MANAGER:add_event(Event({
func = function()
assert(SMODS.change_suit(scored_card, nil, "Clubs"))
scored_card:juice_up()
return true
end
}))
end
end
}```
tried this but it did not work lol
syntax error?
it said unexpected symbol near then
you did
local left = true then
line 5 of the calculate function
if you give me like 5 minutes I can fix it
im on my phone rn soo
i'd feel bad if you did it for me D:
i'll try to make some changes
if it doesnt work
then u can fix it
this is wrong
if context.after then
for k, v in pairs(context.scoring_hand) do
if (k > 1 and context.scoring_hand[k-1]:is_suit('Clubs')) or (k < #context.scoring_hand and context.scoring_hand[k+1]:is_suit('Clubs')) then
G.E_MANAGER:add_event(Event({
func = function()
SMODS.change_base(v, 'Clubs')
v:juice_up()
return true
end
}))
end
end
end
calculate = function(self, card, context)
if context.after then
for k, v in pairs(context.scoring_hand) do
if (k > 1 and context.scoring_hand[k-1]:is_suit('Clubs')) or (k < #context.scoring_hand and context.scoring_hand[k+1]:is_suit('Clubs')) then
G.E_MANAGER:add_event(Event({
func = function()
SMODS.change_base(v, 'Clubs')
v:juice_up()
return true
end
}))
end
end
end
end
}```
i did this and it's no longer crashing, but the suit change still isn't happening D:
ok i changed
context after
to context individual
and card area == play
now it works
thank u
No, it can't.
o
i wanna do this from now so
how would i remove vanilla jokers?
just the jokers
i know pokermon does this
i mean
referencing pokermon's code sounds like a pretty good idea
i would guess it iterates over G.P_CENTERS and adds in_pool = function() return false end and no_collection = true to all the vanilla jokers
local smods_add_to_pool_ref = SMODS.add_to_pool
function SMODS.add_to_pool(prototype_obj, args)
if prototype_obj.set == "Joker" and
(not prototype_obj.original_mod or prototype_obj.original_mod.id == "Balatro") then
return false
end
return smods_add_to_pool_ref(prototype_obj, args)
end
you can add whatever other condition to the if there
or that
i'd add this to the .lua file?
pokermon doesn't do no_collection, it's a setting that toggles whether the joker pool is restricted to only pokermon's jokers
yes, keep in mind this will remove all vanilal jokers as long as the mod is installed if you just paste it like that
huh, i thought it removed them from the collection too
oki np
it works!! thanks
plus they still appear in the collection
which is fine by me
How do I fix this
code?
It's supposed to make cards and packs in the shop increase by $1 while lowering the price of rerolls by $2
I think this is it
You're supposed to lower the reroll prices in add_to_deck
?
add_to_deck = function(self, card, from_debuff)
G.GAME.round_resets.reroll_cost = G.GAME.round_resets.reroll_cost - 2
G.GAME.current_round.reroll_cost = math.max(0, G.GAME.current_round.reroll_cost - 2)
end,
remove_from_deck = function(self, card, from_debuff)
G.GAME.round_resets.reroll_cost = G.GAME.round_resets.reroll_cost + 2
G.GAME.current_round.reroll_cost = math.max(0, G.GAME.current_round.reroll_cost + 2)
end
local oldcardsetcost = Card.set_cost
function Card:set_cost()
local g = oldcardsetcost(self)
if self.ability.set == 'Booster' then self.cost = self.cost+1 end
return g
end
Can you put it all together so I can send it to my coder whole please
SMODS.Joker {
key = 'magician',
unlocked = false,
discovered = false,
rarity = 1,
cost = 1,
atlas = 'Jokers',
blueprint_compat = false,
pos = { x = 1, y = 11 },
set_badges = function(self, card, badges)
badges[#badges+1] = create_badge('Bizarro', G.C.SECONDARY_SET.Spectral, G.C.WHITE, 1)
badges[#badges+1] = create_badge('Bonus', G.C.RARITY.Legendary, G.C.WHITE, 1)
end,
add_to_deck = function(self, card, from_debuff)
G.GAME.round_resets.reroll_cost = G.GAME.round_resets.reroll_cost - 2
G.GAME.current_round.reroll_cost = math.max(0, G.GAME.current_round.reroll_cost - 2)
calculate_reroll_cost(true)
G.E_MANAGER:add_event(Event({
func = function()
for k, v in pairs(G.I.CARD) do
if v.set_cost then
v:set_cost()
end
end
return true
end
}))
end,
remove_from_deck = function(self, card, from_debuff)
G.GAME.round_resets.reroll_cost = G.GAME.round_resets.reroll_cost + 2
G.GAME.current_round.reroll_cost = math.max(0, G.GAME.current_round.reroll_cost + 2)
calculate_reroll_cost(true)
end
}
local oldcardsetcost = Card.set_cost
function Card:set_cost()
local g = oldcardsetcost(self)
if next(SMODS.find_card('j_modprefix_key')) and self.ability.set == 'Booster' then
self.cost = self.cost+1
end
return g
end
Thank you
i want this joker to make spades and clubs held in hand at end of round give $1, but it doesn't work (likely because i have a slightly wrong context)
the only thing in vanilla that does something like this are gold cards... and their code in vremade uses a base config of h_dollars, so i don't have any reference here
calculate = function(self, card, context)
if
context.cardarea == G.hand and
context.end_of_round and
context.game_over == false and
(context.other_card:is_suit("Spades") or context.other_card:is_suit("Clubs"))
then
G.GAME.dollar_buffer = (G.GAME.dollar_buffer or 0) + card.ability.extra.dollars
return {
dollars = card.ability.extra.dollars,
func = function()
G.E_MANAGER:add_event(Event({
func = function()
G.GAME.dollar_buffer = 0
return true
end
}))
end
}
end
end
throw a context.individual in there
ah okay thank you
just as a question (if you know), what exactly is context.individual? i see it used mainly in stuff related to cards played/held in hand, but i haven't really definitively known what it means
i dont think you need so many contexts either. context.individual and context.end_of_round and your suit check
ignore this i was wrong
it's used when evaluating individual cards
i mean i guess that makes sense lol
so in this case, you're looking at each card in hand (context.other_card) to see if its spade or club
i've seen context.game_over == false used quite a bit with things for context.end_of_round
shrug, it seems superfluous to me but it shouldn't hurt anything
that's fair
it doesn't matter too much, since events pause when the game over window pops up
ah okay
one more question: the joker seems to juice twice per eligible card held in hand
i assume this is due to the event shenanigans, but i'm unsure since i believe i've used this exact setup before due to it being used for the code in vremade's reserved parking
i dont think you need the dollar buffer code. i think just returning the dollar value will be enough. check if you're getting double the money. or just try commenting it out and see if it still works
i know it'd theoretically work; i'm just wondering if there's some kind of easy/common solution for this since the event manager block is used for timing with other possible things out of my control
i think it's fine though
with joker calculates basically all of the timing and messages get taken care of automatically from just the returns. but im not entirely sure what you're trying to do
anyone know how i can grab the entire contents of the full deck. i want to check each card in it for stuff
dollar buffer is more for other effects that happen at the same time, if you only return dollars those other objects won't know you added money because it happens in an event
til
i did try to make it automatic but it causes some issues with legacy support https://github.com/Steamodded/smods/issues/709
i'm pretty sure you can just iterate through pairs(G.playing_cards)
i.e. for checking enhanced cards for a joker in my mod:
if G.playing_cards ~= nil then
local enhanced_count = 0
for k, v in pairs(G.playing_cards) do
if v.config.center ~= G.P_CENTERS.c_base then
enhanced_count = enhanced_count + 1
end
end
card.ability.extra.mult = enhanced_count * card.ability.extra.mult_mod
end
You should be checking if next(SMODS.get_enhancements(v))
instead of the if v.config.center ~= G.P_CENTERS.c_base?
Yes.
Yes.
how would i get this condition to search for cards of the given suit in the unscoring portion of the hand? at the moment the game just crashes upon playing a hand
if context.cardarea == "unscored" and (context.other_card:is_suit("Hearts") or context.other_card:is_suit("Diamonds")) then
i'm pretty sure that i have to replace other_card with something, i'm just not sure what exactly
You need context.individual
ah, okay
funny given that my last issue was solved through the context as well 😭
does context.round_eval exist?
Yes.
okay; what could be the reason on why this doesn't reset its dollar amount then? by the way, i assume that context.round_eval is occurs after the payout; though, i may be incorrect
local triggered = 0
if context.cardarea == "unscored" and context.individual and (context.other_card:is_suit("Hearts") or context.other_card:is_suit("Diamonds")) then
SMODS.scale_card(card, {
ref_table = card.ability.extra,
ref_value = "dollars",
scalar_value = "dollars_mod",
message_colour = G.C.MONEY
})
triggered = triggered + 1
end
if context.round_eval then
card.ability.extra.dollars = math.max(1, card.ability.extra.dollars - (triggered * card.ability.extra.dollars_mod)) -- this is for compatibility with value manipulation
triggered = 0
end
triggered is set to 0 every context.
ah
is there a context that would work for this effect? context.round_eval ends up occuring before calc_dollar_bonus; i'd like it to preferably occur right after, but i'm not sure how feasible that is without simply using context.starting_shop
obviously context.starting_shop could work, but i kinda want it to have perfect timing such that the reset occurs directly after all dollar "calculations" on the payout screen have finished
does anyone know how to properly check what booster pack is being opened?
if context.booster.kind == 'Arcana'
Thank you
hey so im trying to make this consumable that wins the blind instantly when used. it gives the chips, but the blind doesnt end and you still need to play abother hand. im also try ing to get it to display text, but while i can make a joker do that, it doesnt work for a consumable in the same way from what i can tell.
SMODS.Consumable {
key = "shutdown",
set = "CMD",
cost = 4,
atlas = 'CMD',
pos = {x = 4, y = 0},
loc_txt = {
name = "C:\_shutdown",
text = {
'Immediately wins the blind',
}
},
can_use = function(self, card)
return G.GAME and G.GAME.blind and G.GAME.blind.chips
end,
use = function(self, card, area, copier)
local half = math.floor(G.GAME.blind.chips)
G.E_MANAGER:add_event(Event({
func = function()
play_sound('tarot2', 0.76, 0.4)
card:juice_up(0.3, 0.5)
G.GAME.chips = (G.GAME.chips or 0) + half
if G.hand_text_area and G.hand_text_area.game_chips then
G.hand_text_area.game_chips:update_text()
end
-- Trigger win check
if G.GAME.chips >= G.GAME.blind.chips then
G.FUNCS.win_round()
end
return true
end
}))
end,
}
if a card has zero or one enhancement, will SMODS.get_enhancements() still return a table or just the single value?
It always returns a table.
can i do SMODS.get_enhancements()[1] to just grab the first one without needing to store the table?
No, the table is string indexed.
that's so annoying. how do i just get a card's enhancement?
card.config.center.key
okay, just confirming. will this work? trying to just copy an enhancement from _source to _target
local _enhance = G.P_CENTERS[_source.config.center.key]
_target:set_ability(_enhance, nil, false)
Yes.
okay thanks
blarg... still not working...
kay, but you confirming it should work let me find the issue. checking against the wrong extra value 🤦🏼
_enhance.key
I'm trying to figure out how to add custom challenge rules to my mod, and found myself looking at this snippet of code in game.lua for starting a game.
Would I hook into this area of the function, add a check for my custom rule to change a self.GAME.modifiers variable to then use in other hooks to do what I want?
Or am i thinking about this all wrong?
Yes, just do rules = {custom = {{id = 'modprefix_variable', value = value}}}
So, I understand how to hook functions, but from what I've seen you can only insert code at the beginning or end, but I'm not sure how to add code to the middle. How would I go about adding a hook to Game:start_run() to actually set my self.GAME.modifiers value when my custom rule is used?
No, I mean yes, you're thinking about it wrong, you just need to put rules = {custom = {{id = 'modprefix_variable', value = value}}} in your SMODS.Challenge definition.
oh, so would value = value be my self.GAME.modifiers.WhateverRuleIEndUpCallingIt = true then?
or however I want to store it?
Is anyone experienced with modding willing to take a look at some disgusting chatgpt modified yorick code I've been messing around with that's been crashing?
No, 'modprefix_variable' is what you want to call the variable and value is what you want to set it to.



