#💻・modding-dev
1 messages · Page 668 of 1
can someone please tell me why this doesn't actually ease the blind's score? it changes the value of G.GAME.blind.chips but there's no visual display
G.E_MANAGER:add_event(Event({
trigger = 'ease',
ref_table = G.GAME.blind,
ref_value = 'chips',
ease_to = 1000, --dummy value
delay = 0.5,
func = (function(t)
return math.floor(t)
end)
}))
blind chip text is based on the value of G.GAME.blind.chip_text
its a little dumb but that is how it works
roger that, is lua gonna throw a fit if i throw in the desired value wholesale into chip_text or do i need to perform some kind of string conversion?
i thiiink its safe to put chip text as a number but just try it and see
(i don't program in lua often 😭)
note that chip text won't overwrite the value in chips and you still have to change that
yeah yeah
when you want to update it as a whole, do this:
G.GAME.blind.chips = new_value
G.GAME.blind.chip_text = number_format(G.GAME.blind.chips)
G.GAME.blind.chips hold the actual value you need to reach to beat the round
it can be as precise as 52.454751647856478
G.GAME.blind.chip_text is the text version of G.GAME.blind.chips with proper format so that it's short enough to be displayed, in this case it's 52.5
i love you
thank you so much
Im trying to get a loop going of checking 3's in a Three of a Kind, not triggering.
if context.before and (next(context.poker_hands['Three of a Kind'])) and not context.blueprint then
for i = 1, #context.scoring_hand do
if context.scoring_hand[i]:get_id() == 3 then
card.ability.extra.ThreeCount = card.ability.extra.ThreeCount + 1
end
end
if context.joker_main and not context.blueprint then
if card.ability.extra.ThreeCount >= 3 then
card.ability.extra.ThreeCount = 0
return{ xmult = card.ability.extra.xmult}
else
card.ability.extra.ThreeCount = 0
end
end
end
your context.joker_main check is inside context.before
if context.joker_main and context.scoring_name == 'Three of a Kind' and context.poker_hands['Three of a Kind'][1][1]:get_id() == 3 then
return {xmult = card.ability.extra.xmult}
end
well, you may want tighter checks for it
yeah that weas it, thanks
Is there a way to make multi-line challenge rules work? do I just have to add a separate rule that does nothing for each extra line that I want to add?
this snippet won't work if first scoring card is rankless or from splash effect
also it won't work as i forgot te context of needing 3 threes in the played hand
but its working now
Is this the best way to implement this?
is there a way to render a tag so that you could read its description?
since jokers are centers i just made CardArea and put them there, no idea how to do the same for tags
Pretty much, yeah x'3
how come my custom context within a tag never triggers, but
but inside a joker it does trigger
non-code related question for y'all here, but how would you refer to "hands per round" in a description when it comes to a card that ISN'T giving them to you? My specific use I'm using this for is for a joker which gives xmult based on how many hands you have, but any way of writing it I can think of gives off the impression I'm talking about the "remaining hands" rather than the full per round amount, lol
oh. tags use a different thing??? how do i send a calculation for tags 
per starting Hand?
loop through G.GAME.tags and call apply_to_run on each of them
insane, but sure
it works, ty
Tag calculate when 
🥶
struggling with implementing an ability that doubles the values of consumables
i have code but it's not working
is there a standard way of value-manipulating things?
i currently have:
function smsn_multiply_all_berry_values(mult)
for i = 1, #G.consumeables.cards do smsn_multiply_berry_values(G.consumeables.cards[i].ability.extra, mult) end
for _, v in pairs(G.P_CENTERS) do if v.set == "Berry" then smsn_multiply_berry_values(v.config.extra, mult) end end
end
function smsn_multiply_berry_values(berry, mult) -- We shouldn't recurse down nested tables, in case a Berry wants to keep track of playing cards, or such.
for k, v in pairs(berry) do if type(v) == "number" then v = v * mult end end
return berry
end```
I saw that in the last smods version, context.end_of_round now also has the winning hand. How do I get it? Is context.end_of_round itself the winning hand?
oh it's context.scoring_hand / context.full_hand, neat
using cryptlib mostly
mm. not touching that then
theres also #1406740128231194644 's value manipulation
which is compatible with cryptlib
Consumable value manip works strangely, yeah
I haven't had to deal with the in-and-outs in a few months but I seem to remember there also being differences in how vanilla vs modded consumables are handled, as well as consumables like the suit or enhancement tarots vs those with their own dedicated use function
right, ya
okay so, forgive me if this question is simple, but I haven't modded in a while so I'm not really able to recall exactly how I'd've done this before, but how do I check for the amount of cards of a certain enhancement in my deck and use that as a variable? I want to make something sorta like cloud nice here, but with enhancements rather than rank! :3
But for just doing it with a custom type, your solution seems entirely sufficient
i'm lucky, i'm not messing with those ^u^
I wouldn't use an API for that, no. Though if you ever want to, I'd gladly help with setting up a compatibility standard for Blockbuster up for ya
oh wait! Isn't there a github for this? with all the base game jokers remade? I wish I had that saved somewhere lol, that may help here lol
no there isnt
oh thank you!
much appreciated <3
dont believe his lies
oh, okay, lmao sndfjk heh
vanillaremade is a collective hallucination
when we open the github we have a 1 in 2 chance to create a tarot card
god i love vanillaremade
who doesnt
i wish vanillaremade existed when i started
I can tell I'm back in my balatro phase, cuz I'm getting a joker idea from every basic concept which comes up in conversations lmao
hmm
firstly, 1$ cost
secondly
Scored Aces give +1 Mult, +1 Chips, and earn $1
lmao
did I get the vibe right? sdfd
peepee poopoo
is there a non-cursed way of running a function when a card with a custom edition is clicked on? i'm trying to play a sound on top of the usual card select sound effect if the card has said edition
i could hypothetically add an update that checks if the card is highlighted, but i strongly prefer not running things per frame if an alternative exists
you think only one Ace or each ace is funny
hook Card:click()
sure, that works
This is the first thing I see when I wake up btw
Like today, woke up to this 😭
is this a kappa deck n oway
it's nothing special just starts a run with a twitch related joker that's it
also
May or may not release the alpha today

trying to code an effect that converts +mult effects into 2.5X value +chips, however it's not working
-- Thanks, TOGA's Stuff!
local calcindiveffectref = SMODS.calculate_individual_effect
SMODS.calculate_individual_effect = function(effect, scored_card, key, amount, from_edition)
local astros = SMODS.find_card("j_smsn_astro")
if scored_card.config.center.set == "Joker" and next(astros) and key then
if string.lower(key) == "mult" or string.lower(key) == "mult_mod" then
key = "chips"
amount = amount * astros[#astros].ability.extra.chips_times
end
end
return calcindiveffectref(effect, scored_card, key, amount, from_edition)
end```
the effects happen normally, but also give +chips
why?
oh also Onyx Agate is unaffected
sre u want +chips or xchips
i said +chips, ya
how do i modify the card selection limit? i remember seeing it on the smods wiki but i can't find where exactly i found it
ah found it
nevermind
wdym?
is it actually giving the mult or is it just the message?
mult and message
iirc
lemme check
aha. just the message
i see why then
it's not removing the mult message
it's because mult_mod effects have the message seperate, they don't use the built in smods auto-message functionality
G.jokers.cards[#G.jokers.cards]
this is checking for if itself is the rightmost joker?
no, that gets the rightmost
@willow plinth how are you getting this self detected dupe?
ahhh i see
what do i do then ^^;;?
you can remove the message from those effects, but the message might not always be specifically the mult one for some modded stuff
i see
i think that's okay ^^
if i'm changing the scoring then i can change the message too
how would i remove the message, though?
effect.message = nil
ah grand ^^ thank you!
got quips working
there's a specific easter egg quip i have where it switches the card used to a reskin of itself with a ifferent soul texture.
this, however, doesn't keep the stake sticker as on the real joker card and thus creates an inconsistency.
is there a way to force two cards to share the same stickers?
-# i have another regular joker pair i'd like to do this for too
...do you explicitly need it to be a different Joker? You could just change what textures are used for base and soul.
yeah
that's what i want for the custom quip joker
as for the other one, it's partially inspired by the Jekyll/Hyde gimmick of Brainless Kitty from Qualatro and follows the same gimmick. I'd want to merge those too since i did that before but it was a little buggy with tooltip displays not being updated or showing the other state
-# swaps between a buff/debuff joker upon condition
on another note i can't quite figure out how to replace the vanilla quip pool upon use of the custom quip (since it's joker-conditionahle), so i just have its weight set to 999999999
would want to proof this though so i don't have to rely on workarounds
you can put a quip_filter on your mod object to remove all the others
wait, it has to be a hook? even for a custom joker or
what eris said
basically if you want to change the value you can change card.cost but it will get reset when something calls set_cost on it
i see. does the original set_cost return anything?
or do i have to get the initially determined cost by calling the original set_cost first and then adjusting it afterwards?
oh, it doesn't
anyone got set_edition documentation? 
i'm rifling through the smods wiki and for some reason can't find anything
why does it not show up in search 
search is not good for the wiki sadly
thats why i made the vremade one be all in one page
how do you create a random card from a pool?
i'm changing my Hanafudas to use pools instead of booleans in their configs
SMODS.add_card({set = 'poolkey'})
thanks ^U^
hey guys is it posibel to make a joker look iff there are ohter cards it need, Fx lets say i have to cards that can combin and i wanna look if boths cards are there befor it is abale????
next(SMODS.find_card("your joker key here"))
thx man
ya npnp ^^
how would I go about setting a variable inside a challenge rule description? I would assume it's some sort of #1# like others use but I'm not sure where the variable would be set.
custom challenge rules will use whatever is set as the value for it in #1#
im fairly certain at least
yes
i tested with no mods but smods enabled to ensure it's an smods issue - i'm guessing it's because i'm on macos?
why does my aero color card have a suit and rank??? 😭
lmao
I have also noticed this today
i also got the same "effect" briefly on a death card from revo's vault
it's when you copy a card
i see
also obviously i only have one smods and it lives in Mods/smods (as it should?)
maybe my launch script is also complicating things
i have it like this (which works but i don't think it's the "vanilla" lovely file):
#!/bin/bash
gamename="Balatro"
exename="$gamename"
defaultpath="/Users/$USER/Library/Application Support/Steam/steamapps/common/$gamename"
export DYLD_INSERT_LIBRARIES=liblovely.dylib
cd "$defaultpath"
lovefile="$defaultpath/$gamename.app/Contents/Resources/$gamename.love"
if [ ! -e "$lovefile" ]; then
ln -s "$gamename.loves" "$lovefile"
fi
./$exename.app/Contents/MacOS/love "$lovefile" "$@"
how do you poll a pool?
so i guess if defaultpath was a relative path i would be fine
i see how create_card does it, but i'm assuming there's an SMODS function for that
No, there isn't.
coming soonTM
wahoo :D!
how would I pass multiple values through? value = 20, 50 just passes through the 1st one, and nil for the 2nd one, value ={ 20, 50 } displays the table string in the dialogue, and value = 20, value2 = 50 still only passes through the 1st one, and nil for the 2nd
i
dont know if its possible to do multiple variables in a challenge description?
it might be but its at least not easy
oopsie poopsie! (this is good news because it means the pool worked properly)
how would i set the default of this pool, though?
default = "card key"
thanks ^U^
How do face card skins/playing card skins/friends of Jimbo cards work, and would there be a way to mix and match the appearances of individual ranks' appearances based on sets of deck skins
weird, it's still doing it
local pools = {
phanta_chaff = { default = "c_pine_chaff_a" },
phanta_ribbon = { default = "c_pine_ribbon" },
phanta_animal = { default = "c_plum_blossom_ribbon" },
phanta_bright = { default = "c_pine_crane" },
}
for rkey, pool in pairs(pools) do
if not G.P_CENTER_POOLS[rkey] then
local reg = pool
reg.key = rkey
reg.cards = {}
SMODS.ObjectType(pool)
end
end```
Is there a way to make a message appear without returning?
A Balatro mod with various characters and overly complicated effects - wingedcatgirl/Bibliography
SMODS.calculate_effect({message = 'message'}, card)
i knew it existed but it wasnt on the wiki so i didnt know what it was called
Thank you
Oh
crash on navigating to a collections page
try disabling slay the jokers
Or use the source code version instead of release if absolutely needed.
yeah that seems to be the solve
i guess that's what 'the fix' everyone has been referring to since it explodes when trying to parse a multibox description
Did STJ finally implement multibox support???
Regardless, that’s a big common issue solved
Def weird for it to not be in a release like instantly tho
now that the new update is out, is there any way i can change the card in the title screen to a custom card
i think theres smth called context:title_card but idk what that is LOL
return {
{ key = 'j_modPrefix_jokerKey' },
remove_original = true
} end```
it didnt work
return {
{ key = 'j_hatch_hatchet' },
remove_original = true
} end```
your steamodded is behind. menu cards was introduced in 1501a, you're on 1224a
my sticker's localisation values and sprite arent showing up 😭
SMODS.Joker({
key = "burrito",
config = { extra = { discards = 7, discard_sub = 1 } },
loc_txt = {
["name"] = "Burrito",
["text"] = {
{
"{C:red}+#1#{} discards",
"{C:attention}-#2#{} discard per round"
}
},
},
pos = { x = 6, y = 6 },
cost = 7,
rarity = 2,
blueprint_compat = true,
eternal_compat = true,
perishable_compat = true,
unlocked = true,
discovered = false,
atlas = "CustomJokers",
loc_vars = function(self, info_queue, card)
return { vars = { card.ability.extra.discards, card.ability.extra.discard_sub } }
end,
calculate = function(self, card, context)
if context.end_of_round and context.game_over == false and context.main_eval and not context.blueprint then
if card.ability.extra.discards - card.ability.extra.discard_sub <= 0 then
SMODS.destroy_cards(card, nil, nil, true)
return {
message = localize('k_eaten_ex'),
colour = G.C.FILTER
}
else
card.ability.extra.discards = card.ability.extra.discards - card.ability.extra.discard_sub
return {
message = "-1 Discard",
colour = G.C.FILTER
}
end
end
end,
add_to_deck = function(self, card, from_debuff)
G.GAME.round_resets.discards = G.GAME.round_resets.discards + card.ability.extra.discards
ease_discard(card.ability.extra.d_size)
end,
remove_from_deck = function(self, card, from_debuff)
G.GAME.round_resets.discards = G.GAME.round_resets.discards - card.ability.extra.discards
ease_discard(-card.ability.extra.d_size)
end
})```
fucked up but im unsure where
lemme send over the exact error
functions/common_events.lua:113: bad argument #2 to 'max' (number expected, got nil)
Additional Context:
Balatro Version: 1.0.1o-FULL
Modded Version: 1.0.0~BETA-1501a-STEAMODDED
LÖVE Version: 11.5.0
Lovely Version: 0.9.0
Platform: Windows
Steamodded Mods:
1: Hatchet by Plasma [ID: hatchet, Version: 1.6.0]
2: DebugPlus by WilsontheWolf [ID: DebugPlus, Version: 1.5.1, Uses Lovely]
3: Deltarune Deck by nolo33lp [ID: DeltaruneDeck]
Lovely Mods:
Stack Traceback
===============
(3) LÖVE function at file 'boot.lua:352' (best guess)
Local variables:
errhand = Lua function '(LÖVE Function)' (defined at line 605 of chunk [lovely debugplus.console "debugplus/console.lua"])
handler = Lua function '(LÖVE Function)' (defined at line 605 of chunk [lovely debugplus.console "debugplus/console.lua"])
(4) field C function 'max'
(5) Lua upvalue '_mod' at file 'functions/common_events.lua:113'
Local variables:
mod = nil
(*temporary) = C function: builtin#37
(6) Lua field 'func' at file 'functions/common_events.lua:145'
(7) Lua method 'handle' at file 'engine/event.lua:96'
Local variables:
self = table: 0x35de4f58 {start_timer:true, timer:REAL, blockable:true, trigger:immediate, func:function: 0x35de4f30, delay:0, complete:false, time:20.51750065384, blocking:true (more...)}
_results = table: 0x35ab6628 {blocking:true, pause_skip:false, time_done:false, completed:false}
(8) Lua method 'update' at file 'engine/event.lua:184'
Local variables:
self = table: 0x358b58c0 {queues:table: 0x358b58e8, queue_last_processed:9.2166666666667, append_count:0, append_queue:base, queue_dt:0.016666666666667, queue_timer:9.3191175663527 (more...)}
dt = number: 0.0178875
forced = nil
(for generator) = C function: next
(for state) = table: 0x358b58e8 {unlock:table: 0x358b59d8, other:table: 0x358b5a78, tutorial:table: 0x358b5a28, base:table: 0x358b5a00, achievement:table: 0x358b5a50}
(for control) = number: nan
k = string: "base"
v = table: 0x358b5a00 {1:table: 0x35783f58, 2:table: 0x35de4f58}
blocked = boolean: false
i = number: 2
results = table: 0x35ab6628 {blocking:true, pause_skip:false, time_done:false, completed:false}
(9) Lua upvalue 'gameUpdateRef' at file 'game.lua:2617'
Local variables:
self = table: 0x35188900 {F_GUIDE:false, F_CRASH_REPORTS:false, F_QUIT_BUTTON:true, HUD_tags:table: 0x35dcb3a0, F_ENGLISH_ONLY:false, viewed_stake:1, HUD:table: 0x35d52da8 (more...)}
dt = number: 0
http_resp = nil
(10) Lua method 'update' at Steamodded file 'src/ui.lua:190'
Local variables:
self = table: 0x35188900 {F_GUIDE:false, F_CRASH_REPORTS:false, F_QUIT_BUTTON:true, HUD_tags:table: 0x35dcb3a0, F_ENGLISH_ONLY:false, viewed_stake:1, HUD:table: 0x35d52da8 (more...)}
dt = number: 0.0178875
(11) Lua field 'update' at file 'main.lua:1022'
Local variables:
dt = number: 0.0178875
(12) Lua function '?' at file 'main.lua:961' (best guess)
(13) global C function 'xpcall'
(14) LÖVE function at file 'boot.lua:377' (best guess)
Local variables:
func = Lua function '?' (defined at line 932 of chunk main.lua)
inerror = boolean: true
deferErrhand = Lua function '(LÖVE Function)' (defined at line 348 of chunk [love "boot.lua"])
earlyinit = Lua function '(LÖVE Function)' (defined at line 355 of chunk [love "boot.lua"])
you are using d_size when the value is called discards
or discard_sub idk which one
code?
i have a Joker that retriggers unscored cards, however a few effects aren't being retriggered
only scoring or money effects are being retriggered
is there something i can add to their return tables to say they can be retriggered?
yeah i dont see anything wrong
Code?
nop
okay this code is trash 😭 i didn't return anything
i used card_eval_status_text
it'll probably work when i return something
that has indeed solved the problem
finally figured it out, when you override apply you have to set card.ability.[sticker key] to true
ok so im making a joker that's like madness but it levels up every poker hand instead of giving itself xmult
i tried to copy black hole
in place of where normally it would gain mult
but the game's not responding to that at all
ok i figured it out
nvm
any explanation as to why using m_lucky as a quantum enhancement seems to affect all of my played cards instead of just the ones with a seal adding it?
if context.final_scoring_step and context.cardarea == G.play then
return {
xchips = card.ability.seal.extra.xchips,
}
end
if context.check_enhancement then
return {
m_lucky = true
}
end
end```
because it is returning m_lucky for every playing card
ah I see it now, I need to check if the seal is on the current card during scoring right
depends on the effect
if you just want the card to always be considered lucky just check context.other_card
and context.other_card doesn't work
i meant checking if it has the seal
nor context.other_card.seal == [seal]
thats weird
i'll try nesting it instead of and
should be
both with and without mod prefix it fails
if context.final_scoring_step and context.cardarea == G.play then
return {
xchips = card.ability.seal.extra.xchips,
}
end
if context.check_enhancement then
if context.other_card.seal == "modern" then
return {
m_lucky = true
}
end
end
end```
can you print context.other_card.seal in that context
sure
still doesn't work with the correct name
must be context.other_card in some way then
what does it print
nil for cards with none and [modprefix]_modern for the ones that do have it
if context.final_scoring_step and context.cardarea == G.play then
return {
xchips = card.ability.seal.extra.xchips,
}
end
if context.check_enhancement and context.other_card.seal == "fgc_modern" then
return {
m_lucky = true
}
end
end
}```
this fails
never applies lucky properties
true
I should just manually write out my own lucky card odds table here
probably more fun that way anyway
cool this works
if context.main_scoring and context.cardarea == G.play then
local ret = {}
if SMODS.pseudorandom_probability(card, 'lucky_mult', 1, card.ability.seal.extra.mult_odds) then
card.lucky_trigger = true
ret.mult = card.ability.seal.extra.mult
end
if SMODS.pseudorandom_probability(card, 'lucky_money', 1, card.ability.seal.extra.dollars_odds) then
card.lucky_trigger = true
ret.dollars = card.ability.seal.extra.dollars
end
G.E_MANAGER:add_event(Event {
func = function()
card.lucky_trigger = nil
return true
end
})
return ret
end
end
}```
that is very funny
Ok, so, im having a bit of a problem, im trying to make it so that the Joker counts how many light and dark suits are in a played hand, and if they are equal, it adds 0.2 for every pair, and tho its currently somewhat working, it can only detect if its equal, and Im not sure what causes it, idk if someone can help me out
local variables are not kept between calculate calls, so they are 0 by the time it reaches joker_main
Oh, ok, I see, I see, any recommendations then?
you dont even need the context.individual part, you can just do the counting in joker_main directly by iterating on context.scoring_hand
So like, I can move the counting stuff into the joker_main by puting the context.scoring_hand in the if statement?
no, you need to loop through it
for _, playing_card in ipairs(context.scoring_hand) do
-- your counting code here, replacing context.other_card for playing_card (or whatever you name it)
end
ooo, okok, I see
What's the best way to read this 20 value? I've found that SMODS.Challenge.obj_table.c_uma_unstable_income.rules.custom[1].value works, but was wondering if there was an easier way
So something like this?
G.GAME.modifiers.uma_tax
yeah that tracks
Do you know if its possible to have multiple values stored in the challenge rule? or is it limited to 1? I tried a bunch of things earlier but nothing ever worked with the description (#1#, #2#, etc.)
no, forget about it, made it work, thanks :D
is no_juice not working for anyone else?
a function for ordering jokers inside the collection still doesn't exist, right?
Yes, it doesn't.
honestly, how would that even work? i wonder how that could be done in a way that doesn't have mods arguing with other mods about how the collection should be ordered. would one mod take precedent, or
...me when mod priority
definitely should only have the scope of a mod's own content
but what if some mods are like "i want all the jokers of same rarity, including my own, to be together" and others are like "i want my jokers after all the other jokers"
or other weird niche cases like "i want everything all crazy style but legendaries go at the back"
for the latter higher mod priority
for the former they should probably not want that , messing with vanilla collection order is just annoying unless its fully wanted by the player, in which case they should download a mod that specifically does that
why would anybody reasonably do this and number two if somebody did do this why would anybody really care
and this as well
wait lmao i didn't even recognize you
well in any case hi lily
er
ophelia, now
glares
i mean, i guess
hi
any reason for the name change or just because you felt like it?
(which isn't like unreasonable btw)
felt my first major bout of dysphoria tonight and i needed to do something
im fine enough
doesn't sound particularly fun
yum blinds
well i sincerely hope you feel even better soon
woah what the
im alive will continue to be and thats all that truly matters
"will continue to be" is really what matters here
breaking away from cryptid bad design
so like super hard blind but it doesn't actually like end your run or anything and gets you an exquisite joker if won?
yes
no stakes but high reward
its only spawned by the valkredux equivalent of gateway
yea so like a little reward if you can beat this challenge
ugh i have to convert it to blindexpander if i want it to be good though
what's that?
api mod which primarily adds 'passives' for blinds
which are basically just mini blinds that you can apply to any boss blind easily
"mini blinds"? what does that mean?
theyre just blinds except no sprite or anything and they dont spawn
like you could have a passive for -1 discard and then apply that to any other boss blind in your mod and itd have that effect as well
in all honesty, i'm not exactly following... but, it seems pretty ambitious and fun
its bsaically just a way to modularly split blind effects into easier to read chunks
basically but the multiboxes are actually the effects rather than just extra text for fun
are multiboxes usually used for fun? most of the time i see them it's just to split up long effect descriptions on jokers/(rarely) consumables
by 'for fun' i mean being able to be split arbitrarily
with blindexpander you would define each passive and its loc seperately and then just define all the passives that the blind uses
oh i see (again)
so the split for multiboxes is not arbitrary
okay now i understand
that's cool
pretty useful for really long stuff like the blind you posted
wh
what
Unrestrained curiosity can lead to forbidden knowledge you can't unsee.
is shakespeare really dead?
I didn't mean it to rhyme
I found a (really jank) way to have multiple variables in a challenge description, but it works! Using G.GAME.modifiers doesn't work for this since the modifier isn't loaded yet in the menu, but SMODS.Challenge.obj_table always exists and lets me pull data from it.
A poet and you didnt know it
uhhh if it's harcoded for a specific challenge why don't you just... put the values in the text??
i can probably pr a way to add more vars later today doesn't seem very hard
trying to fix a joker that discards your hand. The problem is discard_cards_from_highlighted is constrained by the 5 card highlight limit and draw_from_hand_to_discard has weird delay and doesnt trigger discard effects. Is there some better way to implement this? just looping over a few cards at a time with discard_from_highlighted?
you could temporarily increase the highlight limit
how can I add a custom UI into info_queue?
alright next issue, there does not seem to be any safeguards against discarding the same card twice, so if I have two copies of the joker all discarded cards get duplicated. probably will just need to patch discard_cards_from_highlighted to fix this
what type of ui
I wanna display a health value that uses formatting like this
so just normal text?
any advice for wording this better? the idea is basically that aces give more xmult the more you have in the scoring hand (e.g. if you play a high card ace then the ace is worth 1.2x mult, if you play a pair of aces each ace is 1.4x mult, so on) but i feel like this makes it look like a high card ace would give 0.2x mult when scored, as in reducing your mult by 80% - but if i rewrite it to 1.2x mult, then it would look like a pair of aces would give 2.4x mult for each ace, which isn't how it works. i'd rather not write "1x mult + 0.2x mult for each ace in scored hand", because while accurate that's rather wordy. there's gotta be a better middle ground here
Reminds me of that old conspiracy theory from note pad people thought Bush hid the files turning into [][][] when you saved it was Microsoft hiding something lol
When in reality it was just a bug
+0.2 xMult
And any sentence with same structure would result in same thing
this probably works yeah, ty
time to see if I understood the wiki enough to add my own context
can one add calc_dollar_bonus to something other than jokers? or just a custom means for variable end-of-round money? (for reference, i'm attempting to make a custom seal, you earn $1 at end of round for every card in your full deck with that seal)
you can use perma dollar bonuses
perma_p_dollars, -- money on scoring
perma_h_dollars, -- money on held at end of round (like gold cards)
neither of those would work though, no? i'm trying to make it so it's money at end of round in full deck, like cloud 9 does for 9s
not for seals
any idea why the bottom 2 methods are nil on instances of the card?
how about ease dollars
how are you accessing it
that can be used anywhere but it doesnt put it in the round eval
oh okay
.config.center.function
yes
ease dollars wouldn't show up on the end-of-round screen i think, which is where i'd want the money earned by the seal to be shown for clarity
yeah i understood after n' clarified
you can use mod calculate and context.round_eval to add it
but i dont have an example for that
is it theoretically possible to change the deck during a game 
G.GAME.selected_back and G.GAME.selected_back_key seem related to this, im gonna check what happens if you change it
You can apply a new deck, but to remove the previous one you'd have to hardcode something for some of them (like hardcode -1 discard if you lose red deck)
I havent tested it yet but I was told this works to apply a new deck
that sounds really janky
cursed lol
As I said I havent tried it
Pokermon recently released a challenge that applies a random Pokermon deck to the challenge and I believe that's more or less how it was done
Im not yet in a stage of my mod where I can really use these kind of effets so I havent looked much into it
i mean it should work it just wouldn't support any modded decks and you would likely need to take decisions as to what 'unapplying' some decks means and even then it might behave badly if you apply magic deck when you have full consumable slots or something
this would be better as a separate api first probably
Definitely
Hey, im codding a mod and stumbled upon an issue, i cant access mult for some reason.
The joker supposed to get current mult and do operations based on it (odd/even mult events, maybe other stuff later on)
While ive seen some mods using G.GAME.chips, for me G.GAME.mult is just nil
I even tried to get mult from context.mult, its a nil too
oh, a modding guide, nice!
thanks!
W vremade wiki
can I make a seal on a playing card trigger during context.individual or no
why
I wanna make a seal that makes cards in-between it an another sealed card give x1.2 mult
like
seal card card seal card
card 2 and 3 would give x1.2 mult
you can probably use mod calculate for that
how does one get the card representing the deck, i.e. the one in the bottom right you can click to view deck & drag around and stuff?
G.deck.cards[1]
and to be safe is that nil if you've already drawn every card from the deck?
yes
do playing cards not store an instance of their seal on them, just the key?
afaik, yeah
what's an instance of a seal?
you have card.ability.seal, which mirrors the config values
like how enhancement store data on their card
for getting the config of a seal would it be
G.P_SEALS.my_seal.config
for the config you have it in card.ability.seal
which has the advantage of not being static
thx
if you need other properties of the prototype that you'd access with config.center on enhancements, what you said is right
You shouldn’t often need those though
yep
So that if there are changes, they happen in one single place
Less risk of my user error
i guess
how do i check if a card has been repeated
can u try not context.individual
nop
im trying to make a joker detect if a card has been retriggered
You can use this lovely patch to create a context for it (https://github.com/nh6574/VanillaRemade/wiki#whats-a-patch)
# Add context when a card retriggers
# Credit: Somethingcom515
[[patches]]
[patches.pattern]
target = '=[SMODS _ "src/utils.lua"]'
pattern = '''effect.message = effect.message or (not effect.remove_default_message and localize('k_again_ex'))'''
position = "after"
payload = '''
effect.extra = {func = function() SMODS.calculate_context({modprefix_card_retriggered = true}) end}
'''
match_indent = true
then you can use context.modprefix_card_retriggered
it adds a new context you can use in calculate (modprefix_card_retriggered is true)
yeah
It would be better to just set a flag when a card is retriggered
ah i see
What if I'll make PR where I'll use forbidden knowledge to recreate badge & mod authors line line with initially intented marqueen?
Like this
oh i just remembered Stupid was making this nvm
trying to figure out how to make this joker work. here are the errors so far
- it does lose $1 but it doesnt seem to update it with the standard "-$1" text that you would see in, say, a rental sticker - so i had to program my own one and i dont really like it
- it does NOT spoil at -$20 or below even tho i really want it to
-- Spoiled Milk
SMODS.Joker({
key = "spoiledmilk",
config = { extra = { dollar = 1, limit = 20 } },
loc_txt = {
["name"] = "Spoiled Milk",
["text"] = {
{
"Lose {C:money}$#1#{} per round",
"If balance is below {C:money}-$#2#{}",
"this {C:attention}Joker{} spoils"
}
},
},
pos = { x = 8, y = 6 },
cost = 7,
rarity = 2,
blueprint_compat = true,
eternal_compat = false,
perishable_compat = true,
unlocked = true,
discovered = false,
atlas = "CustomJokers",
loc_vars = function(self, info_queue, card)
return { vars = { card.ability.extra.dollar, card.ability.extra.limit } }
end,
calculate = function(self, card, context)
if context.end_of_round and context.game_over == false then
if G.GAME.dollars <= -20 then
SMODS.destroy_cards(card, nil, nil, true)
return {
message = "Spoiled!",
colour = G.C.FILTER
}
else
G.GAME.dollars = G.GAME.dollars - card.ability.extra.dollar
return {
message = "-$1",
colour = G.C.YELLOW
}
end
end
end
})
you can add ```lua to the code block so it has nicer colors
why not do this?
imma try that rn
does it destroy itself a round after you get to -20? or does it never do it
it doesnt, no
it should be doing that but it doesnt
loc_vars = function(self, info_queue, card)
return { vars = { card.ability.extra.dollar, card.ability.extra.limit } }
end,
calculate = function(self, card, context)
if context.end_of_round and context.game_over == false then
if G.GAME.dollars <= -20 then
SMODS.destroy_cards(card, nil, nil, true)
return {
message = "Spoiled!",
colour = G.C.FILTER
}
else
return {
dollars = -card.ability.extra.dollar
}
end
end
end
})```
the code rn (guidance from eris and bakerdozenbagels)
the next joker i need to program i genuinely have no idea how to make
its pretty simple in concept: gain x0.1 mult per dollar below 0
but like
idek how to do that
btw does this not remove like a million dollars per round?
im guessing some sort of hook?
it shouldnt do
xmult = 1 + (G.GAME.dollars < 0 and 0.1 * -G.GAME.dollars or 0)
hell yeah
Now problem
Can you control overflow direction?
ouch
i have one last issue but its a pretty small one
option 1: I'm PRing this with partial overflow support (i.e. only truncate vertical or only horizontal)
options 2: I'm adding padding for this line specifically
ill bring it up after i test milkman
uhhhh is context.individual in end_of_round broken
is context.individual calculated with context.game_over present normally
no?
i mean like at the end of round
i dont think so
I mean partial overflow would be generally useful
because if you do context.game_over == false that wouldnt trigger in individual
since game over would be nil
i think
oke milkman works but the text isnt updating. lemme see if i can fix that ymself
context.individual isn't present in end_of_round
you just do context.end_of_round and context.cardarea == area
no?
don't you?
it has repetition too
I’m pretty sure individual exists
Okay.
option 1: no_overflow = vh stands for vertical/horizontal
option 2: no_overflow = wh stands for width/height
It was the main reason for adding main eval, no?
nvm i have no idea
yeah
now only main_eval seems to run
wait I'm confused
1 imo
thats why this doesnt remove a million dollars
let me try without the game over
okay got it
mhhh chezburger
yeah context.individual should work fine
oh ok without the game over it works i either didnt know that or it changed at some point
-- Milkman
SMODS.Joker({
key = "milkman",
config = { extra = { xmult = 1, xmult_gain = 0.1 } },
loc_txt = {
["name"] = "Milkman",
["text"] = {
{
"Gain {C:white,X:mult}X#2#{} Mult",
"per {C:attention}dollar{} below zero",
"{C:inactive}(Currently {X:red,C:white}X#1#{C:inactive} Mult)"
}
},
},
pos = { x = 9, y = 6 },
cost = 7,
rarity = 2,
blueprint_compat = true,
eternal_compat = false,
perishable_compat = true,
unlocked = true,
discovered = false,
atlas = "CustomJokers",
loc_vars = function(self, info_queue, card)
return { vars = { card.ability.extra.xmult, card.ability.extra.xmult_gain } }
end,
-- Credit to N' for code
calculate = function(self, card, context)
if context.joker_main then
return {
xmult = 1 + (G.GAME.dollars < 0 and card.ability.extra.xmult_gain * -G.GAME.dollars or 0)
}
end
end
})
i know why it isn't updating (the "currently" text is calling back to card.ability.extra.mult) whereas this joker is referring to an overall xmult variable. so im guessing i have to add some sort of way to equate card.ability.extra.mult's value to xmult, all the time. but idk how
context.game_over is what's preventing that
doing smth like card.ability.extra.mult == xmult wasnt working
it's only present in the main eval
which is also responsible for Mr bones type effects, which is why the game over is there
option 1: no_overflow = "vh"
option 2: no_overflow = { v = true, h = true }
i dont think this was always the case but i might be wrong
"vh" for sure
makes sense
it was
1 again, assuming you can just do "h"
okay
just do 1 + (G.GAME.dollars < 0 and card.ability.extra.xmult_gain * -G.GAME.dollars or 0) in loc_vars
you can also invalidate other truthy non-string values and assume it's either falsy or a string after that
oo
it's not necessary imo
yeah it isn't
game doesn't check align so why should I
-- Milkman
SMODS.Joker({
key = "milkman",
config = { extra = { xmult = 1, xmult_gain = 0.1 } },
loc_txt = {
["name"] = "Milkman",
["text"] = {
{
"Gain {C:white,X:mult}X#2#{} Mult",
"per {C:attention}dollar{} below zero",
"{C:inactive}(Currently {X:red,C:white}X#1#{C:inactive} Mult)"
}
},
},
pos = { x = 9, y = 6 },
cost = 7,
rarity = 2,
blueprint_compat = true,
eternal_compat = false,
perishable_compat = true,
unlocked = true,
discovered = false,
atlas = "CustomJokers",
loc_vars = function(self, info_queue, card)
return { vars = { 1 + (G.GAME.dollars < 0 and card.ability.extra.xmult_gain * -G.GAME.dollars or 0) } }
end,
-- Credit to N' for code
calculate = function(self, card, context)
if context.joker_main then
return {
xmult = card.ability.extra.mult
}
end
end
})```
?
the first one should still be card.ability.extra.xmult_gain
o oke
yeah sure, but you can still make that assumption
align does too
uh oh 😭 i fucked up somewhere
-- Milkman
SMODS.Joker({
key = "milkman",
config = { extra = { xmult = 1, xmult_gain = 0.1 } },
loc_txt = {
["name"] = "Milkman",
["text"] = {
{
"Gain {C:white,X:mult}X#1#{} Mult",
"per {C:attention}dollar{} below zero",
"{C:inactive}(Currently {X:red,C:white}X#1#{C:inactive} Mult)"
}
},
},
pos = { x = 9, y = 6 },
cost = 7,
rarity = 2,
blueprint_compat = true,
eternal_compat = false,
perishable_compat = true,
unlocked = true,
discovered = false,
atlas = "CustomJokers",
loc_vars = function(self, info_queue, card)
return { vars = { card.ability.extra.xmult_gain, 1 + (G.GAME.dollars < 0 and card.ability.extra.xmult_gain * -G.GAME.dollars or 0) } }
end,
-- Credit to N' for code
calculate = function(self, card, context)
if context.joker_main then
return {
xmult = card.ability.extra.mult
}
end
end
})
i am the milk man
milkman and spoiled milk my beloveds
i feel like i should know how to diagnose this but i rly dont
both are #1#
the second one should be 2
o oke
okay probably second to lasu question: vh or hv (for like docs purposes, I will do check like align anyway)
because you changed the code?
that matters how
yeah i think so
-- Milkman
SMODS.Joker({
key = "milkman",
config = { extra = { xmult = 1, xmult_gain = 0.1 } },
loc_txt = {
["name"] = "Milkman",
["text"] = {
{
"Gain {C:white,X:mult}X#1#{} Mult",
"per {C:attention}dollar{} below zero",
"{C:inactive}(Currently {X:red,C:white}X#2#{C:inactive} Mult)"
}
},
},
pos = { x = 9, y = 6 },
cost = 7,
rarity = 2,
blueprint_compat = true,
eternal_compat = false,
perishable_compat = true,
unlocked = true,
discovered = false,
atlas = "CustomJokers",
loc_vars = function(self, info_queue, card)
return { vars = { card.ability.extra.xmult, 1 + (G.GAME.dollars < 0 and card.ability.extra.xmult_gain * -G.GAME.dollars or 0) } }
end,
-- Credit to N' for code
calculate = function(self, card, context)
if context.joker_main then
return {
xmult = card.ability.extra.xmult
}
end
end
})``` im gonna test this out
the calculate code is still wrong
just which one looks or reads better
Vh
i didnt say to change the calculate code lol
Thanks autocorrect 😭
vh imo
the code that was done earlier worked well, the only issue was the localisation not updating correclty
okay
yes, and you changed it
o
ok
why would you change it if it was working...
idk i was misinterpreting what was being explained to me
-- Milkman
SMODS.Joker({
key = "milkman",
config = { extra = { xmult = 1, xmult_gain = 0.1 } },
loc_txt = {
["name"] = "Milkman",
["text"] = {
{
"Gain {C:white,X:mult}X#1#{} Mult",
"per {C:attention}dollar{} below zero",
"{C:inactive}(Currently {X:red,C:white}X#2#{C:inactive} Mult)"
}
},
},
pos = { x = 9, y = 6 },
cost = 7,
rarity = 2,
blueprint_compat = true,
eternal_compat = false,
perishable_compat = true,
unlocked = true,
discovered = false,
atlas = "CustomJokers",
loc_vars = function(self, info_queue, card)
return { vars = { card.ability.extra.xmult, 1 + (G.GAME.dollars < 0 and card.ability.extra.xmult_gain * -G.GAME.dollars or 0) } }
end,
-- Credit to N'
calculate = function(self, card, context)
if context.joker_main then
return {
xmult = 1 + (G.GAME.dollars < 0 and card.ability.extra.xmult_gain * -G.GAME.dollars or 0)
}
end
end
})``` this should be fine
you know getting responses to a small questions immediately feels very nice
from how the description reads, shouldn't the first variable be xmult_gain and not xmult?
it should
im so confused GUHHH cus like
the code is fine, what wasnt updating was the localisation
so n is like "ok add this to locvars" so im thinking "ok so i have to move this" then
i need like super specific instructions bc im autistic as shitr
and something like this is kinda outside of my wheelhouse
it's fine haha, we got there in the end
when i say im autistic as shit, im not exaggerating
i literally have autism
diagnosed
either way this should work
looks good
ok thats kinda weird, for some reason it adds an extra +1 mult for no reason
that looks correct though?
[ignore my dumbassery]
gains X0.1 implies it starts at one imo
X1 base, 18 times X0.1 added
that 6 could have meant anything without clarifying
where I'm at it's the worst grade you can get
gcse and its consequences
in Switzerland it's the highest grade you can get
you mean smth like this?
in gcses, grades go from 1 to 9
6 is like a B
i didnt do math for alevels or uni so
except in a-levels where it's barely passing
(0-15)
yeah something like that
I would be lazy and not account for people being dumb and using it wrong
wait yeah we established that's unnecessary
I just meant you can assume it's falsy or a string after accounting for the case where it's true
Game does not check what alignment is, it assumes it's string anyway
bad screenshot but you can barely see
I want follow same logic despite it's lazy one
bump.
am i just not suppressing this juice right? because i want to juice on the individual card rather than when the cards are played
smart lovers card
is there any documentation on manipulating booster packs in the steammodded wiki
like adding extra choices, taking away choices, etc
boolean, nil, table throws error
so it makes sense do string.find just to throw more clear error to log
I'll do that
oh thanks
another variant, any truthy value considered as true i.e. vh; string passed as-is; nil and false, well, falsy
honestly, if people want to be dumb, let them be dumb and have it not work
true
ok now im a little lost
ik i have to use G.GAME.modifiers.booster_size_mod in some way
I'm stopping and this then, I still need adjust collision check and drawing to partial things
is there like a context i need to call or
might be a silly question but is there a mod/a way that I can spawn cards to do testing on?
like context.shop or
DebugPlus!
Ahh thank you so much!!
Download this mod, and follow the instructions. I use Ctrl+3 to spawn in jokers and Ctrl+C to spawn in cards, but idk if thats right
-- Ballad of Jimbo
SMODS.Joker({
key = "ballad",
config = { extra = { slot = 1 } },
loc_txt = {
["name"] = "Ballad of Jimbo",
["text"] = {
{
"{C:attention}Buffoon Packs{} may",
"contain an extra {C:attention}Joker{}",
}
},
},
pos = { x = 0, y = 7 },
cost = 7,
rarity = 2,
blueprint_compat = false,
eternal_compat = false,
perishable_compat = true,
unlocked = true,
discovered = false,
atlas = "CustomJokers",
loc_vars = function(self, info_queue, card)
return { vars = { card.ability.extra.slots } }
end,
apply = function(self, card, context)
G.GAME.modifiers.booster_size_mod(1)
end,
})```
would this work
no SMODS
o
also = 1 instead of (1)
or G.GAME.modifiers.booster_size_mod = G.GAME.modifiers.booster_size_mod + 1 would be better
also there's no apply on jokers
o is it just the standard calculate function
you want add_to_deck
okei
gulp
-- Ballad of Jimbo
SMODS.Joker({
key = "ballad",
config = { extra = { } },
loc_txt = {
["name"] = "Ballad of Jimbo",
["text"] = {
{
"{C:attention}Buffoon Packs{} may",
"contain an extra {C:attention}Joker{}",
}
},
},
pos = { x = 0, y = 7 },
cost = 7,
rarity = 2,
blueprint_compat = false,
eternal_compat = false,
perishable_compat = true,
unlocked = true,
discovered = false,
atlas = "CustomJokers",
loc_vars = function(self, info_queue, card)
return { vars = { } }
end,
-- Credit to N'
add_to_deck = function(self, card, context)
G.GAME.modifiers.booster_size_mod = G.GAME.modifiers.booster_size_mod + 1
end,
})
ah yeah
G.GAME.modifiers.booster_size_mod = (G.GAME.modifiers.booster_size_mod or 0) + 1
because it doesnt exists at the start of the run
oke
@viscid talon i must be missing something. i cannot find the spawn command for the life of me
ok hold on
press 3 or ctrl + 3 in the collection menu hovering the card
heres how you spawn a joker
wait
first click options
I found it
you can also hold tab during a run for the commands
bump
You're calling Card:juice_up outside of an event.
i hate explosion gif i hate explosion gif
if i wanna use a joker to take money away from the person, is it not just dollars = -{amount}?
it is just dollars = -amount
Okay, easy part is done. Now, collision 
oh im stupid
I didnt realize it was trying to give the money at the end of the round as opposed to on hand play
lmao
I apologize if this is an obvious question but I want to add joker art to my jokers. I know I could probably figure out how to, but im sure you guys might know more than me.
you need atlas
declare atlas
assign atlas to joker
assign where the sprite is in atlas to joker
<3 thank you
where did the name of the card go? 
i think you overwrote something
-- Hearts and Minds
SMODS.Joker({
key = "heartminds",
config = { extra = { mult = 0, mult_mod = 4 } },
loc_txt = {
["name"] = "Hearts and Minds",
["text"] = {
{
"Gain {C:mult}+#2#{} Mult if played hand",
"contains a {C:attention}Flush{}",
"then {C:attention}destroy{} cards",
"{C:inactive}(Currently{} {C:red}+#1#{} {C:inactive}Mult{})"
}
},
},
pos = { x = 1, y = 7 },
cost = 7,
rarity = 2,
blueprint_compat = false,
eternal_compat = false,
perishable_compat = true,
unlocked = true,
discovered = false,
atlas = "CustomJokers",
loc_vars = function(self, info_queue, card)
return { vars = { card.ability.extra.mult, card.ability.extra.mult_mod } }
end,
calculate = function(self, card, context)
if context.individual and context.cardarea == G.play then
context.other_card.should_destroy = false
if context.before and next(context.poker_hands['Flush']) and not context.blueprint then
context.other_card.should_destroy = true
card.ability.extra.mult = card.ability.extra.mult + card.ability.extra.mult_mod
return {
message = localize('k_upgrade_ex'),
colour = G.C.RED,
}
end
if context.destroy_card and context.destroy_card.should_destroy then
return {
remove = true
}
end
if context.joker_main then
return {
mult = card.ability.extra.mult
}
end
end
end
})
it no worky
to clarify, it doesnt seem to recognise flushes, gain mult then destroy the cards
use smods.destroy_cards instead
yeah prolly a better idea
but like, what? all i have are enhancement and seal changes and a custom sticker. there is this? but i don't know if that's the culprit?
nothing should be removing the card name from the card
-- Hearts and Minds
SMODS.Joker({
key = "heartminds",
config = { extra = { mult = 0, mult_mod = 4 } },
loc_txt = {
["name"] = "Hearts and Minds",
["text"] = {
{
"Gain {C:mult}+#2#{} Mult if played hand",
"contains a {C:attention}Flush{}",
"then {C:attention}destroy{} played cards",
"{C:inactive}(Currently{} {C:red}+#1#{} {C:inactive}Mult{})"
}
},
},
pos = { x = 1, y = 7 },
cost = 7,
rarity = 2,
blueprint_compat = false,
eternal_compat = false,
perishable_compat = true,
unlocked = true,
discovered = false,
atlas = "CustomJokers",
loc_vars = function(self, info_queue, card)
return { vars = { card.ability.extra.mult, card.ability.extra.mult_mod } }
end,
calculate = function(self, card, context)
if context.before and not context.blueprint and next(context.poker_hands['Flush']) then
card.ability.extra.mult = card.ability.extra.mult + card.ability.extra.mult_mod
SMODS.destroy_cards(card, nil, nil, true)
return {
message = localize('k_upgrade_ex'),
colour = G.C.RED,
}
end
if context.joker_main then
return {
mult = card.ability.extra.mult
}
end
end
})
nvm it seems to destroy itself and not the scored cards
it does seem to be when the card is enhanced
since there's zero things touching this and it doesn't say 9 of spades
oe
idk how to do that :sob
SMODS.destroy_cards(context.full_hand, nil, nil, true)
o yay
the description says played cards so i assumed
either works depending on what the effect is
trying to make a joker that makes steel cards and gold cards have the same effects and be considered as the same, tried has.enhancement and center, nothing seems to work, anyone knows how to do it?
this is indeed a perfect use case for quantum enhancements as described here: https://github.com/Steamodded/smods/wiki/Calculate-Functions#quantum-enhancements
make sure you've enabled the optional feature
aren't quantum enhancements really laggy atm though
they may impact performance, there's not much to be done about that though
-- Spoiled Ballot
SMODS.Joker({
key = "spoiledballot",
config = { extra = {} },
loc_txt = {
["name"] = "Spoiled Ballot",
["text"] = {
{
"On the {C:attention}first hand{} of round",
"the {C:attention}first{} played card is",
"enhanced into a {C:attention}Salt Card{}",
}
},
},
pos = { x = 2, y = 7 },
cost = 7,
rarity = 2,
blueprint_compat = false,
eternal_compat = false,
perishable_compat = true,
unlocked = true,
discovered = false,
atlas = "CustomJokers",
loc_vars = function(self, info_queue, card)
return { vars = {} }
end,
calculate = function(self, card, context)
if G.GAME.current_round.hands_played == 0 then
if context.cardarea == G.play and context.other_card == context.scoring_hand[1] then
scored_card:set_ability('m_hatch_salt', nil, true)
G.E_MANAGER:add_event(Event({
func = function()
scored_card:juice_up()
return true
end
}))
return {
message = "Spoiled!",
colour = G.C.GREEN
}
end
end
end
})```
this returns with an "attempt to globalise scored_card, null value" error
well you didn't define scored_card
oo how do i define it
that depends on what card you want to change the enhancement of
to start with, that context check is bogus
what should this actually do?
in that case add a check for context.individual
and replace any scored_card with what the scored card actually is, i.e., context.other_card
-- Spoiled Ballot
SMODS.Joker({
key = "spoiledballot",
config = { extra = {} },
loc_txt = {
["name"] = "Spoiled Ballot",
["text"] = {
{
"On the {C:attention}first hand{} of round",
"the {C:attention}first{} played card is",
"enhanced into a {C:attention}Salt Card{}",
}
},
},
pos = { x = 2, y = 7 },
cost = 7,
rarity = 2,
blueprint_compat = false,
eternal_compat = false,
perishable_compat = true,
unlocked = true,
discovered = false,
atlas = "CustomJokers",
calculate = function(self, card, context)
if G.GAME.current_round.hands_played == 0 then
if context.individual and context.cardarea == G.play and context.other_card == context.scoring_hand[1] then
other_card:set_ability('m_hatch_salt', nil, true)
G.E_MANAGER:add_event(Event({
func = function()
scored_card:juice_up()
return true
end
}))
return {
message = "Spoiled!",
colour = G.C.GREEN
}
end
end
end
})```
like this?
i got this error
oh, where does that go
also there's another instance of scored_card you forgot to change
oke
i apologise
all good
i have amended the error
calculate = function(self, card, context)
if G.GAME.current_round.hands_played == 0 then
if context.individual and context.cardarea == G.play and context.other_card == context.scoring_hand[1] then
context.other_card:set_ability('m_hatch_salt', nil, true)
G.E_MANAGER:add_event(Event({
func = function()
context.other_card:juice_up()
return true
end
}))
return {
message = "Spoiled!",
colour = G.C.GREEN
}
end
end
end
})```
still returns with an error
[SMODS hatchet "src/jokers.lua"]:3920: attempt to index field 'other_card' (a nil value)
Additional Context:
Balatro Version: 1.0.1o-FULL
Modded Version: 1.0.0~BETA-1501a-STEAMODDED
LÖVE Version: 11.5.0
Lovely Version: 0.9.0
Platform: Windows
Steamodded Mods:
1: Hatchet by Plasma [ID: hatchet, Version: 1.6.0]
2: DebugPlus by WilsontheWolf [ID: DebugPlus, Version: 1.5.1, Uses Lovely]
3: Deltarune Deck by nolo33lp [ID: DeltaruneDeck]
Lovely Mods:
Stack Traceback
===============
(3) LÖVE metamethod at file 'boot.lua:352'
Local variables:
errhand = Lua function '(LÖVE Function)' (defined at line 605 of chunk [lovely debugplus.console "debugplus/console.lua"])
handler = Lua function '(LÖVE Function)' (defined at line 605 of chunk [lovely debugplus.console "debugplus/console.lua"])
(4) Lua field 'func' at file 'src/jokers.lua:3920' (from mod with id hatchet)
Local variables:
(*temporary) = nil
(*temporary) = nil
(*temporary) = string: "attempt to index field 'other_card' (a nil value)"
(5) Lua method 'handle' at file 'engine/event.lua:96'
Local variables:
self = table: 0x379fce20 {start_timer:true, timer:TOTAL, blockable:true, trigger:immediate, func:function: 0x36f3fe20, delay:0, complete:false, time:32.101023284119, blocking:true (more...)}
_results = table: 0x37276c28 {blocking:true, pause_skip:false, time_done:false, completed:false}
(6) Lua method 'update' at file 'engine/event.lua:184'
Local variables:
self = table: 0x370801d0 {queues:table: 0x370801f8, queue_last_processed:14.316666666667, append_count:0, append_queue:base, queue_dt:0.016666666666667, queue_timer:14.444634293842 (more...)}
dt = number: 0.0168431
forced = nil
(for generator) = C function: next
(for state) = table: 0x370801f8 {unlock:table: 0x370802e8, other:table: 0x37080388, tutorial:table: 0x37080338, base:table: 0x37080310, achievement:table: 0x37080360}
(for control) = number: nan
k = string: "base"
v = table: 0x37080310 {1:table: 0x36af17e0, 2:table: 0x379fce20, 3:table: 0x379fd7d0, 4:table: 0x379fd970, 5:table: 0x379fdd58, 6:table: 0x379fedb0, 7:table: 0x379fee38 (more...)}
blocked = boolean: false
i = number: 2
results = table: 0x37276c28 {blocking:true, pause_skip:false, time_done:false, completed:false}
(7) Lua upvalue 'gameUpdateRef' at file 'game.lua:2617'
Local variables:
self = table: 0x36934ca0 {F_GUIDE:false, F_CRASH_REPORTS:false, F_QUIT_BUTTON:true, HUD_tags:table: 0x373e0220, F_ENGLISH_ONLY:false, viewed_stake:1, HUD:table: 0x3737e3d8 (more...)}
dt = number: 0.0168431
http_resp = nil
(8) Lua method 'update' at Steamodded file 'src/ui.lua:190'
Local variables:
self = table: 0x36934ca0 {F_GUIDE:false, F_CRASH_REPORTS:false, F_QUIT_BUTTON:true, HUD_tags:table: 0x373e0220, F_ENGLISH_ONLY:false, viewed_stake:1, HUD:table: 0x3737e3d8 (more...)}
dt = number: 0.0168431
(9) Lua field 'update' at file 'main.lua:1022'
Local variables:
dt = number: 0.0168431
(10) Lua function '?' at file 'main.lua:961' (best guess)
(11) global C function 'xpcall'
(12) LÖVE function at file 'boot.lua:377' (best guess)
Local variables:
func = Lua function '?' (defined at line 932 of chunk main.lua)
inerror = boolean: true
deferErrhand = Lua function '(LÖVE Function)' (defined at line 348 of chunk [love "boot.lua"])
earlyinit = Lua function '(LÖVE Function)' (defined at line 355 of chunk [love "boot.lua"])
oh whoops, you can't do that in an event
you need to save context.other_card to a local variable outside and reference that
local other_card = ??
context tables are reused between cards being scored, so context.other_card is expired by the time the event gets to run
im getting rid of the event
fair
how do i make a custom consumable rate bigger, like the thing on the spectral deck but with my own type of consumable 🤔
why is this occurring?
are you extending an smods object
look at what spectral deck does in vannilla remade.
what's the code that's causing this
and adding a default atlas
oh right i forgot about that thing
i'm kinda dumb
ur all good
i don't know; this is my atlas code it should be so simple
SMODS.Atlas({
key = "joker",
path = "joker.png",
px = 71,
py = 95,
})
and
and jokers use atlas = "joker"
are you actually loading the file with the atlas
it's worked for like forever
yes
oh wait
i'm loading them after lol
oopsie
oh you're right
in that case i'm not actually sure what's going on
this is how i load the jokers
local files = {
appetizers = {
list = {
"dragonfruit",
"blueberry",
"grapes",
"shrimp",
"durian",
"wonderous_bread",
"jelly_beans",
"apple",
"apple_core",
"tomato"
}, directory = "items/appetizers/"
},
jesters = {
list = {
"hal",
"henry",
"tom",
"barber",
"ballbo",
"rogue",
"eddrick",
"super",
"eureka",
"timmy",
"gary",
"golden_sun",
"jack_frost",
"jim",
"gumphrey",
"soothsayer",
"polymath",
"luminary",
"furious",
"larry",
"phony",
"frank",
"crafted",
"schlitzohr",
"hotboxer"
}, directory = "items/jesters/"
},
normalities = {
list = {
}, directory = "items/normalities/"
},
fables = {
list = {
-- "narr",
"manqian",
"turold",
"taillefer",
-- "dagonet"
}, directory = "items/fables/"
}
}
for _, set in pairs(files) do
for _, name in ipairs(set.list) do
assert(SMODS.load_file(set.directory .. name .. ".lua"))()
end
end
it should be pretty simple
is there an enhancement equivalent of SMODS.has_any_suit
worth noting having them each in seperate files slows loading down somewhat
that is nowhere near the point of that
it's essentially a rudimentary way of ordering jokers
alright
i've tried many, many times to implement the way that other mods do it to no avail
so this is just how it is lol
the way joker order is deterimined is by what is defined first
so you could have them all in one lua file and they would be in order from top to bottom
i am not putting all of my jokers in one lua file
you dont have to
just flat-out i'm not doing that
that was an example
and i know this anyway
there's just some other ways that mods like cryptid/all in jest do it that i can't seem to replicate
cryptid has its jokers in one joker file?
no, it separates them
but it uses a function to order jokers in the collection
same with all in jest
im looking at the github right now?
i mean they are seperated by rarity
so im half wrong
inspect every joker and peep the order function
additionally, multiple files define jokers
e.g. m.lua, exotic.lua, misc_joker.lua, epic.lua
intresting
in any case, my one issue right now is just this crash lol
yeah
can you send your atlas code and where you reference the key? this atlas you pasted up here is generic
sure
You mean you want to check if a card counts as every enhancement?
noe
these are all of my atlases, inside of lib/smods.lua, loaded by my main.lua file:
SMODS.Atlas({
key = "modicon",
path = "icon.png",
px = 34,
py = 34,
})
SMODS.Atlas({
key = "joker",
path = "joker.png",
px = 71,
py = 95,
})
SMODS.Atlas({
key = "placeholder",
path = "placeholder.png",
px = 71,
py = 95,
})
i use the joker one, for example, simply like this:
...
blueprint_compat = true,
atlas = "joker",
calculate = function(self, card, context)
...
im trying to make a flower pot clone that creates a divine card if there are sulfur, mercury and salt cards played
calculate = function(self, card, context)
if context.joker_main then
local elements = {
['Sulfur'] = 0,
['Mercury'] = 0,
['Salt'] = 0,
}
for i = 1, #context.scoring_hand do -- IF NOT
if context.scoring_hand[i]:has_enhancement('Sulfur', true) and elements["Sulfur"] == 0 then
elements["Sulfur"] = elements["Sulfur"] + 1
elseif context.scoring_hand[i]:has_enhancement('Mercury', true) and elements["Mercury"] == 0 then
elements["Mercury"] = elements["Mercury"] + 1
elseif context.scoring_hand[i]:has_enhancement('Salt', true) and elements["Salt"] == 0 then
elements["Salt"] = elements["Salt"] + 1
end
end
for i = 1, #context.scoring_hand do -- IF YES
if context.scoring_hand[i]:has_enhancement('Sulfur') and elements["Sulfur"] == 0 then
elements["Sulfur"] = elements["Sulfur"] + 1
elseif context.scoring_hand[i]:has_enhancement('Mercury') and elements["Mercury"] == 0 then
elements["Mercury"] = elements["Mercury"] + 1
elseif context.scoring_hand[i]:has_enhancement('Salt') and elements["Salt"] == 0 then
elements["Salt"] = elements["Salt"] + 1
end
end
if elements["Sulfur"] > 0 and
elements["Mercury"] > 0 and
elements["Salt"] > 0 then
return {
xmult = card.ability.extra.Xmult
}
end
end
end
})``` im wondering if this will be enough
It should be SMODS.has_enhancement(context.scoring_hand[i], 'm_modprefix_key')
SMODS.has_enhancement(context.scoring_hand[i], 'm_hatch_sulfur') ?
Yes.
where do i put that
-- Philosopher's Stone
SMODS.Joker({
key = "philosopher",
config = { extra = { } },
loc_txt = {
["name"] = "Philosopher's Stone",
["text"] = {
{
"If played hand contains",
"a {C:attention}Sulfur Card{}",
"a {C:attention}Mercury Card{}",
"and a {C:attention}Salt Card{}",
"create a {C:tarot}Divine Card{}",
}
},
},
pos = { x = 3, y = 7 },
cost = 7,
rarity = 2,
blueprint_compat = false,
eternal_compat = false,
perishable_compat = true,
unlocked = true,
discovered = false,
atlas = "CustomJokers",
calculate = function(self, card, context)
if context.joker_main then
local elements = {
['Sulfur'] = 0,
['Mercury'] = 0,
['Salt'] = 0,
}
for i = 1, #context.scoring_hand do -- IF NOT
if SMODS.has_enhancement(context.scoring_hand[i], 'm_hatch_sulfur') then
elements["Sulfur"] = elements["Sulfur"] + 1
elseif SMODS.has_enhancement(context.scoring_hand[i], 'm_hatch_mercury') then
elements["Mercury"] = elements["Mercury"] + 1
elseif SMODS.has_enhancement(context.scoring_hand[i], 'm_hatch_salt') then
elements["Salt"] = elements["Salt"] + 1
end
end
for i = 1, #context.scoring_hand do -- IF YES
if SMODS.has_enhancement(context.scoring_hand[i], 'm_hatch_sulfur') then
elements["Sulfur"] = elements["Sulfur"] + 1
elseif SMODS.has_enhancement(context.scoring_hand[i], 'm_hatch_mercury') then
elements["Mercury"] = elements["Mercury"] + 1
elseif SMODS.has_enhancement(context.scoring_hand[i], 'm_hatch_salt') then
elements["Salt"] = elements["Salt"] + 1
end
end
if elements["Sulfur"] > 0 and
elements["Mercury"] > 0 and
elements["Salt"] > 0 then
return {
xmult = card.ability.extra.Xmult
}
end
end
end
})``` my code rn
good news is that it doesnt break
bad news is that it doesnt really do anything
oh wait
LOL
HOLD ON
nvm i figured it out LOL
bizarre issue
-- Medicine Cabinet
SMODS.Joker({
key = "medicine",
config = { extra = { xmult = 3, odds = 4 } },
loc_txt = {
["name"] = "Medicine Cabinet",
["text"] = {
{
"{C:white,X:mult}X#3#{} Mult in a {C:attention}Boss Blind{}",
"{C:green}#1# in #2#{} chance to expire",
"during a {C:attention}Boss Blind{}"
}
},
},
pos = { x = 5, y = 6 },
cost = 7,
rarity = 2,
blueprint_compat = true,
eternal_compat = true,
perishable_compat = true,
unlocked = true,
discovered = false,
atlas = "CustomJokers",
loc_vars = function(self, info_queue, card)
local numerator, denominator = SMODS.get_probability_vars(card, 1, card.ability.extra.odds, 'j_hatch_cakeslice')
return { vars = { numerator, denominator, card.ability.extra.xmult } }
end,
calculate = function(self, card, context)
if G.GAME.blind.boss then
if SMODS.pseudorandom_probability(card, 'j_hatch_cakeslice', 1, card.ability.extra.odds) then
SMODS.destroy_cards(card, nil, nil, true)
return {
message = localize('k_extinct_ex')
}
else
return {
message = localize('k_safe_ex')
}
end
end
if context.joker_main and G.GAME.blind.boss then
return {
xmult = card.ability.extra.xmult
}
end
end
})
whenever i go into a boss blind and try this, the game just... dies. no crash message, nothing. it just closes 😭 im guessing its stack overflow
the first if condition doesn't have any context checks
when do you want it to be destroyed?
during a boss blind
at the start?
bump?
then add context.end_of_round
and context.main_eval
to the G.GAME.blind.boss condition
oke
question here, which tbh is mostly out of curiousity rather than any idea I currently have for any jokers or anything, but how would you make a math function for dice? What I mean is, like "3d6", "5d6", etc
I know how I'd do it, like, on it's own, it being random(1,6) + random(1,6) or whatever lua's random function is (I forgor lol), but like, how would I make that into a repeatable var u know? Simple example joker idea would be a joker which gives +1d6 Mult and rolls an additional die for each boss blind you defeat while holding it
local mult = 0
for i=1, card.ability.extra.value do
mult = mult + pseudorandom('seed', 1, 6)
end
i have a joker that upgrades based on the number of cards with a random suit in the total deck of the player, but the logic for upgrading is a bit odd at the moment
i'd still like it to use SMODS.scale_card for compatibility, but i'm unsure on how i'd set this up such that "upgrade" isn't shown suit_count() times
if suit_count() ~= 0 and context.end_of_round and context.main_eval and not context.blueprint then
for i = 1, suit_count() do
SMODS.scale_card(card, {
ref_table = card.ability.extra,
ref_value = "xmult",
scalar_value = "xmult_mod",
message_colour = G.C.MULT
})
end
end
no_message = true then return a message.
i had thought of that, but on the molecular-level chance that somebody somehow uses this joker and tracks when it scales, it would be off
i know it doesn't really matter all that much, but if there's a better way to do it accurately, i'd want to use it
especially considering it would be easily possible by just setting the value to the correct one instead of using SMODS.scale_card
operation = function(ref_table, ref_value, initial, change)
ref_table[ref_value] = ref_table[ref_value] + suit_count()*change
end
so it becomes this?
SMODS.scale_card(card, {
ref_table = card.ability.extra,
ref_value = "xmult",
scalar_value = "xmult_mod",
message_colour = G.C.MULT,
operation = function(ref_table, ref_value, initial, change)
ref_table[ref_value] = ref_table[ref_value] + suit_count() * change
end
})
Yes.
thanks so much!
Back:apply_to_run() on vanilla decks causes this crash:
how do i make the upgrade message appear after a stone card is scored, as, currently, this joker upgrades before
if context.individual and context.cardarea == G.play and not context.other_card.debuff and SMODS.has_enhancement(context.other_card, "m_stone") then
SMODS.scale_card(card, {
ref_table = card.ability.extra,
ref_value = "mult",
scalar_value = "mult_mod",
message_colour = G.C.MULT
})
end
bonus question: do i need not context.other_card.debuff or would it work correctly without?
you need to return a message
oh wait
do you upgrade every time a stone card has been scored
or do you just upgrade once, even if two stone cards or more have been scored
...set no_message = true in the table, then manually SMODS.calculate_effect the message on the card?
every time one has been scored
smods.scale_card already does so?
i’m not exactly following
er ok wait no i get it
i’ve never used SMODS.calculate_effect though so i don’t really know what i would do there
SMODS.calculate_effect({message = localize('k_upgrade_ex'), colour = G.C.MULT}, target_card_here)
aqre you upgrading the joker or the card itself
the joker
ok thanks
yeah then i would put card and not the stone card
i never did put the stone card though
he edited tho
i see
target was other_card
how do i make a joker transform into another joker?
Put no_message = true in SMODS.scale_card then return a message.
im trying to get into making mods for the game for the first time and im searching through steammodded's api to see how things work and im starting to get an idea of how different systems n stuff in the game work but i cant seem to find how i get my mod to actually do anything, like how to get it to initialize itself and act as a mod instead of just being some files with code that dont activate
i know its probably pretty simple and im probably just looking in the wrong places but i really cant find how to do it properly
thank u sm
also
how do i make it say a message
when it transforms
i tried a few stuff
but nothing's been working
ok i figured it out
oh yeah i looked through the metadata and i have metadata set on my test mod the mod still doesnt really do anything
currently im just trying to add a single extra joker
nevermind
If it's in a calculate you would do return {message = 'message'}, elsewise, you would do SMODS.calculate_effect({message = 'message'}, card)
loc_vars = function(self, info_queue, card)
return { vars = { card.ability.extra.mult } }
end,
calculate = function(self, card, context)
if context.setting_blind and not context.blueprint then
card:set_ability("j_sj_captainmarvel_joker")
return {
message = 'SHAZAM!',
colour = G.C.RED
}
end
calculate = function(self, card, context)
if context.joker_main then
return {
mult = card.ability.extra.mult
}
end
end
end,
}```
this plays the message but now the other effect (+4 mult) doesn't work
Remove the second calculate.
when i do that then the game crashes :((
wait let me try something
ok phew
there was an extra end
now both the message and effects happen
thank u
btw how do i make it so one of the jokers can't show up in the shop? Do I just give it like a 0 rarity?
return false in in_pool.
looking through it actually worked quite well and was very convenient hooray
cost = 7,
blueprint_compat = true,
eternal_compat = true,
unlocked = true,
discovered = true,
soul_pos = nil,
in_pool = false,```
i did this but i get the feel it's not what you meant
in_pool = function()
return false
end,
Me and my coder have been trying to fix this for so long but it still isn't working
The aim is for example:
Imagine a reroll costs $5, this would bring it down to $3 but the base price would still be $5, and if the base price goes any lower it would take 2 off that instead
Someone please look into their code and clean it up according to their description, I still want it to raise the other prices in the shop by $1
I sent it to my coder and unless they just didn't do it the code didn't work
It should work now, also tell your coder that they shouldn't be using attention_text when they want a joker to display a message.
Did you test it yourself or something
Yes, I did.
Maybe they forgot to put it in or something
Does your test version include the price increase for other shop items
If yes can you slide it for me to put into the build I'm testing
why is the upgrade text triggering on the played card(s)?
calculate = function(self, card, context)
if
(context.individual and
context.cardarea == G.play and
not context.other_card.debuff and
SMODS.has_enhancement(context.other_card, "m_stone")) or
(context.discard and
not context.other_card.debuff and
SMODS.has_enhancement(context.other_card, "m_stone")) and
not context.blueprint
then
SMODS.scale_card(card, {
ref_table = card.ability.extra,
ref_value = "mult",
scalar_value = "mult_mod",
no_message = true
})
return {
message = localize("k_upgrade_ex"),
colour = G.C.MULT,
card = card
}
end
Ok so my coder legit just forgot to do it
You need message_card = card in the return.
instead of card = card?
Yes.
thank you again king somethingcom
A card does indeed equal a card last I checked
if you return { mult = mult } it would, in fact, do something
Damn I wonder if I'll get +3 mult if I set the mult to give |-3| mult
So uh I'm testing big leagues which does this
And it created a brainstorm
Which then created another joker
And I'm wondering if that's like a bug or something cuz brainstorms aren't supposed to copy the effect that created it I assume
No, Brainstorm copies all jokers that are blueprint compatible.
I know that but the caveat is that big leagues created it, and it copied the rekoj post-trigger
Of course brainstorm will copy it but I'm wondering if it makes sense for it to copy it in this context
okay i have a very specific issue with my joker. this is its code at the moment:
calculate = function(self, card, context)
if
(context.individual and
context.cardarea == G.play and
not context.other_card.debuff and
SMODS.has_enhancement(context.other_card, "m_stone")) or
(context.discard and
not context.other_card.debuff and
SMODS.has_enhancement(context.other_card, "m_stone")) and
not context.blueprint
then
SMODS.scale_card(card, {
ref_table = card.ability.extra,
ref_value = "mult",
scalar_value = "mult_mod",
no_message = true
})
SMODS.calculate_effect({message = localize("k_upgrade_ex"), colour = G.C.MULT}, card)
end
if context.individual and not context.other_card.debuff and context.cardarea == G.play and SMODS.has_enhancement(context.other_card, "m_stone") then
return {
mult = card.ability.extra.mult,
card = context.other_card
}
end
end
right now, the upgrade message appears before the card has been scored, and the effect is obviously applied after the joker has upgraded
what i would like to occur is for the joker to upgrade after a stone card has been scored, INCLUDING the actual effect itself
so, for example, if i haven't played any stone cards in the run and i play one stone card, i wouldn't like it to give any mult whatsoever; then, the next one would give +5
how would i go about this timing?
Replace the SMODS.calculate_effect with a return
i've found that doing so doesn't allow the second effect to activate
Yes, because they happen in the same context, and you can't return more than once.
Yes, you shouldn't use that inside a calculate function unless it's in a func in the return, you should use SMODS.merge_effects to merge the returns then return at the end.
thanks you once again king somethingcom
is it possible to do the same thing but for seals
No, the best you could do is hook Card:get_seal but most people just check card.seal
okok
What on earth is this
atrocious hook I think
with quantum enhancements enabled that's gonna drag performance
When i play a card, the joker should burn it with 50% chance, but instead it crashes the game, am i doing something wrong?
Oops! The game crashed:
main.lua:2438: functions/common_events.lua:919: attempt to index local 'card' (a nil value)
This crash may be caused by continuing a run that was started on a previous version of Steamodded. Try creating a new run.
Additional Context:
Balatro Version: 1.0.1o-FULL
Modded Version: 1.0.0~BETA-1016c-STEAMODDED
LÖVE Version: 11.5.0
Lovely Version: 0.9.0
Note: it was a new run
Replace j_bowot with card
oh,
yea that works thanks!
is there a way to make it play burning animation? nvm it does now
-# im sorry for pinging you so much lol



