#💻・modding-dev
1 messages · Page 71 of 1
it's hard to make something that works across Unity and Minecraft
and, believe me, making something that works for a LOT of games is hard
that's the ideal solution for a balatro-specific mod manager yeah
yeah, go about it in-game
you still need to solve discoverability and hosting, but like I said: how it's done now is fine, we just need repo metadata and indexing
i wonder what exactly you're trying to achieve... neither of us can talk all mod devs into using it and we're already working on something for an in-game solution
we've been there, TS just didn't manage to stay relevant enough
yep, TS didn't stick
and how far in the future is that going to be available?
I mean I'd its hosted on github, basically forever
Also the manual way won't go away
I won't make such a predictment because it will be wrong either way
i don't think you understand the question
when will it be ready
they're asking how long until it's available
no one knows
Oh
which is fine, that's software
Who knows
exactly, it's indefinite
but manual installation exists for now
Same with how long until most mods people want go to thunferstore
If I may give you my reasoning for why I brought it up in the first place:
Creating an actually good mod manager sounds like a giant task, at least to me
It will probably suck for a long time, and be its own project forever
so why not work on a compromise which works towards a band-aid fix while the long term solution is being worked on
because you need to maintain bandaid features
imho it's better to do it right before it becomes adopted
Because our current compromise is fine and the other one has some doensodes wed have to adopt
balatro does not get updated frequently enough for that to be a problem imo
steamodded does
Balatro updates don't break mods (mostly)
Balatro updated don't break mods anymore
Lovely Persits throifg updates
which is another reason why it's not really a problem to have a band-aid solution
We have a band aid solution called installing mods manually
again what do you even suggest we do
that isn't a solution
Sure it is
it's worked so far
It solves the problem of no mods
there is no world in which you can get all current mod devs to start uploading to TS out of nowhere
which was not what we were talking about
why is this necessary? an all or nothing solution gets us nowhere
I doubt we can get most even
it's really hard to move an entrenched community over to something like TS
even if everyone agrees on it, which isn't the case at all
because where is the point in using thunderstore if most mods either aren't on there or probably outdated?
god this is just cyclical
ease of access
Ease of Access except it doesn't work
???
ease of access doesn't matter if you still end up having to install mods manually
If everything is missing or outdated it's not easier
Cause then Jr just doesn't work
Okay
I'd argue the backend isn't too bad to get working, and we've managed with UI before too
what we've been doing is fine for now, where we go is sorta undefined
it's hard to direct authors in a way without stepping on toes
I've learned that lol
sure browsing a database of mods takes some UX considerations, but it's just a search menu in the end
I will say that package management is a bit more complex
version control and resolving dependencies can mostly be automatic
but things are much easier when you can focus on a single game
like I said: Balatro is a prime target for an in-game package manager
Steamodded also already has a working version checker and dependency system
So version resolving isn't that hard on top
I think at this point it's wayyyy too late to consider something like TS
it's gh or a self-managed community solution, but even the latter will have the same problems
maybe cases where mods require a specific version or earlier could be a bit more tricky if there isn't a backlog of versions to pull from
you either make something that works for it all - ts, gh, and whatever else
or we just sorta stick with gh - it's worked in the past and it will work agaain
this is moreso about tooling imho
I can theoretically integrate that tooling into lovely but it goes against the whole "game agnostic" promise
Right, but that's not really what I meant
I feel like whatever gets made will be inferior in some ways to other mod managers for a long time, maybe forever
sometimes you just need to throw time and brains at a problem and it gets better
eh
the big problem here isn't feature complete-ness, it's about directing the community towards something other than gh
which, as we've seen in the past, isn't going to work
it doesn't need integration with lovely, i don't think
I can't think of a reason why it would need to be in lovely either
probably not a good fit with lovely's premise no
maybe steamodded could ship some external tooling that guides you through the install process and does whatever it can automatically
thinking of ease of access up to the point of having steamodded itself up and running
yeah that's also one of my points
getting steamodded itself is already a big barrier in some cases
it's a limit test for the user - if they can't install Steamodded then they're not going to have much luck with mods in general
it's more about lovely tbh
which isn't a good or bad thing, just the way it is
Tbh I see a lot of people struggling with more than just the antivirus
But it's because they don't read
Lol
people also struggle with installing r2mm itself
it's just treadmill work after a certain point
if it's not the antivirus, it's usually the location of steamodded/lovely in my experience
there's nothing wrong with creating an "smods installer" which also installs lovely
I guess you can't help everybody
that's what I've learned yeah
it doesn't mean you don't try
but you can only do so much after a certain point
That'd work if the av thing is ever 'fixed'
god the av problem has been a pain in the butt
But tbh the av is doing what it's designed to
not generally no - I do think you can if you do it personally, but that just becomes unfeasible at some point
of course, yeah, but TS's userbase doesn't allow for that unfortunately
with dev-oriented software absolutely though
anyways either way you guys have my support. I have 0 care if you guys pivot towards ts, nexus, or stick with gh
at the end of the day I mostly care about lovely working
which it isn't for most people lol
it's frustrating because it's such a black box. you throw a new binary at it - all good! and then two days later it's detected
Would a microsoft signing certificate work for that actually? Though they're probably extremely expensive
it's hard to say. the big problem with microsoft certs is that they're yes, expensive, and iirc only available to enterprise
you can self-sign but it doesn't make the problem go away
I don't know that much about them, but self-signing doesn't sound very useful yeah
something something https://en.wikipedia.org/wiki/Evil_bit
The Request for Comments recommended that the last remaining unused bit, the "Reserved Bit" in the IPv4 packet header, be used to indicate whether a packet had been sent with malicious intent, thus making computer security engineering an easy problem – simply ignore any messages with the evil bit set and trust the rest.
I was hoping that reputation based trust would make av problems go away with time, but nope
An easy process to install steamodded+lovely, with steamodded having a built-in manager that can pull from github probably is a good approach
As long as other mod managers were at least considered, so that there won't be a scenario in a ~year where someone goes "why didnt we use mod manager X" and nobody can give an actual good reason why
an in-game package downloader would make steam deck users very happy
that's been the big reason why I don't use mods on my deck
I mean the steam deck does have git so just git clone all the things
the annoyance is switching back and forth between desktop mode tbh
Set up a modpack so all you have to do to update is "git submodule update --recurse --remote --merge"
that's actually very valid
I would need to drop my addiction for 2 minutes to do that though
and that is just not an option
Lmao
ssh in from your pc
are there any templates or actual guides for creating a balatro mod? ive looked at a couple but cant figure out how to get anything to work.
The best thing is the wiki pages and looking at other mods
Do you have any experience coding?
What agrument I should use to disable default console?
--disable-console
thanks
do people have tools to help with making atlases or is it just a photo editor?
#1269501493690503192 message
Does this count?
you could also use something like imagemagick
though not terribly applicable for Windows I admit
Not that it probably isn't also for windows, but Dim's thing would do the same thing as a purpose built tool
I'm just using gimp as of now
Aseprite can make atlases p easy
Epic Brazillian Miku 🇧🇷
I’m so happy people enjoyed my take on Brazilian Miku 😭
I use MS Paint when updating Cryptid atlases (and I think most others use art tools, some of which may have better features for that?)
I still have no idea how to work with this
where do I start
I was done with joker data but this is just confusing
this doesn't look like 1.0.0 code lol
yea thats 0.9.8
danm
better drink the 1.0.0 juice otherwise your code will get outdated, if people are even still playing on 0.9.8
most (if not all) mods being made right now are for 1.0.0
proof of concept that needs a lot of work to function properly in actual gameplay but the idea is simple - have a joker that acts as two jokers
what it does is basically for any action a joker can do it temporarily becomes the joker its made of
so if both jokers trigger with same context you'd need to combine outputs
thats def going to take some work
also find_card is hooked to add fused jokers at the end if they contain either of the fusions
the calculate call gets broken into two different calculate calls
ah so you patch card_eval for that?
nope, infinifusion doesnt return anything as itself and rather acts as a proxy to trigger calcs on the jokers its made of
although it seems like i need to figure out how to save the fusion properly bcos atm it seems like it always breaks due to the fact its constantly changing its center
what a trippy
i cannot distinguish between version code
like
is Blizzow themed jokers version 1.0.0
i cannot
the basic principle for most of the functionality here is ```pull card.ability into a local 'data'
replace card.ability with data.extra.j1_ability
replace card.config.center with G.P_CENTERS[data.extra.j1_key]
run card:<function>(<arguments>)
save card.ability into data.extra.j1_ability
<repeat the same but replace j1 with j2>
replace card.ability with data
replace card.config.center with infinifusion center```
the most annoying will be making info_queue to see the fused jokers bcos vanilla jokers dont come with a loc_vars
@shell timber Think I overtuned your template 😅
oh not bad
if it has SMODS.INIT its not 1.0.0
Oh cool
Ok
Also some mods have upscale.py or some 5hing like config file
Is that mandatory if I want tp wdd jokers?
Not really
upscale.py is just a quick script to change spritesheet size instead of manually doing it.
Config is if you want your mod to enable/disable/modify some properties in itself
btw fyi 5 months ago is not "right now", what i meant are mods currently at the top of #1209506514763522108
Thanks lads
mobile is out
partially 😅
game discussion can't stop talking about piracy lmao
loooooooooooooooooooool
can we get a commemorative joker in cryptid?
the crash of 24
[OR-FGEMF-20] jimbo
Damnit was about to say that lol
It has to be code joker related
or well
code card related
maybe it makes Code Cards and packs free like Cartomancer
blocks purchases for 2 antes but gives you a pointer afterwards
each time you purchase you get a popup like
saying [OR-FGEMF-20]
kinda funny that brainstorm's texture is bleeding into the perkeo due to pixel smoothing
what the fuck does [OR-FGEMF-20] mean 😭
i just realized that the way my infinifusion is setup is kinda stupid because it's hardcoded into being restricted to 2 jokers when if I were to put all of the current code in loops it would allow for theoretically infinite fusions
like I just repeat the same chunk of code twice with different variable names
Can we talk about mobile modding here
ok hello
@languid mirage ik you asked a mod whether mobile modding discussion was allowed, did you ever get a response on that?
Who gives final say if it is allowed
By thunk?
yea
cool
but they wont give any notice otherwise
so we won't know for sure for about a week, probably
i imagine the discussion about porting saves from desktop to mobile is fine though that's not really modding
Yeah
porting saves? I think so
Hopefully
save editor stocks on the rise

I’m sure you can inject mods with save data tho
not well
hah
very much doubt that lol
you can actually
interesting
balatro is a gamecube game real
save file is an encoded lua file that returns lua table
I may or may not have injected 0.9.8 with the settings file
so it's not impossible to just decode the file, edit it to load stuff, and encode back
it's rather sad that save files can be an attack vector tbh
is there an actual reason for it being that instead of something reasonable like a json file
dont think so
there's one on github with a free use license so meh
I mean... the only performance you're saving is on load
which I don't think matters?
balatro is (was?) a one man team
and the save file works so it doesn't really make a lot of sense to focus on it instead of one of a bunch of other issues
espescally with the potential issues that may come up
okay so I can confirm that when opening balatro
the cloud save loading into the game
will overwrite the library folder containing your game save
if you pull the cloud save, close the game, replace the save, i think it should be fine
or just replace it with the game running
but before it saves itself
what if you turn off the internet, update save and start the game
then turn on the internet
or just switch steam to offline mode
attempt number 2 incoming
didn't work
even with wifi off
so i'm wondering if there's a different save spot
Yeah probably on device or in the app somewhere
Might have to clean out the app entirely of all cache and save data
Because remember you can’t just add data you also have to remove the old save
but it is also overwriting that folder that i'm importing stuff into
Maybe the iPhone caches stuff on its own system
Well I asked thunk through dm maybe they’ll help us
Is thunk a dude
yeah
Ok
yeah if I can figure out where the saves ACTUALLY are, because that's not it
then we can go from there
Where did you put the saves into the official version @kindred knot
into the library folder
like the "1" folder
within library
as if it was the pc version
but it deletes the saves from there
There’s a library folder in the official ipa?
@kindred knot there’s a ton of save data stored in .plist files
Device identifiers and whatnot
no in the files when you backup the save through imazing
i don't think it holds any significance other than just being called jkr
as in it's not a file format that's just the extension
.jkr files are used only because they are called joker files
and i love that
it's just a deflate compression format
but the .jkr file extension meaning joker also took me a long time to get 🤣
me too
does anyone know how to change a joker's sprite and loc_txt when they arent unlocked?
and also a deck's loc_txt
some of themn aren't even compressed
like the version.jkr in the game directory
and demo unlocks used a list of keys
is there a way of reading a joker as it's being sold?
have peopel figrued out how to injkect save files into mobile yet?
if so I want to make a payload to collect some info if someone is down
No. It’s going to be hard. There’s a lot of data that the official app checks. We are going to have to load the app into Xcode and test it.
I call not doing it. Someone with more experience should.
If it's for joker calculation you can use context.selling_card (or whatever its name is) and check if the card's set is a Joker
ty ty
well good luck finding someione who owns balatero there
Pretty rare for people to have jailbroken devices in 2024 tbh
I have one but not balatro
I mean, the main reason I bought it was so that I could always have the latest version
I just asked the creator of the github conversion tool to come help us out
Where can I find xchips code
ligma code

Talisman
Thx
hi, does anyone know how shortcut works? i wanna make a similar card but cant seem to find the lines in source code specifiying how ti works
shortcut logic is included with the function that finds straights (get_straight)
you'd have to patch the relevant hand evaluation
im sorta new to modding on lua, so idk how to do that. im using the balaui.dev website to make my stuff, how does this translate into a variable?
oh uhh... the steammodded page doesnt really explain well then...
(https://discord.com/channels/1116389027176787968/1264841732730916974 or https://www.balaui.dev/ if anyone's interested)
basically you have to change the code for an existing function
for that you need to be able to write code and understand what existing code is doing
in other words it has nothing to do with steamodded
you misunderstood me, i mentioned steam modded since it has example jokers
which is where im trying to learn from since there isnt a guide
yeah i get you
I'm just saying steamodded guides don't cover it because it's just Balatro's source code
and i have access to the source stuff its just i cant find the thing im looking for
i looked through everything
like i said the function is called get_straight
yeah im looking through the code again
though for steamodded the vanilla function sees no use whatsoever because i fully rewrote it to support custom ranks
what im trying to do is basically a wraparound thing, so shortcut + it can go like 10 Q K 2 4 (if my math is correct)
yeah you'd have to think about what that's gonna mean for the algorithm for detecting straights. the way it works rn both in vanilla and steamodded would have a hard time accounting for wraparounds because it needs a rank to start searching on as well as a rank where it knows it's done searching
i just love when i spend an hour trying to figure out why sometihng isnt working, only to realise its because in one place i put . instead of : 😭
if you know what that means and can adapt the algorithm to support wraparounds, you can do that
it seems a slight bit challenging, ill try but lua might be harder then i thought
i do know that wraparound is a thing for normal straights but only for A 2 3 4 5
so i might need to find where that happens
when working with existing code, it's extra important to be able to figure out what it's doing
I'm all for helping people start modding, I do it all the time. But I never understand why people don't read the docs first. It's so much harder to help someone who doesn't understand the basic lua syntax etc.
if you understand the code at https://github.com/Steamopollys/Steamodded/blob/main/core/overrides.lua#L567, you might be able to do this
i do read the docs
as is the case with any programming language
I'm not specifically talking about you, I just mean in general.
consult https://www.lua.org/pil/contents.html for how lua works
thanks! very much appericated
back when i used to make discord bots, i was often helping people in the discord forums of d.js. the sheer amount of people that were trying to make full projects without learning the basics first was truly astonishing
btw @frosty dock, there's an issue with tooltip titles for booster packs
(seems like name_override fails because of _c.generate_ui in the if-else tower of generate_card_ui())
I do have a lovely fix but I feel like there should be a better way lol
yeah, I had pretty much the same experience haha.
hm
this is what I have but it kinda sucks
# generate_card_ui
[[patches]]
[patches.pattern]
target = "functions/common_events.lua"
pattern = """desc_nodes.name = localize{type = 'name_text', key = name_override or _c.key, set = name_override and 'Other' or _c.set}"""
position = 'before'
match_indent = true
payload = """name_override = name_override or (_c.set == 'Booster' and _c.key:find('_%d$')) and _c.key:gsub('_%d$', '') or nil"""
basically inserting a name_override by assuming that any Booster key ending with _[digit] should have that part removed
yeah that's not pretty
if anything this is an oversight and should be moved into _c.generate_ui
vanilla packs already get the right key in their loc_vars, apparently it was just never considered by me that names are put elsewhere for infoboxes
because generate_ui only ever considered putting the name as full_UI_table.name and not desc_nodes.name
so I'll need to add this to generate_ui functions and patch the condition in generate_card_ui so it doesn't override pre-existing desc_nodes.name
right
I think I get what you're talking about
let me know if you have something that works, I'd be interested in your implementation
probably not tonight, might go to sleep soon
I'll probably just push it to main steamodded once i have something that works
I asked you over github
Or the creator or whatever
Are you the creator ? I saw you say something about the creator in mentions so I added you
Dawg my GitHub has (sadly) literally never touched balatro
Nor is it named after my gamertag
I also don’t know what the conversion tool is
if you're talking about balatro-mobile-maker, I think it's @pliant sapphire or osmudge
Conversion of what
Ok thank you
wow thanks for that discord
Never mind dawg it’s all set I got extremely confused earlier by the context of the conversation I was hopped up on caffeine and took shots in the dark
You mentioned the creator of the conversion tool so I added you
The balatro port? I think I linked a balatro PC to something else port like a year ago, but I was told it was unofficial and technically piracy. So I deleted that message
But that was literally a year ago.
Oh lol
Yeah my last message in this server was 4 months ago
And I came here to ping you because it was our only server in common
Tragically I can’t help you. Good luck though
@pliant sapphire can you help us try to get our saves from sideloaded ipa into official app?
Try opening a github issue on the sideloader thing. And that's all I'll say on that because Ocean is right
I was warned not to mention it here. Sorry folks
Talking with various sources it seems it is not possible
Apologies for discussing a forbidden topic
im really annoyed because i cant get this joker to work. im trying to make it work like Turtle Bean (or other food jokers) where it goes away after a certain amount of rounds, but it just gives me errors.
it shouldnt even be triggering that part, but the game crashes when i end the round
just realized thats not even the part thats causing the bug, new screenshot is
you really should include more about the error in the screenshot
idk what else to include, but i fixed it
why dose this crash my game?
for me changing context.end_of_round to context.end_of_round and not (context.individual or context.repetition) worked
oh my gosh thank you so much!
i have no idea why it fixes the problem but i'm very pleased
now im having the same error but for some reason in a different spot!?
💀
can someone here help me figure out where i need to download from to get the SMODS.create_card{} function?
Eh Mods just tell me if this kind of thing is not allowed... But it may be possible to disassemble the Android APK, then reassemble it with the "debug" flag enabled-- Which would allow us to modify the contents of the save folder. I'll play around and let you all know if I come up with anything.
#📜・modding-rules "Only PC Modding discussion is permitted - discussion of modding Balatro on other platforms will not be tolerated." You are on thin ice discussing this.
Yeah apparently I was on thin ice when they put a strike on my YouTube channel for something that's completely legally protected. Whatever, sorry for helping people modify a game they own.
Try to take down my GitHub if you want 🤷♀️
As much as I don't agree with the rule, you're only gonna cause yourselves problems flouting it. Also they don't care about yoru github only what you talk about here
They cared about what I posted on my YouTube channel.
unfortunate if true
And those strikes never go away. So yeah, I'm a little salty.
they copyright struck you????
Worse, community guideline strike. Circumventing Technology Measures.
Or something along those lines, I forget the exact wording
sheeesh
um... did i ask this at a bad time...?
I was able to enable the debug flag for the Android app. That's what allows us to transfer files into the saves folder. Should have something together soon for transferring saves to Android.
As for iPhone users: I got no clue 🤷♀️
just use latest steamodded
tried downloading the main branch of steamodded, and it isn't there. do i go with "dev"?
is there a good mod i can look at for how to make a config?
config for a joker?
you can check out this one
my config is within the src folder
so is all of your config expect for the settings themselves handled within the config?
but... you don't have an smods config?
what
It doesn;t show up in the ui for me
you should convert it to an smods config though. If you'd be up to it
for a mod that actually uses the smods config, morefluff is an option
If your able to transfer saves, could you try putting this settings file in and showing me the results. https://cdn.discordapp.com/attachments/1288906099180699661/1288931143437123584/settings.jkr?ex=66f7a2eb&is=66f6516b&hm=a480b4968449f534bef129fcbf44bfcffa202cccfb834005820584bc12209b99&
i'm lost so i'm gonna go to sleep, and when i wake up it might be easier
thank you very much for showing me this mod :)
np :3 sleep well
is there a way to make a mod that contains a bunch of texture packs that can be toggled on and off at will?
actually ig texture packs dont make you restart do they
based on how poorly switching from 1x to 2x works without restarting they very much may, lol
I think it's the pixel art smoothing option, in any case that's what I meant that sscrews up without restart
i see
is there any document that has like, all of the stuff you can use while coding jokers?
Steamodded's github has a wiki section with a chapter about jokers
ty
i cant seem to find it, do you have a link to it?
ah ty
how do you check if a scoring card is an enhanced card?
like how theres context.other_card:is_face() to see if a scoring card is a face card, how can you see if its enhanced in general?
You have to check if the card.ability.effect is different from "Base"
what would that look like in code?
seems all good to go, just pushed it up to main
nvm
I’m currently trying to figure the best way of structuring them, but hopefully soon, yes
Seems like you pushed it to the index branch instead?
I swear this isn't the first time I messed these up 💀
How i can create a mod for change the text in game like joker names and descriptions?
it's on main now 💀
god lua is an ugly language sometimes
that's not lua
how is that a Lua thing lol
oh sorry
that's just balatro's text parser
It's just a placeholder
but wasn't sure
for formatting variable values into localization
All good haha, I'll take a look at how you did it
it is you're right
alternatives are like {} %%
idek how else you'd do it
yeah smth like that
[] is kinda what I think automatically when I think placeholder, but idk if it's reserved in the syntax for something specific
in lua strings % is reserved as an escape character
which is so confusing when you don't know it
though yeah it's a string so square brakets would be fine i guess
there is a example mod for this?
I keep trying to use \ instead lol
Yeah same
did you check example mods in steamodded?
Maybe there's misprint code
nvm
Am I missing something or couldn't you just change the localization?
cryptid has variable description for ERROR joker
It's in epicjokers file
hmm nevermind
Unless you want to dynamically change the text?
isn't that basically what Stupid said?
a variable as in a loc variable with #1#
Well it was Yamper's question, I'm not sure what exactly he's looking for
yeah I get'cha
the question was fairly ambiguous
sorry, im new on this code things
That's fine, we just need you to clarify what you're planning to do when you say "change the text"
or ones that you added
the last time i touch code was years ago for mod btd5 
wait huh
lua is a language alright
🗿
only in lua patterns though? it's still interpreted as a regular character in strings normally
I believe it's because Lua is pretty old and doesn't really adhere to some C-style conventions like most other languages do?
if 1993 is old for a programming language, sure
Pretty sure that's older than most people here 💀
but yeah there's not much C-style influence in its origin
Yeah exactly
probably why it feels... off to me when I've only coded in pyton and c++ (and only then in college classes years ago)
is lua procedural, oop, or functional?
technically it's multi-paradigm
aren't those more styles than inherent qualities of a language? at least somewhat?
thats not a term ive ever heard of
im not really sure, i know some programming languages have to be OOP or Functional
like haskell has to be functional
Some languages were really designed to be one of those styles
I wouldn't say it's inherently object-oriented because it doesn't really have classes, but there's implementations of OOP that support it
I'd say procedural, but also has hints of OOP (table-wise, and it's really weird ngl)
I'd agree it's more procedural/imperative than functional, though it could certainly be used that way
thats good news for me
i dont particularly enjoy oop
it doesntmesh with my brain well
both Balatro itself and steamodded do use an OOP-derived system to emulate classes, though it's actually just prototypes and metatables
gonna abuse typeclasses and do blocks to do entirely OOP haskell
still to this day i dont udnerstand what on earth a monad is
Haskell has to be functional because functional is actually a restriction, not a featureset
a container you can join together
it's functional for the purpose of being functional
or run a function through
it's a featureset when the compiler recognises the restriction
is that seriously all a monad is?
my lecturer spent 4 lectures trying to explain monads
and nobody got it
yeah a monad is anything that satisfies the contract (i.e. interface in OOP) of a monad
which is to have an empty value ('identity')
be joinable ('concat')
be mappable ('flatmap')
be wrap/unwrappable ('return', 'bind')
so... a container you can join together, like... a list
in fact, there is a concept called the 'free monad' which is the most general monad that all other monads can be considered a specialisation of
which is... the type List
so...
a monad is just a List type where some of the Lists are equal
university ('declarative programming' undergrad subject) + bartosz milewski's 'category theory for programmers' on youtube
fair enough
former for actually using haskell, latter for understanding the abstract significance
i learned most of my haskell from a phenomenal book
"learn you a haskell for great good" by Miran Lipovaca
e.g. the 'maybe' monad ('optional' in java) is a list where we only care about lists of 0 and 1 elements, i.e. we 'forget' about all of the additional elements so elements that differ in anything but the first element are considered equal
formally, that means there's a 'forgetful' functor from List to Maybe
this is the most understandings of monads ive ever had
which makes Maybe an instance of List in a way
that was reading/reference material for the declarative programming subject
trying to figure out Maybe when i was speedrunning learning haskell for my assessment made me cry
idk why maybe confused me
rightfully so
its phenomenal
btw some of these operations can be derived from one another, so there are different ways to specify a monad
the most common distinction is between choosing to specify the kleisli arrow (>=>) vs the bind operation (>>=) (AKA 'the fish')
i dont remember seeing or using those
we basically stopped after monads
the difference is the kelisli arrow is like function composition, keeping the monad 'lifted' whereas the bind operation puts a map 'under' the monad
bind takes a monad, applies a function to it, and gives you back a monad
you should change your username to magic monads
already taken
thats a shame
and then another option is like I said earlier to 'restrict' a List type down to what you actually wanted by defining equality on it
but this is wasteful cus when you're programming you want to 'construct' the object from minimal parts
one caveat, it's a container in the sense that it 'promises' to hold things, not that it necessarily currently does, like the IO and Reader monads don't exactly hold anything at the time, they build up (join/bind) to something that when the main function recieves gets passed input and passes output (the Writer monad 'holds' the value it's trying to write/consume, like when you partially apply a function)
with anything functional you gotta tack 'lazy evaluation' all over it
otherwise you can't have any control flow at all
the benefit is that if everything is functional, you can make every expression lazy
anyway back to balatro lua or whatever
that was a fun and informative side convo haha
update on infinifusion: rewrote it to use an recursive system, meaning the code is much cleaner and it can technically have infinite jokers within a fusion
also fixed the saved fusions breaking
What is infinifusion again
the quick proof of concept from yesterday
tl;dw: ability to fuse literally any jokers together
Does it include modded jokers too?
i need to write a bit for loc_vars to show the fused jokers as info_queues + add a way to naturally fuse jokers and then it'll be presentable as release
literally any jokers
oh that + visuals although idk what to do for them
i'm thinking of making a system like pokemon infinite fusion (where combos can have unique sprites) which would turn this into a fun community project but i think there should be a base system to show the fused jokers proceduraly
although im not sure how i'd even do that
the way infinifusion works is by temporarily changing into the jokers its made of to execute actions
i have a special function that automatically goes through the list of jokers in the fusion, turns infinifusion into that joker and then run whatever function i need, then turn back into infinifusion
so like calculate runs card:calculate_joker(context)
The only thing I would wanna see (if possible) is the ability to define custom images and/or localization for fusions but atm it's just proof of concept so that isn't like a necessity
custom images are definitely one of the things on the todo list because i definitely want it to follow pokemon infinite fusions in that regard
although unlike pokemon, mechanically infinifusion can be literally any set of jokers
so you could technically have all sinful jokers fused into a single joker
if you do that it would trigger once for every card, twice for every card with smeared and 4 times for wilds
what im thinking i could do for custom sprites/localizations is turn it into an api module where you basically define what the fusion is made of and what sprites/localization to use
I would love to help with a community pack for fusion art when it releases or start one
so you could do something like SMODS.Infinifusion { contents = {'j_joker', 'j_joker'}, atlas = 'doublejoker', loc_txt = { name = 'Double Joker' }
Has this been tested with econ Jokers yet? I know that's kinda weird to do for end of round calculations
i have not but what it would do if i did is run the econ separately
so the rocket + the rocket would end up with 2 lines of rocket money
everything infinifusion does is done through turning into the joker its made of
except for passive jokers like splash

I see
very modular I like it 👍
Lemme know if you like need a second playtester for it I'd love to try and test modded jokers out
i'll release it for testing when i add a natural way to fuse jokers (atm i just have it so you can spawn infinifusion and it comes prefused with 2 placeholder jokers) and the proper info_queue to track the jokers within the fusion (the hard part for this would be restoring vanilla jokers because they dont have a proper loc_vars)
bet
so how are you gonna handle splash?
not fusion art but could you make a sprite for a spectral that fuses the leftmost and the rightmost joker? name and icon can be anything you want
I could try
by hooking smods.find_card to append relevant fusions into the list
i also need to hook find joker too but yeah
what if the fusion art cut the jokers you fused down the middle and put the halves together
would be neat but would require me to figure it out
for now my plan is to just make it look like undiscovered joker
you could do it the "long way" by individually cutting every joker in half and putting them on sprite sheets
wouldn't really work for modded jokers
yeah
that seems a little
i don't know how to put it but
doesn't that invalidate the existance of joker slots
there'd be special rules for fusion I'd assume
if it just triggers both jokers separately and they take up 2 joker slots there's no point in fusing
but if they take up 1 joker slot there's no point not fusing
for now there's just a spectral that fuses two jokers but thats mostly for testing purposes
Now that balatro is on mobile are there any mods for it?
mobile modding has not been legalized unfortunately
Hope it gets legalized in the future
lmao saying it that way makes it sound like it's waiting for government approval
Well technically you can with bluestacks
@opal spade wip
main inspiration rn is a saw because I'm really getting like mycologist vibes from infinifusion rn and idk why
I have Lua moment question.
We have initial code which works:
for k, v in pairs(self.P_CARDS) do
-- stuff
end
BUT if I do:
local iterator = pairs(self.P_CARDS)
for k, v in iterator do
-- stuff
end
Game crashes with error
bad argument #1 to '(for generator)' (table expected, got nil)
Did I don't understand smth?
even if we were allowed to discuss it here, modding mobile games (esp in a way that supports our current mods) is far from trivial, so please understand that it hasn't been figured out in less than a day
I'm not experienced enough with Lua to be able to explain, but https://www.lua.org/pil/7.3.html seems like a good read about this
basically pairs returns more than one value, and for expects to be given all of them
when you assign to a local variable, the return value gets automatically adjusted to one value
the others get tossed
why are you trying to assign an iterator to a variable?
Because I need to use different iterator depends on boolean
local _iterator, _iterator_table = pairs(self.P_CARDS)
if args.challenge and args.challenge.deck and args.challenge.deck.cards and G.challenge_setup_use_override and G.challenge_setup_order == 2 then
_iterator = iterate_challenge_deck(args.challenge.deck.cards)
end
for k, v, _ch_card in _iterator, _iterator_table do
-- game setup stuff
end
just guessing here, but wouldn't
iterator = condition and self.P_CARDS or other_cards
for k, v in pairs(iterator) do
...
end
work?
No it isn't
local next = next
if args.challenge and args.challenge.deck and args.challenge.deck.cards and G.challenge_setup_use_override and G.challenge_setup_order == 2 then
next = iterate_challenge_deck(args.challenge.deck.cards)
end
for k, v, _ch_card in next, self.P_CARDS do
-- game setup stuff
end
assuming iterate_challenge_deck returns an iterator that behaves the correct way
Sure
function iterate_challenge_deck(t)
local index = 0
return function()
index = index + 1
if t[index] then
local _card = t[index]
local key = _card.s .. "_" .. _card.r
return key, G.P_CARDS[key], _card
end
return nil
end
end
should be fair game then
Now it works, finally
oh they are completely different types, I see
Yea, and I need include in iterator card crom challenge declaration, that's why I need custom iterator
local keep, _e, _d, _g = true, _ch_card and _ch_card.e or nil, _ch_card and _ch_card.d or nil, _ch_card and _ch_card.g or nil
unlocks and stuff
i got it to work
now i just need to finish writing the the function that gives loc_vars for vanilla jokers
does this just store jokers inside other jokers and calculate them
thats what i did when making Rescribere for cryptid
Me when I fuse Oops all six and Oops all one together 🧠
do i hear cryptid
i think that would disable both of them atm bcos i forgot to hook find_joker to account for fusions
I guess it's more complicated for joker effect that are done outside of calculation
this will be the better rescribere exotic 🔥
They use add to deck and remove from deck
What about jokers like Splash, Shortcut or Four Fingers?
are there any cases of find_joker being used in vanilla code that aren't patched by steamodded?
if so they should be replaced
Yea you could use find_card
this one in state_events comes to mind
Is this from source or lovely dump?
currently if the effect is find_card then it works, if it's find_joker it doesnt
lovely dump
Ah ok
its funny how the example joker i wrote in the comment to the hook for find card is like the one joker that doesnt use find card
didnt notice this but basically yeah
Wait should I not be using find_joker in my mod?
you should be using SMODS.find_card
FUCK
i just accidentally deleted all the art for all of my jokers
luckily there only was like ten but still
o7
everything's working
except for sixth sense's card destruction apparently???
hmmm
strange
everything is working but there are some strange interactions
awesome
sadly this deck wont unlock and i dunno why
i assume seeded runs don't check for unlocks
maybe something related with how seeded runs don't unlock stu-- yea what they said
Oh that’s probably the case, yeah
i just used everything in unlock_card function except the part that returns if its seeded
ah
@crisp elbow infinite fusion available for testing
ITS DONE
And another one!
i completely forgot that the C key with debugplus also counts as copying 💀
why specify that it won't persist if effects don't persist by default
People are already doing it though 👀
with the mobile maker tool it's possible to use modified files as a starting point for compilation, but lovely itself hasn't been figured out
it's possible to use save files as an entry point, iirc this has even been used to inject steamodded 0.9.8
it's worth a try but most mods will at least require a manual process to work without directly using lovely
How I can define multiple settings tabs for mod?
like a branching settings tab with different sections with their own pages?
If so Ceres does that
define SMODS.current_mod.extra_tabs and return a table of tabs, or the above for multiple tabs inside your tab
each tab should have a label string and a tab_definition_function that corresponds directly to a possible config_tab function

Good reason to use github from the beginning
new to this whole lua stuff, trying to make a joker that copies the first scoring cards enhancement and then applies it to all other scoring cards, seems to crash at the local enhancement line though
anyone got any help?
yeah that's not valid lua syntax
don't have local within a table
not exactly sure what you're trying to achieve, but for a start you can't have local inside a table constructor
second you're trying to use that variable somewhere completely different
so even if it would be valid to declare there, it would be out of scope
so because its not being used in the place where its defined, it doesnt mean anything?
I suggest you give this a read: https://www.lua.org/pil/contents.html
alright
anyone know how to draw a UI element beneath something? Like the UI buy buttons?
in terms of calculation, I'd argue you're not using the right contexts and this should remotely work in a similar manner to midas mask
I'm definitely fine when w and minw does not work at all. I'm definitely fine 
i was able to figure out how to make an effect activate when a card is enhanced, but making it so it copies to the rest of them is whats tripping me up
this might help?
#💻・modding-dev message
for your consideration. try to read your way through this and understand what it's doing
calculate = function(self, card, context)
if context.cardarea == G.jokers and context.before and not context.blueprint then -- activates before the main scoring phase, so the enhancements actually apply
local first_card = context.scoring_hand[1]
if first_card.ability.effect ~= 'Base' then -- first scoring card has an enhancement
for _, _card in ipairs(context.scoring_hand) do -- iterate over each card in scoring hand
local center = first_card.config.center -- this has info on the card's enhancement
_card:set_ability(center, nil, true) -- apply that enhancement to current card
-- optionally add the below to make the cards wiggle
G.E_MANAGER:add_event(Event({
func = function()
_card:juice_up()
return true
end
}))
end
return { -- display a message
message = 'Enhanced!',
colour = G.C.MONEY, -- replace me
card = card
}
end
end
end
oooo ty
@frosty dock do you happen to know?
I looked through it, but it doesn't seem to be what i'm looking for, thanks tho :D
oh wait
i remember how to do it
I don't recall having looked into that, or I just can't remember, idk
it's nearing 2am so my time is probably better spent just going to sleep at this point
how do you get the last card in the scoring hand? i know context.scoring_hand[1] gets you the first, but how do you get the last? (i doubt just putting 5 would work, as then it would only work for 5 length hands)
# before a list will give the length of the list
so you use context.scoring_hand[#context.scoring_hand]
ty
welp this is breaking again
im so confused at whats wrong
Maybe you didn't exclude context.repetition?
G.GAME.current_round.free_rerolls = G.GAME.current_round.free_rerolls + card.ability.extra.rerolls
calculate_reroll_cost(true)
card.ability.extra.rerolls = card.ability.extra.rerolls - 1
card_eval_status_text(card, 'extra', nil, nil, nil, {message = '-1 Reroll', colour = G.C.GREEN})
end
if card.ability.extra.rerolls == 0 then
G.E_MANAGER:add_event(Event({
func = function()
play_sound('tarot1')
self.T.r = -0.2
self:juice_up(0.3, 0.4)
self.states.drag.is = true
self.children.center.pinch.x = true
G.E_MANAGER:add_event(Event({trigger = 'after', delay = 0.3, blockable = false,
func = function()
G.jokers:remove_card(self)
self:remove()
self = nil
return true; end}))
return true
end
}))
return {
message = localize('k_melted_ex'),
colour = G.C.CHIPS
}
end```
is the code for the calculation
2nd block would run regardless of context which includes context.repetition.
Should be if context.after and card.ability.extra.rerolls == 0
Assuming this is after scoring
If it's meant to be within the top block then the issue is it's not included
well the 2nd block would only run if rerolls is 0, which would happen only if it had just gotten -1 which can only happen right after the block above it
damn i just tested
i really dont understand why that works but ok
but it doesn't adjust .rerolls so it will activate again next time the func is called
oh but the joker didnt delete itself
That means that this block isn't even running
Cause all these uses of self would crash
should i change them to card?
yea
it works tysm
In theory, how would you make a joker that allows for straight looping ( As in, making 3 2 A K Q a valid straight and everything to that nature )
Pretty sure #1276085451530174484 makes shortcut do that
goddamnit i cant find out how to save something in G.GAME
wouldn't it be just G.GAME[] =
so uh... do we have to use multi-joker sprite sheets again? or is there a way to make per-joker SMODS.Sprite coding work with SMODS.Atlas coding?
you can definitely use individual sprites, many mods do
(and I do mean on 1.0)
ye, been trying to update my code to the latest version
i see... but i'm actually talking about declaring the atlases themselves...
do i need to do that anymore?
oh lemme look
wait a minute... how did i fuck up the debug server--
ugh... guess i have to just...
change my mods folder to "Mods_Defunct" and start from scratch until i figure this shit out
ignore
well, i can't ignore it because it seems to suppress my ability to send debug messages
so i guess i just send info messages for now instead?
Did you change the in-game configs?
Print levels are set in-game… for some reason
Also as they said, you can set up individual sprites by pretty much just changing the object name to Atlas (well there might be some slight tweaks but still)
how tf do people shade shit????
whenever i see Unjust Dagger's sprite i am just
amazed
i mean like HOW??
I think in some cases they may draw it at a normal art resolution and then trace it with pixel art
but I'm just guessing
I can't either, so nw
and your jokers look fine, not many base balatro jokers are that fancy
almost all of my joker art is just a copy and paste of an image scaled down
or just a placeholder
ubiquity is literally just a filter i accidentally used
well it probably says something that I didn't really notice, lol
I’d like to know too
I’ve gotten some advice before
IIRC balatro usually uses two highlight colors and a shading color
thus is the creative process tbh
smeared joker typa shit
I try to pick colors from existing Jokers so I don’t follow that particular guideline
Also, things facing the light source are brighter, while facing away are darker. In the middle, there’s a region that can be grey or it can have a stark shift from light to dark depending on the geometry
There’s also reflected ambient lighting you can include
And you can do dithering to keep the number of colors low
These two messages are such a mood lol
@nocturne garnet maybe later I can share some in-progress pics of Brazilian Miku since I asked actual artists for help. I was struggling but in the end I quite like how some elements like the hair turned out
I might also have some WIPs of a different Joker, though that one was more closely traced from a music video
Tangentially, the great thing about playing with so many modded jokers is that any onconsistency just wraps around to everything going together again
Just say it’s a special edition artwork like MTG or it’s a kitchen sink setting like YGO
that's why as long as there is some form of identity to jokers, in any form tbh the specific quality/nature art doesn't matter too much for player experience

People actually liked my placeholder artworks for my first mod
I should release that mod lol
Here’s an example of the placeholder artworks
Those are at least drawings and not text
this is peak
tbh if I ever make a mod the artwork will probably just be me cutting up peices of vanillia jokers and arranging them/changing colors/filters as I see fit
oooh I like too
The Dragon is where I got that shading advice for
The messages were in a thread but here’s how far I got with the artwork #🎨・fan-art message
Ah, I found the advice #1229122387308707930 message
the way i draw jokers is by making/finding an hd image to use as a reference, layering it over the pixel canvas, tracing it and then touching it up look better
Is there any mod with runes (like from Isaac)?
someone was working on one, but i don't think it went anywhere
That’s my process for Jokers that are explicitly references
guys should i reroll
for me thats general process because if its something original i can sketch it
btw, if i were to want to add a custom modifier, how would i do it?
I’m not a good artist so :<
Maybe check Myst’s mod
dw about it, you'll get better after enough effort
do yall know how to get the current blind name
Yes
I can’t check right now but the Steamodded wiki explains how to write Custom Blinds. This is only relevant because they explain how to access the current Blind there
The current blind can provide you a key which you can use to access the Blind pool to retrieve all of the Blind’s data
Or if you’re currently in a Blind you can probably try to access it there
It depends on the timing
there's one good hack i found for making decent shading look better than it actually is.
you do something that makes sense lighting-wise...
then... gaussian blur.
eh
I think the original looks good, and the handle needs more shading to match the blade
Also the bottom ring maybe could use some
i love blurry shading but it doesn't look good in pixelart unless its subtle
I don’t think this particularly should have noise
I’d expect the blade to be smooth not blunt
iunno, i was just giving @nocturne garnet some pointers with their idea
forgot to reply to em
Yeah I’m not saying these are bad suggestions
I’m just talking about this specific artwork
tbh this doesn't look bad
yeah, that's fair. i do think i see what y'all mean about it looking blunt
i think i solved that with a very slight tweak.
I think the brown lines in the middle are a bit stark and out of place
they're just supposed to show the shape of it right?
not sure they should have any hue to to them if so
unless i'm parsing it wrong
yeah, i think making them a color more in line with the rest of it works
slimmed the top of it down just a tad to make it feel a little more sharp
Next shade the handle ;P
ah, yeah it was just for it to be easier for me
for some reason, G.GAME.no_shop is string???
it keeps crashing
and saying no_shop is string
way ahead of you.
I think it would look better with fewer colors
something like this, maybe?
if no_shop is a string, why are you trying to assign a key-value to it like it's a table?
its not supposed to be a string 😭
the modifier should be a table
nvm i think one of my mods also has a No Shop modifier
That’s why you always name things like
yeah
key_name
changed it to jimb_no_shops
wait i mean
shiit
cant find a way to get the blind type when cashing out
what type
like Small, Big, Boss
Do you want the name or the type
type
The types are Boss or not
Anyways, I imagine the current blind doesn’t exist during cashing out, so you need to retrieve it earlier
Unless it’s a Joker, then you can try to do it on the Rocket timing
If it’s a Joker but with a different timing, just have it save the current blind info earlier
Preferably as late as possible IMO
pretty sure you can do G.GAME.blind:get_type()
But I think at that timing the Blind wouldn’t be the same anymore
but assuming that you just completed a blind, wouldn't the fix be as simple as shifting the type back a round?
so "Small -> Boss, Big -> Small, Boss -> Big"
its before the cashout function 😔
it doesnt work for me
wouldn't work if the order is changed
what does it print?
try last_blind
Mods
still wont work 😔
you did G.GAME.last_blind right?
yea
are you sure it's running?
last blind should always have something in it
more like my game crashes if I try to get the blind type during cash out
its running, dont know why it wont work
I think G.FUNCS.cash_out is just too late?


