#💻・modding-dev
1 messages · Page 97 of 1
Gimme the whole error log first
Lemme see the calculate function for the broken joker
if context.after and not context.blueprint then
for index, card2 in ipairs(context.full_hand) do
if card2:is_suit("Hearts") then
Card:start_dissolve(card2)
card.ability.extra.Xmult = card.ability.extra.Xmult + card.ability.extra.Xmult_mod
end
end
end
if context.joker_main and card.ability.extra.Xmult >= 1 then
return {
message = localize{type='variable',key='a_xmult',vars={card.ability.extra.Xmult}},
X_mult_mod = card.ability.extra.Xmult,
card = card
}
end
end
}```
You should call card2:start_dissolve() not Card:start_dissolve(card2)
That might be the issue
let me try
I got a new error
it should be self.config.Xmult_mod
so self.config.Xmult_mod instead of card.ability.extra.Xmult_mod
Yes
it's giving the same error
Ok send me your full code
this is it
Your config is setup wrong
how should it be set up then?
Check the example jokers mods that comes with steamodded
would it be ability.extra.Xmult_mod in the config instead of increase?
No, the config field on your joker object is not formatted correctly. It should be like this ```lua
config = { Xmult = 1, Xmult_mod = 1 }
~~Because
- It's not how you do it in SMODS
- It's a useless extra layer of table
- It's vague~~
ok
Using extra is recommended
The game only copies specific values from the config table when it creates the joker, but it will copy the entire extra table always. Using the extra table will guarantee that your joker has the values you want it to have, and they can be accessed by card.ability.extra.key
Ah I didn't know that
So yeah it should be config = { Xmult_mod = 1, extra = {Xmult = 1} }
why would the Xmult_mod = 1 not be part of the extra table?
I presume it's a static value that doesn't need to be changed?
As in it won't increase or decrease when the joker is in play
the base value wouldn't. I'm trying to have it where every Heart card played increases the Xmult by 1 then destroys the played heart cards (1xmult -> 2 heart cards are played -> 3x mult) almost like a mix between vampire or sixth sense
Just put them all in the extra table
It’s easier to remember that way and harder to screw up
Yeah, but how much you add to the value each time doesn't change. So it doesn't need to be in the extra table. It can be, but it's useless to add it there and it's also best practice to seperate your static and non-static variables
for k, v in pairs(context.scoring_hand) do
print(k,v)
end
returns (when playing a pair)
1, nil, 2, nil
all cards are just nil all the time
what am i doing wrong
it STILL giving me the same error
Send the calc func
---context.after is after the hand is scored
---not context.blueprint means this part cannot be copied by Blueprint
if context.after and not context.blueprint then
---loops through every card in played hand
for index, card2 in ipairs(context.full_hand) do
---check for hearts suit, card2 is the value in the current loop
if card2:is_suit("Hearts") then
---destroy the card
card2:start_dissolve()
---increment Xmult value by adding increase to the Xmult value
card.ability.extra.Xmult = card.ability.extra.Xmult + self.config.Xmult_mod
end
end
end```
do you also want the context?
Send the config field
config = { Xmult = 1, extra = {Xmult_mod = 1} },
just like we talked about before
Yeah sorry I sent it wrong way around at first, it should be config = { Xmult_mod = 1, extra = {Xmult = 1} }
That's mb
what's the difference between Xmult and Xmult_mod
That's a you question, honestly you could just get rid of Xmult_mod and do card.ability.extra.Xmult = card.ability.extra.Xmult + 1
Though I still don’t recommend not using the extra table, it should be card.ability.Xmult_mod
ok so the game stoped crashing but the mult isn't being added
it's giving the pop up saying it's mult
new doe incase you need to look at it
where should card.ability.Xmult_mod go then?
After the +
i think you might just need a joker_main context returning xmult = card.ability.Xmult
You need a message for the pop up text when you increase the mult, using card_eval_status_text or SMODS.eval_this
would it still need to be in my config?
like
if context.joker_main then
return {
Xmult_mod = card.ability.x_mult,
message = localize { type = 'variable', key = 'a_xmult', vars = { card.ability.x_mult } }
}
end
Yea
config = { Xmult_mod = 1, extra = {Xmult_mod = 1} }
Generally, any values you need in your joker should be defined in the config table, and I’d recommend using the extra table within that so you can ensure they’re all copied over (like I said before, there are very specific keywords that will be copied over regardless). When you need to use them in your calculate function (or other functions, loc_vars in particular) you use card.ability.extra.blablabla
So when I’m creating scaling Xmult jokers, for example, I set config = {extra = {xmult = 1, gain = 0.25}} and then my scaling line would look like card.ability.extra.xmult = card.ability.extra.xmult + card.ability.extra.gain. Using the extra table like this means that your joker has can set your variables to be named whatever you like, so you can be really specific with names in more advanced calculations
so the card.ability calls from config, .extra. calls from the extra table and the last part are the values you put in the tabele?
also note how how do you get the code parts to be the same line in discord mine keep making new lines
Single `` instead of```````
like this hopefully
ok thanks
ok, so I don't know what it is, but only when I do card.ability.extra.Xmult = card.ability.extra.Xmult + 1 does NOT not crash
but it's still not counting towards the X_mult (nor the t=chips I might add)
isnt it card.ability.extra.X ?
not in loc_vars
i genuinely have no idea
for some reason x_mult is nil or something
fair enkugh
If you haven’t already, try starting a new run and spawning a fresh copy of the joker, going back into the same run can cause issues with variables if you’ve been changing them
it is not mine
Whoopsie
it is, they just named the card arg center
ooooh, cool
yeah im literally astounded
i ont know whats wrong
oh.
it should be destroyed after 114 hands
or whatever that number was
i forgot
is there any luaLS settings for a better modding experience (auto completion and such)? I'm using zed, so anything beyond LuaLS settings or at best a modified LuaLS binary is out of the question.
Should I create a repo, where every mod for Balatro should be listed? So like an Index, which the Balatro Mod Manager could use.
Everybody would contribute to it by giving the meta-data for their mod and a thumbnail
10
12
1
Yes
Isnt an index already in the work?
the suggestion they're making is from the csl i think
wouldn't be allowed to be changed
oh damn
it's not being worked on but yeah
that poll made it get thought about again i guess
might start getting some attention once beta happens
Does some of y’all created mods without much experience in coding ? Because I would like to create one but I wonder if it’s that difficult
i have no formal expirence in coding, in any capacity
i've learnt all i know about lua through balatro modding raisedcateyebrow~2
Oh okay !
Can a joker be spawned in a shop using debugplus?
?
Ah yes the like 5th mod index
Is there documentation on how to use the RetriggerAPI?
which of these functions triggers first? obviously i only want to calculate the odds once, is there a priority to these things or is it simply based on which is higher in the code?
```lua
calc_dollar_bonus = function(self, card)
local rand = pseudorandom('JokerTest')
local pOdds = G.GAME.probabilities.normal / currentOdds
print(rand, pOdds)
end,
calculate = function(self, card, context)
if context.end_of_round and not context.repetition and not context.individual and not context.blueprint then
local rand = pseudorandom('JokerTest')
local pOdds = G.GAME.probabilities.normal / currentOdds
print(rand, pOdds)
end
end
It's based on whatever order the game runs them in
yeah calculate would come before the screen comes up i suppose
whats the best way to figure out why im crashing all the time?
read the crash log
via the crash log
yes, I have that but my little brain doesnt understand the log
that's programming i'm afraid, logs are your best asset to root for a problem
you can show us but we can only take you so far
send the crash log here and someone might be able to help
it usually pinpoints the line or area the problem occurs
Asking again about RetriggerAPI since it got buried
How do you check when the game has ran through all joker abilities for a played poker hand, then execute code there before the scoring finishes?
refer to #1247703015222149120 message
has anyone tried dynamically changing the name/text of loc_txt yet? Or would it be easier/better to create another joker that replaces it based on if the conditions are met?
You can dynamically change them
is it as simple as loc_txt.text = { "new info" }?
naw prob not
no
yeah thought not kek
you can use variables if it's something simple
otherwise you need to make new keys and swap them
not sure the entire process
i think i can do something clever with loc_vars and just have it point to the same variable in there
not entirely sure what the issue is here, it has something to do with loc_vars not being able to read the config for one reason or another, it says the ability value is nil
(btw it doesnt currently reduce by 1 each hand, that is something I will add once I get this done)
its proably smth stupid lol
yeah can confirm
it's not center right it should be card
ah
at some point we're gonna have to make a mod index index
also, whats the lowest id a stone card can be? i found it once in the source code and never again, and it'd be easier to ask here 😭
-100 to -1000000
ty ty
im having an issue where every card is registering as nil and impossible to get info on
does anyone know why that might be
for example
for k, v in pairs(context.scoring_hand) do
print(k,v)
end
returns
1, nil, 2,nil, etc
how are you checking the print
lovely console
iirc lovely bug
ah
I basically just copied seltzer's code while editing a few things but I'm getting a crash that says something along the lines of a function needing to be a number rather than... whatever it is, it seemingly didnt give me a line where the issue is, I wish the log was saved as a text file or smth
as far as I can tell, there doesnt seem to be any syntax errors, I checked
for context this is a food joker that loses mult every hand
whats your config look like on your joker?
mult = 10,
mult_mod = 1
}
}
send crash
wait hang on I need to figure out where it is in the first place
mods/lovely
you can copy from the crash screen or Mods/lovely/logs
im gonna have to censor my name out of this, for some reason my user folder is my real fuckin name I need to change that
I think this is it
Not too sure but I think this is a you're returning something wrong in a certain context
ill see
Where can i learn to make mods?
Quaso
https://youtu.be/Zp-4U5TlbxY?si=cynb-VfZ89iOSI5E
this video helped me learn the basics, while looking in the base game's code and other mods helped me more
STEAMODDED 1.0.0
A tutorial on how to make a modded Joker.
https://github.com/art-muncher/Example-Mod -- EXAMPLE MOD
https://github.com/Steamopollys/Steamodded -- STEAMODDED
https://github.com/WilsontheWolf/DebugPlus -- DEBUGPLUS
-----------------------------------------------------...
Hey, I think I've seen this before...
🤔
thats crazy
you should probably listen to the amalgam at the end....
download the #1248287850512781452
oh yeah ive been meaning to check that out actually
What does match_indent do exactly in patches?
makes it so when your patch is inserted it has indenting
it matches your indent you could say
Ok but for the pattern I search (without regex) do I need to add the indent in the pattern string?
no
if your pattern matches line() then in this file
if 1 then
if 2 then
line()
end
end
if match_indent is true, you get:
if 1 then
if 2 then
line()
patch()
end
end
otherwise you get
if 1 then
if 2 then
line()
patch()
end
end
Hmm weird why doesn't it find the line
is it erroring in the console?
Oh actually, looks like steammooded has inserted something
yeah patch conflict could cause issues
How do i figure out what the code looks like after steamodded has modified it?
look at the lovely dump
is the modifier that scales text {S:#}{}?
nope its {s:number} {}
aren't the modifiers case insensitive?
i have no idea lmfao
also it feels weird if its s: for scale, but C: or X: for colouration
C:color, X: xmult shit
Actually does LUA allow ternary operators inside an expression? Like does this work:
repetitions = 1 + (G.GAME.n_seal_repeats or 5)
S:# does work, using it rn
imagine
thats not a ternary operator but yes that works
Eh right not ternary but it's rtelative that I don't know the name of
it's a boolean operator
The grandmas are coming.
nvm, im just stupid
it is s:
thats.. annoying
i KNOW, RIGHT??
☹️
Woo, lovely makes it possible to get Windows error message popups in Linux
it really isn't lovely making that possible, it's just that Linux runs the game by emulating windows
thats just wine/proton
Well if we get that technical, WINE is not emulation
depends on your definitojn of emulation
oh right, WINE is a recursive acronym for "WINE is not a emulator"
I wonder if you could use patches to make R code look readable
has there ever been a joker that changes the type of a card whilst it's in your hand? a bit like how midas mask converts face cards into gold when scored, could you change the suit/rank of a card that isn't played?
i have no idea how i'd even start
yeah probably
surely
would take a look at how strength changes cards and then when midas mask runs and then jsut do it
I haven't done any jokers that do that (unless I have forgotten about them) but ortalab has just released zodiac cards that have a lot of hand interaction during scoring
i'll check it out
How do you modify an existing joker's calculate method? I learned how to add a joker with a custom calculate method, but idk how to modify an existing one.
SMODS.Joker:take_ownership('j_joker', { -- replace with whatever key you need
calculate = function(self, card, context)
-- ...
end,
})
add an additional argument of true at the end if you don't want the joker to get your mod badge
is there a thing such as context.after_scoring? I want this joker to do smth right after all the cards and jokers have scored, like how seltzer does
yes, it's called context.after though
So something like this?
SMODS.Joker:take_ownership('j_joker, {calc method here}, true)
you dropped a ', but yes
Okay, thank you
I tried doing that before but there was smth wrong with it I think, lemme try again
it's what seltzer uses
Is there a way to calculate the mult based on the money the player has and display that in the loc_txt? GAME seems inaccessible in the config.
SMODS.Joker:take_ownership('j_greedy_joker', {
loc_txt = {
name = 'Greedy Joker',
text = {
'Multiplies {C:mult}mult{} based on how',
'much {C:money}money{} you have. {C:money}$100{} = {X:mult,C:white}X1{}',
'Current mult: {X:mult,C:white}X#1#{}'
}
},
local_vars = function(self, info_queue, center)
return {vars = {center.ability.extra.Xmult}}
end,
config = { extra = {
Xmult = G.GAME.dollars / 100
}},
calculate = function(self, card, context)
if context.joker_main then
-- $100 = 1x mult. $80 = 0.8x mult.
return {
card = card,
Xmult_mod = card.ability.extra.Xmult,
message = 'X' .. card.ability.extra.Xmult,
colour = G.C.MULT
}
end
end
}, true)
config is ony set when your mod is first loaded
probably want to use update
see how bootsraps does it
is there a way to see the context of the joker being added to the deck?
(e.g. from a booster pack or bought)
oh no I'm not doing calculate magickery
theres add_to_deck
if you just want to know whne it's aquored
oh wait
unless you mean deteitng when another joker is being added
what are you trying to do?
I want to set the money to 0 upon buying the joker
currently it sets it to -{joker value}
by buying the joker do you mean your joker or any joker
only when buying the modded joker
change the cost in set_ability
you can use add_to_deck to and remeber to chekc the from_debuff
again, it can be obtained from booster packs
also technically judgement
anything that gives jokers for free
tags, even
use set_ability to set the cost of the joker and then add_to_deck to set it back if it's screwing up the sell value
I'm pretty sure that would work
no I think they want t oset your money to 0 not the price
when does set_ability work?
when the joker is created iirc
yeah I want to take ALL money
if you did want it to always be free I think you can just put couponed = true in your config
at this point might as well do a lovely patch
it's $7 but I want it to take all remaining money
dollar buffer momento?
yes
Does take_ownership override all values of a Joker or only the ones you specify? For example, If I have calculate, and loc_txt in the take_ownership method, would that only override their respectful values?
yeah my ass thought I gotta do context.card.ability.name == name
so then I gotta make a new variable in config?
yeah that sounds about uncomplicated and more reasonable
looks like the game calls calcuate with buying_joker = true and your joker as the card when you buy it
just check if context.card == card and then its buyign you
funny how buying_card isn't even used in the main game
there are a few things like that where thunk just doesnt use them
here's another one
oh cool
wait why can't I see the problem
it's swapping mult and chips
silly knife idea, instatly destory any bought joker
scoped knife
there's also effects[ii].extra.func which executes a function you return, I don't think base game uses that either iirc
oh
would that be like making an instant event and doing your stuff?
also thers add_joker(id) which will create and add the given joker or consumable id which is technically unused
it sort of adds the event without using the event manager from what I remember
is there any docs on events?
It's used to debug spawn jokers and in some unused sandbox code
actually yes
oh snap I remember that
lets get it on the wiki
you happy for me to throw it on wilson?
ngl SMODS/Balatro is still fairly undocumented
yeah go ahead
it's better than it was a few months ago
theres a lot of balatr to document
and SMODS has only recently had most of it's api semi-stable
The issue is everyone deep into modding baaltro is so used to reverse engineering baaltro's code, SMODS code is super easy to reverse engineer
wait, so what about when it's free? is it still buying_card if it's gained in booster packs? if so, how to get the price?
I'm sorry btw I'm 3 days into modding or lua in general
buying_card is only from the shop iirc
Very true. It's a pain to get going but once you know what to do you just start searching through the files every time you need something
Nice Christmas hat btw
free yes, booster I don't think so (try it and see)
how do I use add_to_deck in a deck?
I want to write up some docs, what do we need most?
like I want to add a joker to your deck on start
Can loc_txt not be overrided in SMODS.Joker:take_owenership? It still defaults to the text in the localization scripts.
util.lua
I think add_to_deck with some "flags" in config is actually better. but there's a problem of not knowing the price
like everyt function in it
this is what i've kinda thrown together in my thing
fair, we've been missing that
explain why to use it and what vanilla function it repalces
I literally just want it to add a showman with poly
It might be already parsed at that point?
shouldn't be (?)
it should work from what I remember
but I know how to force it to redo localization if nessicary
but using loc files is preferable anyways
c:set_edition('e_polychrome', 1, 1)
oh yeah thats not how you make a joker
All this unnecessary hate for localization files
I'm lazy
loc files are bis
it's a shrimple as that
i won't stop you
How would you force it to redo localization?
if you're ever in a situation where you want to have localization in a mod, you won't want inline loc_txt anymore
how does taking ownership work??
see I'm more worried about getting art then localization
is it the same as it was in 0.9.8??
I suggest you use the localization file instead
Would I create a new one in my Mod's dir and update that?
init_localization() (it's probably not nessicary)
https://github.com/Steamopollys/Steamodded/wiki/03.-API-Documentation when did we drop this from the sidebar
uhh I thought the sidebar was auto populated tbh
oh also for docs the making a mod section should be removed from getting statted and be it's own page with a lot more detail
eremel made a custom one
it's litterally this is the file header, go figure the rest out
There is stuff missing from the custom sidebar (mostly the subheaders)
if you haven't migrated by now you can dig through the old sidebar to find it imo
or maybe I can dump it ith the 0.9.8 stuff
or do we remove that too?
Is there any real reason for the 0.9.8 docs to still exist?
local c = G.P_CENTERS[j_ring_master] would this be the right way to get showman in a variable??
cause I know P_CENTERS is a table, so calling the key would work?
maybe>
?
G.P_CENTERS['j_ring_master'] almost
awww so close
needs to be a string
else you're doing G.P_CENTERS[nil] most of the time which crashes the game
I think what you are looking for is SMODS.create_card
you can however do G.P_CENTERS.j_ring_master
Youre trying to give the user a card, right?
yea, one that already exists, so I thought I could just use the add_to_deck function with I looked through and should work
not really, tho it would still be reachable thru git revision history if someone really wanted them
Centers are more like blueprints used to make cards
#⚙・modding-general message this code should work but you have to change it for jokers
with the custom sidebar we can just leave them in the old sidebar
it's still accessible
there's also this bit of reference which never made it into 1.0 docs https://github.com/Steamopollys/Steamodded/wiki/[OUTDATED]-Add-or-Replace-a-Sprite#base-references
set = "Joker" G.jokers:emplace(card) Remove the consumeablr buffer line
arguably you just look at the code if you need that
And change the key to shoeman's
i think I'm in favor of just kicking it off the sidebar for now
huh... I would've thought just targeting the already created card would work there...
That's the center not a card
ohh...
also i think we should get rid of the numbering of the page titles / file names
it's out of order with the new sidebar
Center is the information about how to make a card and card is the instance of the card in the game
Can't wait for all links to break
it's an easy fix 😢
it'll just send you home
so this will about work?
I'm already home
hooray!
I'd opt to leave the getting started page's name intact so the links don't break, the rest isn't as important
SMODS.create_card can force an edition but that's fine to
changing the sidebar links isn't much of a concern, it might just be irritating for trying to use links posted in other places
for something like https://github.com/Steamopollys/Steamodded/wiki/05.-SMODS.Center#smodsback-formerly-smodsdeck, I'm inclined not to care
If were going to break links I say just break them and will fix them as they crop up
it's just that the getting started page has been refed a lot and is probably in a bunch of other places
though it just sends you to home so it's not hard to find the real page from there
fuck it we ball
TBH home could be the getting started page
good point
I wonder if the sidebar can have collapsible parts
cursed filename [Guide-‐-Joker-Calculation.md]
oh these are different -s
vscode displays them the same lmao
markdown supports them, so yes
how do i get the rarity of a joker in G.Jokers.cards?
is it just G.Jokers.cards[i].rarity?
G.jokers.cards[i].config.center.rarity
thanks
1 is common, 2 is uncommon, 3 is rare, 4 is legendary
it's not guaranteed to be a number though, with custom rarities
yeah i know
i was just looking into it
my card rerolls all of the jokers in hand minus itself and i wanted it to keep rarity
pain in the ass tbh how thunk programmed it 😭
i had to make a huge if/else just to change it to 0.75 for uncommon and 0 for common 💀
because yes, create_card with 1,2,3,4 does nothing for whatever reason
rarity = (rarity == 4 and 4) or (rarity == 3 and 0.98) or (rarity == 2 and 0.75) or 0 this will change it for vanilla rarities
oh actually that's REALLY good
i'm fairly new to lua but that's so much more optimized
thanks
the 4 does nothing though unfortunately 😅
it has to have something set to true but that's alr
I don't know why I set it to 4 😆
4 is truethy
but I check later on if it is 4 for legendary stuff
it is but create_card needs to have the 3rd arg set to true to spawn a legendary and it ignores whatever the number is
this broke it actually
😭
wait nvm i'm just stupid
rarity == 4 as the arg is fine
yea ik
to my knowledge tho i still need the true statement tho iirc
pretty sure the arg is literally like _legendary or smf
coooool it works
i wanna keep working on the texturing for the nameplate, it kinda sucks ass lmfao
texturing the nameplate?
yeah
i'm working on that isaac mod
rn i'm on dice
i finished d20 yesterday, today was d4
also gonna try to do d6 today if i can
i think polyphemus will be legendary and have ^2 mult or smf
maybe i'll even make it exotic in tandem with cryptid or smf
so why is the lovely mod flagged as a virus?
It behaves quite similar to some trojans. See https://github.com/Steamopollys/Steamodded/wiki/01.-Getting-started#step-1-anti-virus-setup
(ooh, nice job on moving the "Anti-virus setup" section to be first btw, whoever did that)
I wonder if we can get a chat bot in here to auto respond with that to messages that mention lovely and virus
Idk
the mods don't like bots haha
Meth should probably put the antivirus warking on the lovely downalod page
a bot that explained the cards by pulling from the wiki was suggested a couple times and denied
probably a good idea
since it's been such a massive pain in the ass
you would think that it would become trusted given the amount of people downloading and using it
my anti-virus actually said something new last time
it just gave this pop-up every time I launched the game but it didn't stop/remove anything
(I had no exclusions on this folder/file - I did have tell win def to allow it to stop the notifications)
How do you get that grey subtext for a joker? Is that just part of the text field in loc_txt?
C:inactive
does anybody know why this isn't destroying cards in rank 3?
deck.apply = function(self)
G.E_MANAGER:add_event(Event({
func = function()
for _, card in ipairs(G.playing_cards) do
for _, rank in ipairs({2, 3, 4, 14}) do
if rank == card:get_id() then
card:remove()
end
end
end
return true
end}))
end
like this should be incredibly simple i'm so confused
hopium, maybe this means they've updated their heuristic
I've figured out a fix and I would like you to test it when convenient
When making the art for the back of a deck, do you setup the file the same as making joker art (71x95), or do you copy the whole enhancers.png file and add it there? If the latter, how do you make it work with other deck mods?
you do the same as what you do for joker art (make a new atlas .png that you load in)
the aspect ratio is the same, i believe most card-related things are (decks, cards, consumables, jokers, etc)
any help?
Nvm figured it out
Well it's a really weird way to set the function. Are you sure you're setting it before it gets called?
i mean it's a function that's part of SMODS.Back
i'm confused, how would you write it?
SMODS.Back {
key = "example",
pos = {x = 0, y = 4},
loc_txt = {
name = "Example Deck",
text = { "Text" }
},
apply = function(self)
...
end
}
so this is the load file's code to load the actual thing:
for _, v in ipairs(decks_to_load) do
--load file and call it deck_loaded for this purpose so we can modify the deck and take from it instead of just its name like with deck_name
local deck_loaded = SMODS.load_file("source/decks/" .. v .. ".lua")()
--throw an error and instead of crashing the game like an angry toddler if the deck isn't found
if not deck_loaded then
sendErrorMessage("Error loading file " .. v .. ".lua", "Shellular's Deck of Cards")
else
--set "universal" info for every deck here so i don't have to write "atlas = 'deck_atlas'" 1 quadrillion times
deck_loaded.key = v
deck_loaded.atlas = "deck_atlas"
deck_loaded.unlocked = true
deck_loaded.discovered = true
if not deck_loaded.pos then
deck_loaded.pos = { x = 0, y = 0 }
end
local deck_obj = SMODS.Back(deck_loaded)
--i'm a little stupid & don't totally know what this means but it's basically going "for each function in the file, pull function and add it to deck_obj"
for k_, v_ in pairs(deck_loaded) do
if type(v_) == 'function' then
deck_obj[k_] = deck_loaded[k_]
end
end
--you did it *party.wav*
sendInfoMessage("Loaded " .. v .. " deck successfully", "Shellular's Deck of Cards")
end
end
and this is the file for the deck in question's code:
local deck = {
name = "Harlequin Deck",
pos = { x = 7, y = 0 },
loc_txt = {
name = "Harlequin Deck",
text = {
"Start run with no",
"{C:attention}Aces{}, {C:attention}2s{}, {C:attention}3s{}, and {C:attention}4s{}",
"in your deck"
},
},
config = {},
}
deck.apply = function(self)
G.E_MANAGER:add_event(Event({
func = function()
for _, card in ipairs(G.playing_cards) do
for _, rank in pairs({2, 3, 4, 14}) do
if rank == card:get_id() then
card:remove()
end
end
end
return true
end}))
end
return deck
How do you add a custom joker at start in a custom deck? Do you use the joker's key?
local greed_joker = create_card('j_greed', G.Jokers, nil, nil, nil, nil)
greed_joker:add_to_deck()
G.jokers:emplace(greed_joker)
Ah I see you just have the object call in the main file and all the definitions in another file. That makes a lot more sense than what I thought you were describing haha
yeah i'm a bit less smart so i just go "this is what tells the other thing the properties to turn into a deck"
i'm still really confused on why it doesn't destroy threes
Yes, you need to use the joker's key.
On modded jokers, key is different from what you give it on instantiation, which basically boils down to [type]_[mod-prefix]_[original-key], e.g. j_lars_jimbo. See #💻・modding-dev message for some more examples.
Also, you probably want to use SMODS.add_card instead of create_card or add_joker.
You can add keys in the config to start with them too
even if i copy the code from hack for selecting cards it doesn't select threes. what is happening
are you iterating over a table while you're modifying it?
(I can replicate btw. That was very confusing for a sec haha)
(okay i'm glad i wasn't just being a dumbass and it was something that others struggled with too)
i'll try not doing that
no worries, it's a common trap haha
just iterate using index
something like this should work #💻・modding-dev message
how would I get my mod to load extra lua files in a folder in the game's directory, it doesnt seem like they do so automatically
assert(SMODS.load_file("path/to/file.lua"))() I believe
How do you set the rarity of a joker? I want to set one to rare (From looking at the source, I think thats an int at 2?)
rare is 3
My joker multiplies mult by how much money you have. However, its value is based on how much you have before you play your hand. So, if you play a gold seal card, the joker's mult will not reflect that when it triggers. How do I ensure that it does update correctly? Should I just use Xmult instead of the local mult?
update = function(self, card, dt)
-- Calculate the multiplier
card.ability.extra.Xmult = G.GAME.dollars / 100
end,
calculate = function(self, card, context)
if context.joker_main then
-- $100 = 1x mult. $80 = 0.8x mult.
local mult = G.GAME.dollars / 100
return {
card = card,
Xmult_mod = mult,
message = 'X' .. card.ability.extra.Xmult,
colour = G.C.MULT
}
end
end,
There’s a “buffer” variable you can add to it, ctrl+f through card.lua for bull or bootstraps and you’ll see it there
I don’t rember the specific name
G.GAME.dollar_buffer
I assume its G.GAME.dollar_buffer? Would I use that in place of G.GAME.dollars in my equation?
okay, thank you!
also you don't need the update function if you recalculate in loc_vars, there's no need to do it every frame
I have it display in the text field of the Joker (Like how Joker Stensil displays the num of empty joker slots).
yeah i figured
idk what im doing but this crashes when I try to open balatro with it
yes jestie, that is not proper syntax
Do you think one would be fine with a spectral like this? I feel like It lacks a lot of detail that other spectrals have. This is my first time spriting, so I just want to know if it would be good enough to seem vanilla-ish
(Also would this be considered mod development? Since this is for a mod I'm making)
my joker works perfectly (yay!!!) but the only issue is that the description is incorrect, it displays the current xMult where the amount increased should be
and idk why that is
i like the looks, but it seems to be a bit shallow compared to other spectrals
it could use some more depth
Yeah I see what you mean, I'll try and add some depth
forgive me for it being kinda ass since this is my first time lol
i could see the card looking like it's rotated a bit about that middle line
wdym?
like it's being warped?
or the entire card
How do you get the on hover effect with the description of something based on what is specified on a deck's (or even joker's) text field? For example, T:m_gold shows the description for a Gold Card. How could I do that for a modded joker?
text = {
'Start with {C:money}$100{},',
'Deck of {C:attention,T:m_gold}Double Gold{} cards.',
'Start with the {C:red, T:j_gree_greed}Greed Joker{}.'
},
say you take that inner card and rotated it so one side faces more towards you
how do i create a sync table that replaces any of the game's specified songs by default with mine btw
the wiki is NOT specific
dunno just an idea, I'm not an artist
Oh I see, basically like Immolate?
sort of, though I was thinking of rotating about the vertical axis
oh nvm
like this, right?
is create_replace_sound called by SMODS.Sound:create_replace_sound or is it standalone?
it's called on an instance of SMODS.Sound, i.e., what's returned by the constructor. But you can just put replace = 'music1' or similar in the constructor
how would that look /gen
yeah, but in a different direction. here the bottom side is rotated towards you, I'm thinking rotate about the vertical axis (where the sides flip) so the left or right side is closer
SMODS.Sound {
...
...
replace = 'music1',
...
...
}
{s:1.2}
or {s:whatever_number}
the key gets the prefix automatically. it just has to contain music for reasons™️
key
does it matter if i add an underscore after music
no, it just has to contain it as a substring
something like this? pretend the red is the backside
i have a hard time seeing which way this is supposed to be rotated, but yes
might just be because it's out of context
yeah i just did that really quick to see if that was what you were talking abt lol
ok so like where is there latency on my sync tracks 💀
When making multiple decks, should you use just one atlas and lay the back images out next to eachother or should you use multiple atlases, with each back its own seperate file?
it's REALLY bad btw
now idk how to warp the graphics 😭 🙏
like at least .25s delay
istg there was no delay in rx11
what did i do wrong the local vars dont update correctly
how would one warp the graphics on this so it looks like it's in it's correct orientation? I have no idea how to lol
I can imagine it but I can't do it
bumping as I am still not sure what the issue is
what are your loc_vars
they're both the same
How would I debuff all suits except a specified one? I assume I would use trigger_effect in SMODS.Back as the base, but what would the if-statement look like?
where can I find documentation about how deck code works in steammodded's current version
on the smods github wiki
there only seems to be outdated documentation
yeah out of the three paragraphs of create a deck, all of them are outdated.
yeah thats the outdated part lol you dont look at the outdated part
its in SMODS.Center with the rest of the center-related things
oh
if you dont want to find outdated stuff dont look at the outdated sections
ok yeah i didnt know the center area had stuff about decks
yeah sorry
Tbf who would click on SMODS.Center when they read it? It means nothing
would it be a positive or a negative to separate out the centers into their own pages? 🤔
I also wonder if it'd be beneficial to have like a page 0 that defines key terms, like what a center even is
I vaguely know from skimming this chat, but if those pages are meant to be of use to a newcomer
https://github.com/Steamopollys/Steamodded/wiki/03.-API-Documentation would probably be "page 0"
On that same note, can somebody please put in the docs how original_key transforms into key?
It's confusing and to understand it you need to either read steamodded's internal code or ask in #💻・modding-dev
Just being able to link to the explanation would be nice instead of having to go through the whole spiel of having to explain wtf type and mod prefixes are
quick question, do custom info queues need to be in a localization file to be used?
cause i have one that is set to a table with name and text and im getting an info queue that says error
afaik yeah
im trying to make a deck that increases the maximum joker slots by one everytime a joker is added to hand and vice versa, but im having a hard time figuring out some of this stuff. like how can i alter joker slots, using add to hand
ive tried looking for refrences but i just cant find anything similar enough that i can use for this
Negative jokers just modify G.jokers.config.card_limit like so
if not self.edition then
self.edition = {}
if self.added_to_deck then --Need to override if adding negative to an existing joker
if self.ability.consumeable then
G.consumeables.config.card_limit = G.consumeables.config.card_limit + 1
else
G.jokers.config.card_limit = G.jokers.config.card_limit + 1
end
end
end
self.edition.negative = true
self.edition.type = 'negative'
this is in Card:set_edition so you could probably add this code to the add/remove function
au tysm
Is it possible to get the source code on mac?
yes, by switching to windows like any sane person
bro im broke
same
sorry for asking so many questions but I don't know whats going on here
oh btw, this is so cool
card = card
ah that makes sense
and also you need to specify more contexts in context.cardarea == G.jokers
move the context.joker_main up to that check
`local cardaddtodeck = Card.add_to_deck
function Card.add_to_deck(self,edition)
cardaddtodeck(self, edition)
if self.ability.set == 'Joker' and (edition == nil or not edition.negative) then
G.jokers.config.card_limit = G.jokers.config.card_limit + 1
end
end
local removefromdeck = Card.remove_from_deck
function Card.remove_from_deck(self)
removefromdeck(self)
G.jokers.config.card_limit = G.jokers.config.card_limit + 1
end`
can you tell me what i did wrong here?
the game runs but this doesnt do anything
yeah idk what I was doing there lol, ty
I would think this would work (though I'd swap the + to a - in the remove from deck line, otherwise joker slots only go up
). Are you sure its actually running your code? You could try putting a debug statement in your section of the code and then try adding a card to your deck
this is the full thing, the first part is working put the second part isnt doing anything as in i can play the deck put none of the code works.
`
SMODS.Back{
name = "Infinite Jokers",
key = "infD",
pos = {x = 0, y = 3},
config = {joker_slot = -4}
loc_txt = {
name = "Infinite Jokers"
text = {
"Start With Infinite Joker Slots."
},
},
local cardaddtodeck = Card.add_to_deck
function Card.add_to_deck(self,edition)
cardaddtodeck(self, edition)
if self.ability.set == 'Joker' and (edition == nil or not edition.negative) then
G.jokers.config.card_limit = G.jokers.config.card_limit + 1
end
end
local removefromdeck = Card.remove_from_deck
function Card.remove_from_deck(self)
removefromdeck(self)
G.jokers.config.card_limit = G.jokers.config.card_limit - 1
end
}
`
uhhh maybe because this is all inside SMODS.Back? It looks like your indentation is all off but that could be from discord formatting weird. Can you try putting 3 ` around your whole code, that'll make it a whole code block instead of each line being individual
You can even do ```lua to get code highlighting
SMODS.Back{
name = "Infinite Jokers",
key = "infD",
pos = {x = 0, y = 3},
config = {joker_slot = -4}
loc_txt = {
name = "Infinite Jokers"
text = {
"Start With Infinite Joker Slots."
},
},
local cardaddtodeck = Card.add_to_deck
function Card.add_to_deck(self,edition)
cardaddtodeck(self, edition)
if self.ability.set == 'Joker' and (edition == nil or not edition.negative) then
G.jokers.config.card_limit = G.jokers.config.card_limit + 1
end
end
local removefromdeck = Card.remove_from_deck
function Card.remove_from_deck(self)
removefromdeck(self)
G.jokers.config.card_limit = G.jokers.config.card_limit - 1
end
}
i didnt know putting everything into smodsback would be a problem kind of my first deck
if i move the final closing bracket to before the code starts it will work then?
Yeah I don't think it goes in there, I think that will just be used to register deck to the game with its name and description and whatnot
The actual code will have to register whether or not you're playing with that deck
One sec
I'm thinking its going to be like the anaglyph deck
But I've never actually done this so if someone else has more insight that might be more useful
So i have info_queuse on my one joker and only the name in the box appears, not the text.
This is how the record in en-us.lua looks like
default = {
name = "Boss Soul",
text = {
"Defeat a Boss to gain a {C:legendary}Boss Soul{}"
}
},
and below is being called in local vars of the joker
OSIRIS.GENERATE_OSIRIS_INFO_QUEUE_BOSS = function(self,bossName,info_queue)
local _boss
if bossName == "" then
_boss = OSIRIS.BOSS_TEXT_TABLE['Def']['Key']
else
_boss = OSIRIS.BOSS_TEXT_TABLE[bossName]['Key']
end
info_queue[#info_queue+1] = {set = 'OsirisInfoQueuesBoss',key = _boss}
end
in this case key is "default"
I can't find how anaglyph does its thing, but one way you might be able to get it to work is by checking in the add/remove methods what back is currently in use and then running your code if its yours, but this seems..inefficient? You might be able to find more info on adding new decks by exploring some githubs of other mods that do so
Could you set joker slots to the length of G.jokers + 1? Idk if it will work but it might be worth a shot
config = {joker_slot = #G.jokers.cards+1} Like this?
what's the issue with just setting the limit to a massive number when you enter the game
thats not cool
i feel like it's a little misleading if it's not like that
finite joker deck
people might start a run with the deck and see the joker slots be normal and get confused
tbh that could be cool
+1 joker slots, joker slots can never change
it'd be bad
but cool
if one wanted to get / compare the editions of all played cards in a hand, what would that look like
this is what ive been trying so far, and thought because of a bug with lovely both return nil, it does successfully tell me that one does and one does not when i play a hand where that is true
if context.before then
if next(context.poker_hands['Pair']) then
local edition_one
local edition_two
for k, v in pairs(context.scoring_hand) do
if v.edition then
if edition_one then
edition_two = v.edition
else
edition_one = v.edition
end
end
print(edition_one)
print(edition_two)
end
end
however when using edition_type it no longer works?
Yeah that
we got some workin jokers here (for the most part)
ballot is there to just better show what some of them do
yes those placeholders are from cryptid
descriptions?
attempted to index joker feild a nil vlaue
kinda expected it ngl
Same but worth a shot
I show them in the video
oh true
lobster!!
i guess a better description of the problem is that v.edition_type returns nil as well
where at least v.edition returns the correct boolean
so in
if not edition_one or not edition_two then
if edition_one == edition_two then
-- neither
print("Neither")
else
-- one has an edition
print("One",edition_one)
end
-- at least one parent has no edition (mixed or neither)
else
-- both have editions (different or same)
if edition_one == edition_two then
-- same editions
print("Same",edition_one)
else
-- different editions
print("Different",edition_one,edition_two)
end
end
these guard cases, using v.edition will correctly give me "One" because one is nil (not true) and true ~= nil
but with v.edition_type it gives me neither because it sets both as nil even though it knows one has an edition and therefore nil == nil
most likely theres a better way to do this altogether, preferably without using an iterator
if anyone can help me make this work id appreciate it it still doesnt
does anyone have an overlay for the stake shading?
what context guide?
Don’t link that one
ooooooooooooooooooo
Because divvy rewrote it so it’s actually readable
thanks divvy
It recommends the simulator code but I found it harder to read
I also thought the original Discord messages were fine
Tbf the original discord messages didnt really explain that much
It just info dumped the context properties
i would say add a [DEPRECATED] in the title but that clearly that didn't work out well for steamodded 
Yeah I don’t find the simulator code easy to read either but I already understand all the contexts so I’m probably not the best judge of it
I can add the new guide to the discord post though
Oh yeah that's probably a good idea
Hey there, first time modder and awfully inexperienced coder here
I'm trying to make a simple Joker that creates a Devil Tarot card when a Round starts, haven't been able to find a way for now. Is that something feasible to do with modding?
If it can be described as a combination of different base game jokers it should be relatively easy to do
Yeah, I was trying to modify the behavior of the Cartomancer joker basically
G.GAME.consumeable_buffer = G.GAME.consumeable_buffer + 1
G.E_MANAGER:add_event(Event({
func = (function()
G.E_MANAGER:add_event(Event({
func = function()
local card = create_card('Tarot',G.consumeables, nil, nil, nil, nil, nil, 'car')
card:add_to_deck()
G.consumeables:emplace(card)
G.GAME.consumeable_buffer = 0
return true
end}))
card_eval_status_text(context.blueprint_card or self, 'extra', nil, nil, nil, {message = localize('k_plus_tarot'), colour = G.C.PURPLE})
return true
end)}))
end```
except that instead of picking random Tarots, it should pick a Devil card. Should be something related to the 'car' tag in the function if I got it right
You might want to take a look at SMODS.create_card, and the key you want is c_devil I think? Can't check right now
oh man i fucking hate ui code
i would rather die than do it
i wanna make a page thingy like in the collection for preset disabled items in #1306355083268722728
but god
it is
so fucking annoyin
@wintry solar do UIs allow infinitely recursive backwards references
i would imagine not?
🤷♂️
what is it you're trying to do?
linux also works and is free
though I'm not clear on whether the great apple overlords will let you install it on their hardware
very unseriously attempting to create an SMODS ui library (which acts as an overhead for vanilla UI)
specifically in this instance i want to, for every single node in a UI, coerce it to an object with an smods overhead object
so i would need to recursively go through the ui nodes, and i would love to be able to do that with unlimited depth
pretty sure you can get source code on mac
and by unseriously i mean i dont plan on going through with it unless its actually useful
it's not obfuscated or compiled or anything
i am getting somewhere i think
wdym by that? like a page with all your disabled items
page with presets
oh ok
I honestly don't know what to do for the background, any suggestions for things I could use as inspiration?
hmm, what's another optical illusion that can tile 
that escher big thingy would be cool
this
true
it'd probably be a paint to draw tho 😭
I think I'm just gonna draw walls and doors in wacky orientations like this
On my on joker i keep getting an error on end of round that says 'for limit must be a number' on line 211 of state events
the only weird thing im doing in the code is calling a function from another file and the context of said function is before so idk
calculate = function (self,card,context)
if card.ability.extra.boss ~= "" then
return{
message = OSIRIS.BOSS_TEXT_TABLE[card.ability.extra.boss].func(self,card,context)
}
end
if context.end_of_round and not context.game_over and not context.repetition and G.GAME.blind.boss and not context.blueprint and not card.ability.extra.abilityStopper then
card.ability.extra.boss = "The Ox" --for testing, can change later on
card.ability.extra.abilityStopper = true
return {
message = "Stolen!",
card = card
}
end
end
first ever message in this server only to recommend this one: https://en.wikipedia.org/wiki/Sky_and_Water_I
Sky and Water I is a woodcut print by the Dutch artist M. C. Escher first printed in June 1938. The basis of this print is a regular division of the plane consisting of birds and fish. Both prints have the horizontal series of these elements—fitting into each other like the pieces of a jigsaw puzzle—in the middle, transitional portion of the pr...
Iirc that error means you're returning something unexpected in a .repetition context. Make sure you have a check so that doesn't happen on accident
I have a check for not context.repition in the if statment
Yeah the first one
I think I'm fine with this for now but I may change the colors of the bg
guys
what percentage of people do you think will miss this
installation steps moved to https://github.com/Steamopollys/Steamodded/wiki main page^
has anyone dabbled in config files, particularly ones you can edit in-game (like with debugplus)?
95% of Balatro players can't read
i can't find documentation for creating config files specifically and my very crude config file can't be edited at runtime and isn't very user friendly
The Steamodded wiki has a page on it
that's more than twice the percentage of players it was before, so that's progress
ah twas hiding from me thank
truly a skill issue at navigating wikis and documentation
Ooh I'm liking this rewrite
counting it as a win if 2.5x more people can read because of it
That's 5% of the community WOOOO
nice
Looks fine to me /s
padding is afraid of him
what is calculate_joker and how do i use it?
what are u trying to do
because calculate_joker just, handles joker calculations for all cards
it doesn't have a usecase for typical things
i have no memory of this
oh this?
yeah i dont think calculate_joker would be any help there
yeah im just trying anything
local oldupd = love.update
--save the love.update function so we can call the updates for the rest of the game
function love.update(dt) --runs every frame, dt = time since last frame
if G.GAME and G.GAME.selected_back and G.GAME.selected_back.name and G.GAME.selected_back.name == "Infinite Jokers" then --if theres a game in progress, a deck, and the deck is the infinite joker deck
G.jokers.config.card_limit = #G.jokers.cards + 1 --set the joker limit to the number of jokers + 1
end
oldupd(dt) --call our saved update function so that the rest of the game can do its updates
end
should work
so i can feel like i got something out of wasting 8 hours trying to do this can you atleast explain what love.update and oldupd(dt) is since i havent heard of either until now
well yeah lol
we dont care about optimization here do we
and its like, barely anything so
wont make a dent
😭
I mean no it won't have a real impact but
just feels inelegant
step 1. get it working
step 2. say you'll optimise it
step 3. never do
the alternative is hooking multiple functions for removing a joker, removing a joker from an area, creating a joker, moving a joker to an area, etc
you only need a couple of those but i wouldnt know which youd need to hook
would setting the joker slots to math.inf or whatever the lua equivalent is work? 🤔
do i put the code inside the smods.back {} or do i make a new lua file or what
math.huge and yes but this person wants to do the other thing
just in the main block of your file
SMODS.Back{
...
}
--code
ok i did that and this doesnt do anything
elaborate ?
loads the deck deck does nothing.
can u post the entire lua file
SMODS.Back{
key = "infD",
config = {joker_slot = -4},
loc_txt = {
name = "Infinite Jokers",
text = {
"Start With Infinite Joker Slots.",
},
},
}
local oldupd = love.update
--save the love.update function so we can call the updates for the rest of the game
function love.update(dt) --runs every frame, dt = time since last frame
if G.GAME and G.GAME.selected_back and G.GAME.selected_back.name and G.GAME.selected_back.name == "Infinite Jokers" then --if theres a game in progress, a deck, and the deck is the infinite joker deck
G.jokers.config.card_limit = #G.jokers.cards + 1 --set the joker limit to the number of jokers + 1
end
oldupd(dt) --call our saved update function so that the rest of the game can do its updates
end
ah you removed the name
maybe because i didnt put an extra name
SMODS.Back{
key = "infD",
name = "Infinite Jokers",
config = {joker_slot = -4},
loc_txt = {
name = "Infinite Jokers",
text = {
"Start With Infinite Joker Slots.",
},
},
}
local oldupd = love.update
--save the love.update function so we can call the updates for the rest of the game
function love.update(dt) --runs every frame, dt = time since last frame
if G.GAME and G.GAME.selected_back and G.GAME.selected_back.name and G.GAME.selected_back.name == "Infinite Jokers" then --if theres a game in progress, a deck, and the deck is the infinite joker deck
G.jokers.config.card_limit = #G.jokers.cards + 1 --set the joker limit to the number of jokers + 1
end
oldupd(dt) --call our saved update function so that the rest of the game can do its updates
end
gg
have you considered making the buttons not right on top of each other
you could for sure fit like, 10 of those per page
if they werent so large
now we need Disable Disable Disable Vanilla Jokers
Enable Disable Vanilla Jokers
ok it works, im gonna see if i can make it do everything i want using this as a refrence
Is there a wiki for the Balatro APIs? I know about the steamodded wiki, but is there one that focuses on the game's source?
haha i wish
game is basically undocumented apart from steamodded's own docs
ah okay.
its more fun this way
if you're lucky Thunk added a comment
smh
you're lucky there isn't some eloborate decompilation process you need to go through to get to the source code
smh
0.9.0 demo flashbacks
no joke, there was only one github repository that worked to decompile the source code
because it used a specific version of LuaJIT
Yo
local addjokerslot = Card.add_to_deck
function Card.add_to_deck()
if G.GAME and G.GAME.selected_back and G.GAME.selected_back.name and G.GAME.selected_back.name == "Infinite Jokers" then --if theres a game in progress, a deck, and the deck is the infinite joker deck
G.jokers.config.card_limit = #G.jokers.cards + 1 --set the joker limit to the number of jokers + 1
end
addjokerslot()
end
Whenever i buy a card the game crashes.
I wasn't in the modding game yet back then haha
but i did have the highest glitched score
that wasn't actually 0.9.0
0.9.3 iirc
anything wrong here? no crashes or anything its just not retriggering any cards
oh wait do I need to do context.repetition? lemme try that
that didnt work
right
heres one of my jokers that retriggers certain suits, so just ignore that one line
ah, reptitions = card.ability.extra.reptitions... maybe you could do repetitions = 1 then?
im not sure, i'd just use card.ability.extra...
alrighty ill try that
How can you get a joker to debuff an entire suit like some of the blinds do?
no luck
I think its an issue with the chances
I need to check this actually
ok so its NOT an issue with the chances
local addjokerslot = Card.add_to_deck
function Card.add_to_deck(self, ...)
if G.GAME and G.GAME.selected_back and G.GAME.selected_back.name and G.GAME.selected_back.name == "Infinite Jokers" then --if theres a game in progress, a deck, and the deck is the infinite joker deck
G.jokers.config.card_limit = #G.jokers.cards + 1 --set the joker limit to the number of jokers + 1
end
addjokerslot(self, ...)
end
alternatively ```lua
local addjokerslot = Card.add_to_deck
function Card:add_to_deck(...)
if G.GAME and G.GAME.selected_back and G.GAME.selected_back.name and G.GAME.selected_back.name == "Infinite Jokers" then --if theres a game in progress, a deck, and the deck is the infinite joker deck
G.jokers.config.card_limit = #G.jokers.cards + 1 --set the joker limit to the number of jokers + 1
end
addjokerslot(self, ...)
end
Okay, I got the debuff part working, but is there a way to have it show the debuffs when a round starts, similar to some blinds? I figured I would move part of it to the deck code, but what do I use to check if a round has started?
calculate = function(self, card, context)
for _, card in ipairs(G.playing_cards) do
if card.base.suit ~= 'Hearts' then
SMODS.debuff_card(card, true, 'testJoker')
end
end
end,
still having issues
again, no crashes, its just not retriggering any cards
I temporarily commented out the chance's code just in case there was a problem with it
Are you working with a new instance of the joker or loading an old save?
Probably
Try creating a new instance of your joker
The old save probably doesn’t have the repetitions in the config
yeah if you change config old saves don't
this also means if thunk adjust values in an update old save jokers will have old values still
for most jokers
id sometesting with this and i ended up realizing that i wasnt saving it properly because i actually tried this lol, but what ends up happening is that although it does work, the game will run this code before the joker is actually added and not after.
the simplest solution is just to only activate the code when a joker is added to the deck, how do i specify for that
Is there a way to set text size and color? {C:inactive, s:0.8} colors the text gray, but doesnt resize.
SMODS.Joker had an add_to_deck
this is most certainly not the simplest solution
this is the simplest solution and the overhead is in the nanoseconds so
Wait ehats going on?
incorrect, the simplest solution would be setting joker_slot = 1E300
You want a deck where you always have more joker slots?
since the game would crash long before ever reaching that number its technically infinite
it would be if that was relevant to your problem
Just use the update function to set the joker slot limit to 1 plus the number of jokers
you've been clear you don't want to do that
yeah
Why are we overriding global functions for this?
we did this
yeah okay ill just do that then, ill credit you since i didnt even write any of the code for it 😦
When I play a hand of hearts, this joker is suppose to increment its own mult by 5 per heart card played, but its getting up into the thousands, with numbers like 6,200. Is the issue how I am incrementing the mult?
calculate = function(self, card, context)
for _, pCard in ipairs(G.playing_cards) do
-- Debuff all non-Heart cards, except for Stone Cards
if pCard.base.suit ~= 'Hearts' and pCard.ability.effect ~= 'Stone Card' then
SMODS.debuff_card(pCard, true, 'lJoker')
end
-- Increment mult for each played Heart card
if pCard.base.suit == 'Hearts' then
card.ability.extra.mult = card.ability.extra.mult + card.ability.extra.multAdd
end
end
-- Add mult
if context.joker_main then
return {
card = card,
mult_mod = card.ability.extra.mult,
message = '+' .. card.ability.extra.mult,
colour = G.C.MULT
}
end
end,
Your iterating part has no context check so runs for every single context
So should the whole for loop be wrapped in context.joker_main or the inside of the for loop?
You could but there are better ways to do it, look at the joker calculation guide
the game crashes for me after i hit new run
attempted to index jokers a nil value
oh oops
local oldupd = love.update
--save the love.update function so we can call the updates for the rest of the game
function love.update(dt) --runs every frame, dt = time since last frame
if G.GAME and G.GAME.selected_back and G.GAME.selected_back.name and G.GAME.selected_back.name == "Infinite Jokers" and G.jokers then --if theres a game in progress, a deck, and the deck is the infinite joker deck
G.jokers.config.card_limit = #G.jokers.cards + 1 --set the joker limit to the number of jokers + 1
end
oldupd(dt) --call our saved update function so that the rest of the game can do its updates
end
now it doesnt work at all
Speedrunner
how can you tell which specific pack has been opened? i can see G.booster_pack for any and G.booster_pack_meteor for celestials but i don't see any kind of variable for buffoon, spectral, cards, arcana etc.
SMODS.OPENED_BOOSTER should have the booster card
Blueprint and Brainstorm label my joker as incompatible, yet they still trigger. is there a flag that needs to be enabled for them to show compatible?
blueprint_compat
How to you prevent blueprint from triggering on a joker?
that one you can only do in the code of your calculate function
if not context.blueprint then
Is there a way to prevent a joker from being sold at the shop, like the legendaries?
yes, it's best to use an in_pool function for that
sell this joker to skip to next multiple of 8 ante
would I just set in_pool to false to do that?
you set it to a function that returns false
though it also won't spawn in the shop if you give it legendary rarity
If it has legendary rarity, I assume it would still show up in soul cards?
yes, unless in_pool is returning false
Okay, thank you! Do you know if theres a way to have colored text but also change its size? I tried {C:inactive, s:0.8}, but it only changes the color, not the text size.
inactive inherently changes text size iirc?
don't think so
Wow that actually worked. idk why a space would mess that up. Thank you!
the parser just doesn't understand that
??????
using my method of changing add_to_card instead of updating every tick doesnt crash the game on the second run but when i try to add in more functions it crashes saying function arguments expected near function
== for comparison
send code ?
oh right
how do i make multiple functions
key = "infD3",
name = "Mrk3",
config = {joker_slot = -4},
loc_txt = {
name = "Infinite Jokers3",
text = {
"Start With Infinite Joker Slots.",
},
},
}
local addcard = Card.add_to_deck
function Card.add_to_deck(self)
if G.GAME and G.GAME.selected_back and G.GAME.selected_back.name == "Mrk3" then --if theres a game in progress, a deck, and the deck is the infinite joker deck
G.jokers.config.card_limit = #G.jokers.cards + 1
G.jokers.config.card_limit = G.jokers.config.card_limit + 1
end
addcard(self)
end
local removecard = Card:remove_from_deck
function Card:remove_from_deck(self)
if G.GAME and G.GAME.selected_back and G.GAME.selected_back.name == "Mrk3" then --if theres a game in progress, a deck, and the deck is the infinite joker deck
G.jokers.config.card_limit = #G.jokers.cards
end
removecard(self)
end
it crashes on the second function but works normally when i delete it
local removecard = Card.remove_from_deck
not Card:remove_from_deck
oml
you can only use the colon when you're actually calling the function. also, self is implied when you do Card:remove_from_deck()
Card.remove_from_deck(self)
is the same as
Cars:remove_from_deck()
it was crashing when i didnt have it ealier though?
How do you add money with a joker? I thought it was dollars?
if context.joker_main then
-- Double money
local dMoney = G.GAME.dollars * 2
return {
card = card,
dollars = dMoney,
message = '+$' .. dMoney,
colour = G.C.MONEY
}
end
right now the second function is crashing because of index self nil value whether or not i specify self
nvm i didnt change the second : to .
it works
so uh, is extra_value the value of the card or the, well, extra value of it?
as in, the value gained
added sell value, like from gift card
hmmm
actual sell value is sell_cost iirc
isn't that the sell price?
yeah what else do you mean
nah I'd rather just add the base price than calculate and round down/up the sell price
also, couponed is for when a card is gained for free through tags, right?
theres a function to calculate sell cost iirc
yeah Card:set_cost(). again real sell value is stored in card.sell_cost
yes
I would probably use the sell cost just cause mods may screw with stuff in ways you can't predict
liek I have a joker that spawns jokers who's sell cost is forced to 0
but they still have base cost for example
are they flagged as couponed? if not, I think you should add it 
that's not what couponed does though
couponed cards still sell for a positive price
you know what, this is too much magickery; I'll just use events to set money to 0 after the card is in the deck
you can use add_to_deck to run code when added to deck
ok, so I have a joker that sets money to 0 when bought, the code is this:
-- snip
add_to_deck = function(self, card, from_debuff)
if not from_debuff then
local dollars = G.GAME.dollars
ease_dollars(-dollars)
-- snip (do stuff with dollars)
and it set money to -{j price}
about time I explained myself lol
how do I avoid this?
I think it just adds money, so I dont think that will work
yeah it's relative to current money
nah it would do nothing
Imma try using lovely to inject an extra exact argument into ease_dollars
if you don't care about the effect you can just do G.GAME.dollars = 0
this might be a stupid question but what defines how many chips a card gives? like, if i wanted to make aces score 12 chips instead of 11, what would i call in a joker to change it 🤨
are you setting it and calling ease?
try putting it in an event
cuz it still shows 0
this feels like it's being called multiple times
no, imo it feels like it's setting to 0 before the shop price is paid
yeah so I might be able to do it with events
