#💻・modding-dev
1 messages · Page 113 of 1
oops, I forgot to change something in there, should be G.TILESIZE instead of self.TILESIZE
upd
why the fuck is this cryptid joker triggering twice
I've got a hole in my code somewhere that's annoying me
anyone more experienced willing to take a look?
i've tried to move the description of a joker or consumeable around and the values get updated but the UIBox stays in the same place.
Code:
SMODS.Keybind {
key_pressed = "up",
action = function(self)
hover_popup, hovered_card = nil, nil
for _, v in ipairs(G.jokers.cards) do
if v.config.h_popup then
hovered_card = v
hover_popup = v.config.h_popup
hovered_card.config.h_popup_config.offset.y = hovered_card.config.h_popup_config.offset.y + 1
end
end
if not hovered_card then
for _, v in ipairs(G.consumeables.cards) do
if v.config.h_popup then
hovered_card = v
hover_popup = v.config.h_popup
hovered_card.config.h_popup_config.offset.y = hovered_card.config.h_popup_config.offset.y + 1
end
end
end
if hovered_card and hover_popup then sendInfoMessage(hovered_card.config.h_popup_config.offset.y) end
end
}```
the minecraft suit...
very
where does Steamodded handle negative playing cards?
oh its fucking
commented
okay my implementation for enchanted cards is immensely flawed
tried installing cryptid and talisman i keep getting this error
`Error
Syntax error: game.lua:4: '=' expected near 'Game'
Traceback
[love "callbacks.lua"]:228: in function 'handler'
[C]: at 0x7ffa8d2b2fa0
[C]: in function 'require'
main.lua:16: in main chunk
[C]: in function 'require'
[C]: in function 'xpcall'
[C]: in function 'xpcall'`
it verified fine, it can run other mods, but not these two, and i tried the troubleshooting steps on the cryptid github, it didnt work
delete Balatro.exe and verify again
@wintry solar what do you think of this?
At which point steamodded's localization files are being copied to the global table?
I can't access them from process_loc_text for some reason, but really want to
sounds interesting but could see it leading to an infinite loop
not sure how that'd happen if levels have to be strictly decreasing
should happen right before mod-level process_loc_text
aka after language injection
I don't know what I'm doing wrong then
oh sorry I thought you literally meant steamodded's own loc files
I have used other text entries from the same point in the dictionary, but after the game is loaded
and it worked fine
loc files from mods are used later
so would retriggering how it works now be level 1, and retriggering retriggers be level 2, say?
blinds support loc_vars, so you don't need this
collection_loc_vars exists
I'd prefer the default to be 0, but yeah, basically that
it would also allow having your retriggers be retriggered by standard retriggers, as in level -1
vscode are you drunk
it do that sometimes
so wouldn't two copies of a joker that retriggers all others at level 2 just infinitely retrigger?
inside a retrigger at level 2, further retriggers happen only if they're less than level 2, and retrigger checks don't retrigger
so one such joker might retrigger other effects of the other, but not the retriggering
same how retriggering a joker trying to retrigger at level 2, at level 1 wouldn't cause any additional retriggers
🤔
how do you get the id from a joker (like the one used in an add_joker call)?
I've managed to get the name from a joker, which doesn't really help but is still useful
-
joker 1 retriggers all jokers once at level 2
-
joker 2 retriggers all jokers once at level 1
-
joker 3 retriggers all jokers once at level 0
-
joker 4 just exists
-
when joker 4 triggers, it gets one retrigger from all 3 other jokers at the respective level
-
joker 3's retrigger is level 0 and no retrigger checks have a lower level, so this causes no further retriggers
-
joker 2's retrigger is level 1, triggering joker 3's retrigger again because it's less in level, this is 2 more retriggers
-
joker 1's retrigger similarly retriggers both joker 2's and joker 3's retrigger, with joker 2 subsequently retriggering joker 3 once more. this is 4 more retriggers
so joker 4 gets 7 retriggers in this case
card.config.center_key
big
An additional copy of joker 1 would get the same 4 retriggers
do you get what I mean now?
yeah that makes sense
I just need to unscuff what I currently have before thinking about implementing it 🤣
fair enough haha
i'd love to see what it's up to though, no updates to the branch in 2 days
jolly
Jolly!
I've made three jokers now:
Flat Circle (left): gives a X2 mult if the hand played just after obtaining this card is played again
True Minima (middle): makes the card on the right of it negative and self destructs
Safeguard (right [art is a draft]): When blind is picked, stores the card on its right, destroys it, and at the end of the round (if it has room) returns it, but without any edition it had.
I'm probably gonna shoot for five of these total
m
im coding the first joker of my mod, Joker Lottery
it destroys the joker to the left of it and creates a random joker of the same rarity
i would like to know how to destroy a joker
or if theres some documentation that shows things for destroying and creating stuff
Jolly time of the year
to delete a card you can use card:start_dissolve()
this goes for jokers as well
you add a joker using add_joker([id]), with the [id] being the identifier of the joker (e.x.'j_mr_bones' for Mr. Bones)
whoops hit enter too early lmao
gimme a sec
thx
I have a bit of code I could share from one of my jokers
SMODS.Joker({
key = "Safeguard",
config = {
extra = {
Xmult = 2,
card_name = "None"
},
},
loc_txt = {
name = "Safeguard",
text = {
"When Blind is picked,",
"destroys the card on",
"the right and",
"remakes it without its edition",
"at the end of the round,",
"or when it has space.",
"(Currently stored: {C:attention}#1#{})"
-- C:attention gives the text a yellow colour
-- C:mult/C:chips colours the text to the colour of mult or chips
},
},
rarity = 3,
loc_vars = function(self, info_queue, center)
return { vars = { center.ability.extra.card_name } }
end,
calculate = function(self, card, context)
if context.setting_blind then
local right_card = nil
for i = 1, #G.jokers.cards do
if G.jokers.cards[i] == card then
right_card = G.jokers.cards[i+1]
print(right_card)
end
end
if right_card == nil then
return false
end
if not G.GAME.SafeguardCard then
G.GAME.SafeguardCard = right_card.config.center_key
card.ability.extra.card_name = right_card.ability.name
right_card:start_dissolve()
end
end
if context.end_of_round then
if #G.jokers.cards == 5 or not G.GAME.SafeguardCard then
return false
end
add_joker(G.GAME.SafeguardCard)
G.GAME.SafeguardCard = nil
card:start_dissolve()
end
end,
atlas = "Safeguard",
pos = { x = 0, y = 0 },
})```
well hold on
oh thx, it also shows directional stuff, ill need that for my joker
thx for the help!
honestly i could see smth
like if you have pareidolia and the boss blind is that one where it debuffs face cards
have you tried the jolly Holiday Pack
then you just safegaurd pareidolia until the boss blind is over
nothing compared to my whimsy
oh wait that's huge
lemme test it
yea
based on when i lost a run bc i was using a pareidolia build and got that exact blind 💀
me too
and that build was so op
it was a good run but that boss blind just ruined it 💀
how do i properly check if a card is unlocked/discovered?
what does this mean btw
loc_vars = function(self, info_queue, center)
return { vars = { center.ability.extra.card_name } }
end,
if you have parts of the card that has text that changes (in this case, it's the name of the held card)
you return it in that function and reference it in the text
ah ok
so i dont need to worry about that for this joker
technically, for the whole minima set it was supposed to be memory-based
so I'm going to take it out eventually
I just wanted the practice
I'm kinda stuck on thinking of two other mechanics, though
what's the middle?
it's a card that makes the joker on the right negative and then self-destructs
"you are negative now" explodes
yeah pretty much
also that lock I drew is going to haunt me forever
this is why I don't do art 💀
meh i wouldnt be able to draw a good lock either
but since all of the cards are supposed to be minimal i should probably change it anyway
maybe trace the base game's lock
it coul still be a lock
true
I'm just changing it to that temporarily
mainly so I can focus on other things
if you want i coul try braw one in the style you have
download icon fr
that would be huge
pushed now, still missing post triggers 😄
yeah I tried my hand at that too
I made a series of "wall" hands that were five enhanced cards
so stone -> stone wall
gold -> versailles gate
etc.
is that pun intentional
pun intended?
LOL
can you try put this on the bg; i brew it quickly so sorry if itl ooks awful
just i wanna sese how it looks
thats ngl good
imo
I'll try it out
Hopefully it’s not scuffed 🤞
i need to try and look at riff raffs code to figure out this rarity random thing
is this the 1x or 2x sprite
because the lock i provibeb was for 1x sprites
idrk how tho
oh shit then its too big
gimmie a sec to ownsize it on the 1x
well I put it on the 2x first
and then scaled the card down
yeah I made it better lmao
thats good
yup
I might be going insane but I have no idea why this doesnt work
I tried replacing hover_popup:recalculate() with v.config.h_popup:recalculate() but it gave me the same error
nice
coming from other languages to Lua
it's definitely
something
I don't think I'll ever get over ~=
if context.setting_blind then
local left_card = nil
for i = 1, #G.jokers.cards do
left_card = G.jokers.cards[i-1]
end
end
if left_card == nil then
return false
else
left_card:start_dissolve()
SMODS.create_card({
set = 'Joker',
area = G.jokers,
rarity = left_card.rarity
})
end
end```
i think this should work
now im wondering how i test it because like
how do i create that joker in game without having to go by luck
in the for loop, you have to make sure to check which card is the card this is played from
that's why the if G.jokers.cards[i] == card then was in Safeguard
so it actually looks for the joker on the left of this joker
thx
in your loop it would always pick the next-to-last joker, I believe
do you have the debug tools mod
thats cool
yup
there are a bunch of useful tools
you can add/change enchancements, win blinds, up antes, etc.
btw do i do that whilst in a run?
yeah
it exists
did nothing to greedy joker when i did my turn
sads
ok so i added some debugging and ig it just isnt recognising the greedy joker that is RIGHT THERE
does anyone know where these functions are defined? cant find it anywhere in my decomp
i wanna do something similar to mail in rebate but i dont know how the game does it for that card and id rather retrofit that method while not relying on it outright than try and hack something shoddy together myself
heres my joker code
SMODS.Joker {
key = 'jolot',
loc_txt = {
name = 'Joker Lottery',
text = {
"Destroy joker to left of this card,",
"create a random joker of the same rarity"
}
},
rarity = 3,
atlas = 'atlas',
pos = {x = 0, y = 0},
cost = 2,
calculate = function(self, card, context)
if context.setting_blind then
local left_card = nil
for i = 1, #G.jokers.cards do
if G.jokers.cards[i] == card then
left_card = G.jokers.cards[i-1]
end
end
end
if left_card == nil then
return false
else
left_card:start_dissolve()
SMODS.create_card({
set = 'Joker',
area = G.jokers,
rarity = left_card.rarity
})
end
end
}
did you select a blind and it didn't work? that's what your code is supposed to do, from what I see
well i mean id like it to do that every hand (then why in the world did i use the blind thing my dumbass)
yeah
i mean every hand
change context.setting_blind to context.joker_main
ok
it'll run after you play each hand
though it also didnt do anything when selecting a blind either
ok i changed it
and it still aint do anything 💀
i swear this is probably one of those painfully simple things that i never notice
sorry to interrupt but quick question, just started messing around with this - when calculating joker bonus after playing a hand, is there a way to get the amount of chips that the player has scored?
as in the blue number, no mult
hand_chips and mult are currently scored chips and mult respectively.
Maybe you'd want to store information in the Joker itself? left_card will usually be nil anyway.
but the joker itself is a table meant for like args and stuff if thats what you mean
and why is left_card usually nil? ig thats whats happening
Each time you run the function, left_card doesn't exist until it is technically defined when you set it to the Joker.
Your left card check isn’t in any context so it will always run, but your value is local to the setting blind context so will always be nil in others
You don’t actually do anything when you’ve identified a left card
oh yea i changed the context to joker main recently
hm
so it needs to be in a context? its in joker_main context right? jeez this is confusing
Add config = { extra = { storedrarity = 0 } }, then store the card's rarity in card.ability.extra.storedrarity. When you recreate the card, call SMODS.create_card and pass the card.ability.extra.storedrarity to the rarity argument... then you can reset it to 0 or nil.
SMODS.Joker {
key = 'jolot',
loc_txt = {
name = 'Joker Lottery',
text = {
"Destroy joker to left of this card,",
"create a random joker of the same rarity"
}
},
rarity = 3,
atlas = 'atlas',
pos = {x = 0, y = 0},
cost = 2,
config = { extra = { storedrarity = 0 } },
calculate = function(self, card, context)
local left_card = nil
if context.joker_main then
for i = 1, #G.jokers.cards do
if G.jokers.cards[i] == card then
left_card = G.jokers.cards[i-1]
card.ability.extra.storedrarity = left_card.rarity
end
end
end
if left_card == nil then
print("left card is nil")
return false
else
left_card:start_dissolve()
SMODS.create_card({
set = 'Joker',
area = G.jokers,
rarity = card.ability.extra.storedrarity
})
card.ability.extra.storedrarity = 0
end
end
}```
soo.. is this what you mean?
Remove left_card entirely and replace checks of it against card.ability.extra.storedrarity.
calculate = function(self, card, context, effect)
if context.cardarea == G.hand then
if card.facing == 'front' then
card:flip()
end
end
if context.cardarea == G.play and not context.repetition then
effect.x_mult = 3
if card.facing == 'back' then
card:flip()
end
card_eval_status_text(card, 'extra', nil, nil, nil, {
message = "Unblinded!",
sound = "fm_blind",
colour = G.C.MULT
})
end
end
I'm trying to make my enhancement card drawn with face side down, but it still gets drawn face side up, anything I'm missing?
It should be in set ability iirc
Set ability?
It’s a function you can define on an object
I'll look into it, is there an example code or something on it?
Should be in the wiki
Been working on stuff
imma wipe it clean and try to remake it to see if i make some breakthrough that solves the problem
does anyone know how to make a joker prevent death like our goat Mr. Bones?
There’s a context that you return true in
Can't seem to find it, not in Joker Calculation nor SMODS.Enhancement
It’s in Center
Found it, cheers
key = 'jolot',
loc_txt = {
name = 'Joker Lottery',
text = {
"Destroy joker to left of this card,",
"create a random joker of the same rarity"
}
},
rarity = 3,
atlas = 'atlas',
pos = {x = 0, y = 0},
cost = 2,
config = { extra = { leftc = nil } },
calculate = function(self, card, context)
if context.joker_main then
for i = 2, #G.joker.cards do
if G.jokers.cards[i] == card then
card.ability.extra.leftc = G.jokers.cards[i-1]
end
end
end
if not card.ability.extra.leftc then
return false
else
card.ability.extra.leftc:start_dissolve()
SMODS.create_card({
set = 'Joker',
area = G.jokers,
rarity = card.ability.extra.leftc.rarity
})
end
end
}```
made this
basically just a worse version of the old code
crashes it when starting a run so lol
so how the heck does smods.sound work?
SMODS.Sound({
key = "Goku",
path = "Goku.ogg",
})
yet it's saying it doesn't exist
When using it you need to add a prefix (not in SMODS.Sound, but in the place you want the sound the play)
For example if your prefix is xmpl, then to call it, you need to type xmpl_Goku
oh okay
Didn't think it included sounds before too
tbf, first time playing with sounds
Here's my implementation of playing a custom sound for an Enhancement:
--- PREFIX: fm
----------------------------------------------
------------MOD CODE -------------------------
...(before defining all the SMODS objects)
SMODS.Sound({ vol = 0.6, key = "amplified", path = "amplified.wav" })
... (inside an SMODS.Enhancement implementation)
card_eval_status_text(card, 'extra', nil, nil, nil, {
message = "Amplified!",
sound = "fm_amplified",
colour = G.C.MULT
})
...
i almost just fell asleep
I still don't really have much of an idea on how to use set_ability, and inside card.lua there's nothing related to flips inside it
set_ability = function(self, card, initial)
if initial then
card.facing = 'back'
end
end,
calculate = function(self, card, context, effect)
if context.cardarea == G.play and not context.repetition then
effect.x_mult = 3
if card.facing == 'back' then
card:flip()
end
card_eval_status_text(card, 'extra', nil, nil, nil, {
message = "Unblinded!",
sound = "fm_blind",
colour = G.C.MULT
})
end
end
I don’t remember right now but try taking a look at blinds that flip cards
I did, it's how I managed to find card:flip() in the first place, the problem is making the card stay face down when drawn
function Blind:disable()
self.disabled = true
for k, v in ipairs(G.jokers.cards) do
if v.facing == 'back' then v:flip() end
end
if self.name == 'The Water' then
ease_discard(self.discards_sub)
end
if self.name == 'The Wheel' or self.name == 'The House' or self.name == 'The Mark' or self.name == 'The Fish' then
for i = 1, #G.hand.cards do
if G.hand.cards[i].facing == 'back' then
G.hand.cards[i]:flip()
end
end
for k, v in pairs(G.playing_cards) do
v.ability.wheel_flipped = nil
end
end
function Blind:stay_flipped(area, card)
if not self.disabled then
if area == G.hand then
if self.name == 'The Wheel' and pseudorandom(pseudoseed('wheel')) < G.GAME.probabilities.normal/7 then
return true
end
These are what I could find
Is there a context for when the card is created? Like either by card effect or appears in the shop/pack/etc
No
Try setting card.ability.wheel_flipped to true
I don’t remember if there’s a way to flip cards other than from a blind so it might need some patches
There's card:flip(), like I said, it can actually flip cards without blinds, just apparently not correctly when drawn from the deck
Yeah I think they’ll just flip back though
Yeah my first ever iteration is that the card came out face up, but when played it flipped face down
just created a mod but it doesn't appear on the modlist, did i maybe mess up the metadata?
{
"id": "L6_luckyjimbo",
"name": "Lucky Jimbo",
"author": ["LuckySix"],
"description": "My first mod, so it sucks a bit.",
"prefix": "L6jimbo",
"main_file": "luckyjimbo.lua",
"priority": -20, // [default: 0] ! Mods are loaded in order from lowest to highest priority value.
"badge_colour": "C958D1",
"display_name": "Lucky",
"version": "0.1.0~PREALPHA1",
"dependencies": [
"Steamodded (>=1.0.0~ALPHA-1225a)"
],
}
Agony
Pretty sure the json parser that steamodded uses will break on that comment
(json doesn't support comments)
oops, i forgot that was there, got rid of it and i t works thanks!!
so what would be the most efficient way to test a specific card in game?
this looks kinda trash LOL
made another joker
(far right)
it saves from death, but destroys all other jokers and makes itself polychrome
Is that delirium completion mark
I'm not sure what you're referring to
Its an isaac reference
Dont play it
You wont escape
The only reason why my mod is taking so much time to code is that game
btw does anyone know how to change the "saved by mr bones" text to say something else
relatable 😭
Yeah I am extremely lost on making a patch, is there any documentation on Lovely patches or someone that can help
😨
datamoshed jimbo
does anyone know how to change the ante?
*with a joker, not with the debug menu lol
ease_ante
big
changed the mechanic
Ayo sorry to bother, been looking through chat histories to see if anyone figured out how to draw cards from the deck face down
Did you manage to do it? If so, how did you do it? Been trying to do something similar for a while now, ping me when you're able
I remember having a functional implementation although I haven’t touched it in a while
What do you want to do exactly?
I'm making a custom enhancement, the card is drawn face-down, but if you somehow score it, you get a nice xmult
That's like my one joker but a bit harsher and more useful
If you uploaded the mod somewhere like GitHub, I can go take a look if you'd allow me
I haven’t uploaded it yet :<
Aw
Hmmm
I have a similar effect where it was a Blind that causes some Suits to be drawn flipped
So maybe a hook would be sufficient to replicate it
I am currently fiddling with card:flip(), but the card just won't get drawn face down in non-Boss-Blind situations
Damn I've never coded a hook before
Ah that’s true maybe it wouldn’t be called outside of Boss Blinds
Maybe it would need to be a patch
I also have zero experience making patches
Try hooking Blind:stay_flipped
That's a Blind function so I never really considered it to use with my Enhancement, is this where a hook/patch comes in?
Oh wait I didn't see "hooking"
help, how do I iterate and compare through all the cards in the deck (+ held in hand if possible)?
Yeah I'm gonna be struggling figuring out how to hook
Yes the idea is that the effect would be applied outside of the object
Although
Now that I think about it I remember also having a method to force cards to look face-down
Do you have it? Can I shamelessly copy it
Do you want them to be drawn face-down outside of Blinds?
Like getting them in Booster Packs or Shops or something?
Yes
Yeah sure why not, adds to the challenge
help, i stoopid
compare what
For each card, for example, compare and test if it is for example, a sevel of any given suit.
I would be looking for an enhancement, but that is just an example.
-# wait, let me check steel joker for a sec...
actually, this will do
The good news: I think I found the piece of code that makes it work. The bad news: No idea how it works, exactly.
So uh... help?
mainly the for loop because I stupid af and never got around to understanding it
interesting
what does yours do?
This is the line I think you should look at
local stay_flipped = G.GAME and G.GAME.blind and G.GAME.blind:stay_flipped(self, card)
Does it work anywhere and not just SMODS.Blind?
I think the best solution would be to patch after, and then do something like stay_flipped = stay_flipped or is_jitJets_enhancement(card)
What field will the stay_flipped line be in? pattern or payload?
And I assume target would be the Lua file where Blind:stay_flipped be? I'm not at my computer rn so I forgot
The patch would look something like this, although you either define the function inside the patch or just check directly for the enhancement. something like card.center.ability == jitJets_enhancement; I don't remember where in the center the identity is stored
[manifest]
version = "1.0.0"
dump_lua = true
priority = 0
# Flipping Enhancement
[[patches]]
[patches.pattern]
target = "cardarea.lua"
pattern = "local stay_flipped = G.GAME and G.GAME.blind and G.GAME.blind:stay_flipped(self, card)"
position = "after"
payload = '''
stay_flipped = stay_flipped or is_jitJets_enhancement(card)
'''
match_indent = true
Oops I think I forgot to change the target
It iterates over every card in the full deck, and whenever it finds a Stone Card, it increases a counter by 1
Also @merry raven that shows how to check for an Enhancement, I suppose
Yeah there's only one enhancement that does it, its key is blinded
So I could something like card.center.ability == "m_fm_blinded"? Wouldn't it, idk, break since im basically calling an enhancement inside its definition?
card.config.center == G.P_CENTERS.m_MODKEY_blinded
Ah gotcha
I'll see what I can do tomorrow, it's getting late
Thanks for taking the time to help!
I was thinking in term of effects like Smeared
If you have a function that computes even a simple comparison like this, it's easier to make effects like Smeared
Something like Rank Smeared doesn't work in vanilla because it'd need to be hardcoded
so it wouldn't be compatible with mods
I see
thanks
G.playings_cards is a table go all the playing cards you own, so using that for loop will give you every card as v in turn
Then inside that you’ll want to use SMODS.has_enhancement
Mine undos the last hand on sell (undoing being +1 hand -last hand score) and auto sells if you're about to lose
Oops! Something went wrong:
game.lua:993[string "147226"]:4273: function arguments expected near '}'
i was changing the localization file
can anyone tell me what i need to do to avoid this error or what causes this
code?
why the fuck is it breaking when i go to the next page 😭
why must i be so trash at making ui codeeee
it attempted to call a nil value
i dont know what value it is though...
look at the lovely dump then
better calc 2 still giving different numbers than retrigger api 🤔
Is there a way to remove a consumable from its respective pool?
Like make it so that you can’t get Strength from packs and shops, for instance
you can take_owenership on it and then override it's in_pool function
although irrc strength is the default tarot to it might still show up if it can't get another tarot
im translating the whole localization.lua file
but i think i accidentally deleted something and i cant find it
Anyone have any idea why this doesnt work? It's supposed to move the currently hovered joker or consumeable's description up by 1 unit but it gives this error
I know that the error is caused by v.config.h_popup:recalculate() but i have tried many values and it doesnt work
is there a context for if a joker is being sold, and a way to tell if it is this joker?
nvm I found it
context.selling_self
what is the copier argument in the consumable.use function?
all five jokers done!
the last one swaps the editions of the jokers on the left and right once it's sold
also does anyone know how to get the name of modded jokers?
e.x. "Flat Circle" instead of "j_mini_FlatCircle"
uhh yeah you can just search for the name of the joker instead of the key
for index, value in ipairs(G.jokers.cards) do
if value.name == "whatever you're searching for" then
---do stuff
end
end
that should do it
i think
i have yet to solve this problem in the cashout screen where
if a joker has its name color changed
the color changing tag shows up on the cashout message
i was told this is due to "not localizing it"? but i don't really know what that means in this context
anyone know how to fix that
Just use SMODS.find_card
SMODS.find_card has done nothing but betray me
I cannot get it to return a coherent result ever
the one time I got it to print the output, the table was empty
fuck smods find_card
Are you using the name instead of the key?
i was using the key yes
Were the cards you looking for debuffed?
nope
i had one joker, it was the one i was searching for, and smods.find_card simply did not run
I've never had issues with it
What key did you use?
And you sue that your prefix is right?
yes
¯_(ツ)_/¯
it didn't work for holy water in my mod either
Works fine here for me https://github.com/WilsontheWolf/JamMod/blob/master/lovely.toml#L24
i'm going to update steamodded and hope all the problems magically go away
if they don't, i'm suing
do you know why this happens though
well that's annoying
@edgy reef the payout api is your domain right?
I wouldn't say "payout API" since that got nuked but yeah I know how the ceashout screen works.
Oh well that shows how much I know
It takes the raw text of an object and applies it's own color.
Make a patch on this line (in common_events.lua) before highlighted text that check for config.card and config.card.config.center.key == 'j_joker_key', with the same code in the if check except type = 'name_text' is switched to type = 'name'.
I think everything else should be fine?
uhhh
you lost me at the type = name_text part
ohhhhhh wait
i think i get it hold on
oh wait this wouldn't work cause then localize return a DynaText
ok scratch this, new idea
Have your joker name without color text localized in G.localization.misc.dictionary
Follow the same steps here, but instead change the entire localize part with localize('noncolored_joker_name_key')
how do i make multiple patches in one lovely.toml file
do I need to redo the manifest section or just everything below patches.pattern or what
Only the patches.pattern part
okay
Just look at what other mods (or steamodded) do
i don't expect this to work first try
it panicked
and died
yeah i don't know how to make multiple patches
figured it out
it crashed
how would one go about making a playing card enhancement that makes the card copy all the attributes of the card to the right? have been trying to retrofit how blueprint works but im missing a key step somewhere
you're
missing the entire blueprint function
you're just assigning the card to the right to a variable that doesn't do anything
By attributes do you mean enhancements and seals?
ideally id want to copy the ENTIRE card to the right, basically a playing card blueprint
(also you should probably have a check for if the card is the rightmost, or it might crash if you try to reference i + 1 when it's the last index)
it current just returns nil if its rightmost but yes good idea
So copy rank, suit, enhancement, edition and seal
i know it doesnt have actual copy code yet, but thats because i dont know how to copy aspects of a playing card
the internal structure of a playing card is not somehting im yet familiar with
ive tried retrofitting this once already but it crashes because playing cards dont have a calculate function, so i'm just like... yeah, trying to figure out how to get what i need by the time its time to score
if you want the card to act as the rank of the card to its right you'll have to do some stuff when the card is highlighted i think
there's a cursed tarot in dx-tarots that makes wildcards copy the rank of the card to their right, look at that
[[patches]]
[patches.pattern]
target = "functions/common_events.lua"
pattern = "elseif string.find(config.name, 'joker') then"
position = "before"
payload = """
elseif config.card and config.card.config.center.key == "j_tsun_secret" then
table.insert(left_text, {n=G.UIT.O, config={object = DynaText({string = localize{"k_nocolor_secret"}, colours = {G.C.FILTER}, shadow = true, pop_in = 0, scale = 0.6*scale, silent = true})}})
"""
match_indent = true
i think i followed the instructions right?
but it's crashing
so /shrug
i'm not sure how to achieve what you want, but you might want to take a look at eval_card in common_events.lua in the game code
funny thing, i just thought to try that
im gonna try as we speak
For one, localize needs to be parenthesis, not curly brackets.
it was curly brackets when i copy pasted it
Second, the crash above is from failing a version check not from this
aw, no dice, at least not how i wrote it. gonna try a couple different configurations of it
How'd you write it
try returning that
actually nvm, it's an enhancement
oh
well I did just update steamodded
like an hour ago
do I roll back version or what
yeah, sad :( theres a couple different strands of this thread i can try so its not a dead end quite yet
Wait
?
Store the return value of eval_card and manually set the values on the effect table
..... 
that's my idea anyway, good luck
Can anyone explain to me what copier is in the Consumable.use function?
copier seems to never be used in the game
It's in mod code for consumables, but I'm not sure why. things like this:
I guess I won't worry too much about it
it's used like that in the game as well, but the function is never called with a 2nd parameter
looks like some kind of blueprint for consumables
THERE'S LIKE A WHOLE SPREADSHEET???
^^
And these are on the SMODS.Center page
I guess if you want to be safe use copier or card instead in situations where you'd use card
I think copier is some remnants of old thunk code
It's never used
so i've encountered a new problem... self, card, context, and effect in this function are all fed in as nil.
somehow.
so i literally cant get anything done in this function, and i dont know why its suddenly all nil
i know printing things out can be a bit weird in lua, but as far as i can tell i cant get any info out anywhere in here
lovely is broken when printing tables rn
@gaunt thistle is that fixed in source rn
ohh, thats why. lovely
DebugPlus shows it properly
or you can wrap the table in tprint or inspect for more info
yeah... how do i print things to debugplus instead of the lovely console
lua doesn't have a native way of printing tables, so lovely likely won't either
it intercepts the console
i havent actually figured that one out
debugplus is the way to do it
yeah i was just gonna say there's a tprint function for printing tables
print(tprint(table))
At lwast do the table string
in balatro
instead of nil
if you really want there is https://github.com/WilsontheWolf/DebugPlus/blob/master/docs/dev.md#logging
I merged a PR which uses lua's tostring() function instead of lual_tolstring, so that should improve functionality
but for dev I just use print
that'll be in 0.7.0
ok that should be good
no like i have it, but whenever i try to print, it goes straight through to lovely
you might have only show commands checked
ctrl + / should bring up the funny debugplus console
(just /)
oh change the log level to info
well its you get all the ones to the right of your option as well
maybe I should flip the level so Debug is the right one and error is the left
I will probably make an option to format tables in the future when just printed
but I need to adjust my table printer first
I could also theoretically implement it in lovely but I really want to avoid any bloat
it's the sorta thing that should be vendored out to an actually good library like debugplus
Yeah plus you doing it won't effect DebugPlus logs whereas me doing it will effect lovely logs
Is it possible to make soul-type cards that can replace jokers?
Just had a random thought
wym
like black hole and soul?
but for jokers?
yes
Like, there's a chance for a specific spectral to replace a joker in a pack or something
yeah thats possible
Cool
Results are in for this calculation!
Retrigger API 68 seconds
Better Calc 2 42 seconds
🎉 🎉 🎉
i feel like im so close to getting this working, but whenever it tries to play this card this error happens
its not pointing back to anywhere in my code in the stack trace
not obviously, at least
I'm curious what's the times like before the new talisman change (the calculating screen)
i like lua sorta but the way it prints errors is so unreadable and stupid 😭
the only overhead calculation screen adds is GC which is necessary
To be fair the error handler is part of smods
Well there's some more overhead for stiff running each frame
but yeah with GC overhead excluded it's probably a much bigger improvement than it seems
Like I believe joker display causes more delay with the clacuating screen
oh
then i redirect my anger at smods
well yeah
marginal
I think updating the chip display should be turned off too
Redirect it to me cause I am the guy who made it
oh
And I'm the guy with the knowledge to fix it
wait really
overhead of calculation screen is ~40% of total iirc
fight fight fight fight
Well it's based off the love default handler
(of course this varies)
And stacktraceplus
40% seems like a significant amount, is there no way to reduce that down whilst still having some sort of visual progress?
then wtf is going on here please help 💀
the joker is supposed to destroy joker to the left of it, and then create a random joker of the same rarity
but it does absulotely nothing
SMODS.Joker {
key = 'jolot',
loc_txt = {
name = 'Joker Lottery',
text = {
"Destroy joker to left of this card,",
"create a random joker of the same rarity"
}
},
rarity = 3,
atlas = 'atlas',
pos = {x = 0, y = 0},
cost = 2,
config = { extra = { leftc = nil } },
calculate = function(self, card, context)
if context.joker_main then
for i = 2, #G.joker.cards do
if G.jokers.cards[i] == card then
card.ability.extra.leftc = G.jokers.cards[i-1]
end
end
end
if not card.ability.extra.leftc then
return false
else
card.ability.extra.leftc:start_dissolve()
SMODS.create_card({
set = 'Joker',
area = G.jokers,
rarity = card.ability.extra.leftc.rarity
})
end
end
}
``` im guessing its something with the for statement (`for i = 2, #G.joker.cards do`)
WAIT
I KNOW EXACTLY WHAT IT IS
i swear
i swear if its just that i forgot the s in jokers in the for statement
again it's mostly completely necessary gc overhead
go yell at Mike Pall if you want the luajit garbage collector to be better
fair enough in that case
I guess the alternative without it is you just run out of memory
Yeah probably the best optimization at this point is to make less garbage and calculate less stuff
now that i think about it you could probably build a very efficient garbage collector targeted towards scoring
ok well it just crashes on launch
imma try my older code and change the .jokers thing
yeah we could definitely this actually
I've calculated less stuff!
nvm
Wonder if we can reuse memory somehow
I shaved nearly 40% off that calc
Nice
I was thinking if it would somehow be possible to load the game in a thread headless then save the game, send the dabe to the thread, load it and then calculate in the background
Would allow a stable fps and could be used for like divvys preview as a backend too
eg. a game process whose sole job is to do calculations?
I'm pretty new, how can I use lovely to create a flag for a joker? (i.e. winning a boss blind with it). This is what I have now, but the variable doesn't seem to exist
you should look into achieving that with smods before you go for lovely
how so? I've looked through documentation and I'm not sure how I would keep track of that. I guess I should've specified that I want to keep track of this flag after the joker is gone (like Gros Michel)
nvm I found an example, thanks.
How can I modify the amount of chips needed to beat a blind? I was trying to take info from Mr. Bones but it doesn't seem to recognize G.GAME.blind as an actual value.
G.GAME.blind.chips = math.floor(G.GAME.blind.chips * percent)
G.GAME.blind.blind.chip_text = number_format(G.GAME.blind.chips)```
i wonder if we could multithread like this too. like, we could avoid conflicts by requiring mods to supply the things they affect, and that would eliminate the risk of misordering issues
G.GAME.blind.blind
Nice, what are you calling it?
Oh my goodness i'm stupid, thank you lmao
could that also be used to find out id you overshoot the blind score?
Minima, since all the cards have a sort of minimal design
I would assume so, G.GAME.blind.chips is the amount you have to achieve and i think G.GAME.chips holds how many chips you currently have
ty ty
Now this is just silly
Part of an effect of a Joker I made called "Refrigerator" that makes food jokers degade half as fast
i gotta ask, to do that did you have to overwrite every food joker individually?
...maybe
A necessary evil
how did you prevent your mod name from showing up on the modified jokers tho?
I didn't take ownership of the jokers, I injected my changes with Lovely patches
couldn't you just
search for the joker
and change its values manually if it's in the joker slots...
you don't need a lovely patch or anything
ah, thats a bit too complex for me rn
refrigerator could do it self contained
If I do that then the description wouldn't show up properly in shops or collections or etc.
why would it show up halved in the collection that doesn't make sense
you can check the jokers that are in the shops and they have values set you can change
just check it again when you reroll
Descriptions in collections do change during runs and I wanted to keep that consistent
Thus here we are
tbh I thought the same thing before I started doing them but they're honestly not that bad
i mean i literally started yesterday, im sure i can get there eventually
im also learning lua at the same time
example mod with joker stuffs in it
very useful tool
i am dw
Me too lol
and one for seals
it doesnt have any examples for take_ownship though which im struggling with a bit
take_ownership is really simple
it has two arguments
the first one being the key of the thing you wanna take
like j_splash for splash as an example
the second one being a table
this table should contain everything you want to replace
this is pretty simple when changing things like the name which are just variables but
if you wanna change the calculate function for example, which is usually why you're using the function in the first place
you need to replace the entire calculate function
so first just copy paste the calculate function from the other joker, and then change what you want to change
yeah thats the main part thats tricky
i'm gonna take ownership on splash solely to put my mod badge on it
rn im trying to take_ownership of obelisk to make it trigger on most played hand instead, but for whatever reason it still executes the original code on top of my code
okay well first of all
jimball from cryptid already does that
second I do not support overwriting obelisk to make it "good" it's a joker for pivoting i think it should be changed to uncommon but not have its function changed
i'm not really sure why you'd do this with take_ownership when you can make a new joker?
ok specifically it keeps its normal functionality but changes to upgrade on most played hand if another joker is in the inventory
I second this ngl
this i mean
yeah the problem with obelisk is just that it's too rare
im not just changing it outright
what does it do now
if monolith isnt in hand it works as normal but scales twice as fast, if monolith is in hand then it works the same but always says "reset" when most played hand is player, even is mult is at X1
heres the vanilla code for reference
put one if statement that checks if monolith is there
and then write the full code the way it should act if monolith is there
and then put the vanilla code in the else
that sounds like it'd be much easier and would probably indirectly solve your problem
probably tbh, lemme try
trying this, still scales twice as fast
and monolith does nothing
im really stumped
i think it might be cause like, when it gets upgraded it doesn't actually return anything
unlike something like runner which gives an "upgraded" message
ok yeah when i put a retrun {} after the mult upgrade it scales correctly, but the joker does a little juice up with no msg and looks awkward
Hi, how can I get a card to count as any suit?
under what contexts? like any card at any time?
return {
message = localize("k_upgrade"),
card = card
}
oh man I can't wait for the death of card = card
so true
yeah thats what i did for now, i dont really like it cause obelisk usually doesn't give an upgraded msg and I don't want to change base joker functionality
but it works
i mean it'll work without the return
it just won't give a message
yeah but it still does the like, little juice up effect, just with no text
if you return nothing it won't do that
uhh
if you return a blank table (which is something) yeah it might juice itself
{} is not a falsy value
You mean as an enhancement? I'm pretty sure just add any_suit = true to it
return
end```
is valid code
i assumed that would bug out tbh
naw
it's treated the same as returning nil
even though nothing doesn't exist in lua
More like the smeared joker
But thank you anyway
ok this is making it scale twice as fast again
ah i get it
essentially obelisk behavior is defined explicitly in the vanilla calculate_joker code, so taking over calculate doesn't erase the vanilla behavior
you can use a lovely patch to remove that behavior
i was fearing that was the answer..
i believe it
i don't remember toml syntax for patches anyways
i rarely need them and i just copy other people's code and edit the necessary fields
You'd have to edit the code for the Card:is_suit() function I'm pretty sure, since you're basically just making smeared again and that's where smeared works. I'm not entirely sure how to use lovely patches but if you can figure it out, adding this right above both smeared joker parts should work.
if next(find_joker('YourJokerName')) then
return true
end
i know its like as easy as subtraction, but im still learning addition lmao
potentially dumb question, how do i add a custom enhancement to an existing card via a consumable? for the life of me i cant find how tarot cards like empress and tower do it
Thank you a lot
I feel like it would probably be a better use of time to instead let modded calculate functions handle repititions once by passing them and then doing nath instead of recalculating them each time
do you know if there's like a tutorial on making lovely patches for balatro anywhere?
I imagine it will insanely speed up calculations too
you can just look at someone else's patches and it should be evident what you have to change and how
there's a file path, a pattern (what you want to change), a place (whether you want to to be before, at, or after), and a payload
does cryptid use patches?
and all the other stuff is just filler basically
yes
better calc only calulates repititons that actually do something now
i dont know existing mods well tbh
That's good, but like do we really need to calcualge our +4 mult joker 1000 times instead of doing 4*1000
but you're going to have to do calculations to calculate retriggers anyway
ah it's its literally like, regex?
but I suppose you can just do the repetition contexts first and pass back the number
Find and replace basically
awesome ty
oh shit is the calc 2.0 almost done?
Holy shit it worked
Thank you so much for your help!!
Although people can peek in the deck, but it'll get harder when they get more Blinded cards
Nice. I had had an idea for a similar effect but I thought it wouldn't be difficult
So I thought about an effect that makes the next card drawn face-down
Since you know which ones have the effect but you don't know what's next
Also cool art :0
Thanks! I'm not really good at art but I have a lot of ideas
Love the 2nd from the first image
What do you mean "not good" lol
Those are awesome
Do you have effects for all of these?
Nah they're just plain cards
Can I DM you
Sure thing
That's Jolt, when not played, it gains the total number of chips of each unplayed card (and also an additional +20% of each card's worth) and +5 Mult for each one
chat i just got done porting the currently most relevant balamod mod to steamodded (i saw 2 people use it in just one day)
when i was testing the steel joker code, for another joker i'm making, the smods version always seems to be one update behind, compared to the steel joker, am I potentially missing something to constantly update it?
question: i want my mod to do different things depending on what the ante is (music changes every 2 antes). i think i could make it work by shoving a bunch of G.GAME.round_resets.ante comparisons in the select_music_track return, but would it be possible to use if statements for each case?
right now im trying if (1 <= (G.GAME.round_resets.ante % 8)) and ((G.GAME.round_resets.ante % 8) <= 2) and its never true. it's also nested under a if (G.GAME) but i dont really know what G.GAME is
that looks like it should work, can I see the full function?
there are 7 of these smods.sound blocks per case
surely the problem isnt that i didnt save lol let me check
yeah its saved, doesnt work
it doesn't work because you're only creating the sound when you're ingame
and all those conds are false when the game launches
Oh yeah devs feedback on #1228149931257237664 message
how should i go about updating them
you should move the conditions into select_music_track
alright i figured that would work, its just messy
it's the way
else you're statically creating or not creating the data for the music when the game loads
lol
line breaks:
tbh I would do (G.GAME.round_resets.ante * 2) % 2 == 0
(the first 2 is the number of antes it takes to change and the second is the number of songs to choose from)
then the other song has the == 1
yes
I may be stupid
did...did localthunk accidentally leave in the "chip" part for each of these function names?
no your score is your chips so your mult would be your chip multiplier
oh ok thank god
“Not really good at art” my guy you are COOKING
People be like "I'm not really good at art" and then don't see my art
Lmaooo alright yeah I can draw abstract patterns and shapes but not faces and tangible objects
peak
Absolutely peam
HELLO???? PEAK??????
One more but I don't know how to shade ice
I got this working and now the next thing i want to do is make it so music stops playing when you beat the boss blind where the music is going to change. i think i can use SMODS.Sound:create_stop_sound for this (or if not i can use a silent sound file) but i dont know what game condition to check for (the same one where the payout screen pops up). is there a list of game conditions somewhere? or a way to poll for them with debugplus?
new question: is there a way to do intro + loop music like how binding of isaac does it (intro plays once and then a separate sound file plays afterwards on loop)
brute forcing it with a long audio file is lame and makes for a large download
what's stopping you from playing the intro once and then playing the rest on loop
Here's a fun one i just finished
fun fact you can do this naturally, within a very very small window
how do i not loop something
i assume you play it and then stop playing it when it finishes
theres no flag for when an audio file finishes or anything
i could play an intro as a sound effect instead of music but then theres no way to make the looping part come after it, they would play at the same time
okay so let's say the intro music lasts 10 seconds
you wait 10 seconds after playing it
then play the other thing
all the music is handled within smods.sound, so i dont think thats possible
the issue is how do i play two audio files sequentually using smods.sound
i mean if you confine yourself to only what you can put inside an SMODS.Sound call then you can't do it yeah
but of course there's other things you can do
everything is entirely open to tinkering
im relying on it because it checks what to play every frame and i otherwise dont know how to really do anything that doesnt just run once when the game starts lol
well i wouldn't be able to help with this specific thing (especially because i can't get to my computer)
do y'all know why this isn't working? it's just straight up not activating
deck.trigger_effect = function(self, args)
if args.context == 'using_consumeable' and args.context.consumeable.ability.set == 'Planet' then
G.E_MANAGER:add_event(Event({
trigger = "before",
delay = 0.2,
func = (function()
--this is all jenlib stuff
local low_hand = jl.lowhand()
jl.th(low_hand)
level_up_hand(self, low_hand, nil)
jl.ch()
sendInfoMessage("Upgraded lowest level hand", "Shellular's Deck of Cards")
return true
end)
}))
end
end
for reference, the deck is trying to level up your lowest level hand when you use a planet card
i just need to figure this out
theres gotta be some stupidly simple thing im missing here
im switching between versions of the joker and tweaking things, rn im tweaking my first attempt at making it
i assume you've fixed the #G.joker.cards already
yes, changed it to #G.jokers.cards and then #G.jokers (neither worked 💀
use the first one
ok
ok i made an update
lets see if it works
ok it worked in some way
but now uh
theres a lot of jokers
they arent taking up a slot
ig its just infinitely creating jokers now
heres the code
local left_card = nil
SMODS.Joker {
key = 'jolot',
loc_txt = {
name = 'Joker Lottery',
text = {
"Destroy joker to",
"left of this card,",
"create a random joker",
"of the same rarity"
}
},
rarity = 3,
atlas = 'atlas',
pos = {x = 0, y = 0},
cost = 2,
calculate = function(self, card, context)
if context.setting_blind then
for i = #G.jokers.cards, 1, -1 do
if G.jokers.cards[i] == card then
local left_index = i - 1
if left_index > 0 and G.jokers.cards[left_index] then
left_card = G.jokers.cards[left_index]
break
end
end
end
end
if left_card ~= nil then
left_card:start_dissolve()
SMODS.create_card({
set = 'Joker',
area = G.jokers,
rarity = left_card.rarity
})
left_card = nil
end
return true
end
}
you need to emplace the card you create in G.jokers
isnt that what area does?
so G.jokers:emplace(card)
clearly not
it returns the card it created
so i cut that function (SMODS.create_card) into the emplace function?
you can do that or you can assign the card you create to a variable
they are functionally equivalent
outside of technical things
so this would work
yes
most people wouldn't do it like that though
mostly because you also need to call card:add_to_deck()
well i do whatever dumbass stuff works lol (probably why most of my code always has issues)
potentially
'for' limit must be a number
lemme check
improper return in your calculation function
ok
--- STEAMODDED HEADER
--- MOD_NAME: H1DRO Mod
--- MOD_ID: H1DROmod
--- MOD_AUTHOR: [H1DRO]
--- MOD_DESCRIPTION: Interesting, or extremely dumb stuff..
----------------------------------------------
------------MOD CODE -------------------------
SMODS.Atlas {
key = "atlas",
path = "atlas.png",
px = 71,
py = 95
}
local left_card = nil
SMODS.Joker {
key = 'jolot',
loc_txt = {
name = 'Joker Lottery',
text = {
"Destroy joker to",
"left of this card,",
"create a random joker",
"of the same rarity"
}
},
rarity = 3,
atlas = 'atlas',
pos = {x = 0, y = 0},
cost = 2,
calculate = function(self, card, context)
if context.setting_blind then
for i = #G.jokers.cards, 1, -1 do
if G.jokers.cards[i] == card then
local left_index = i - 1
if left_index > 0 and G.jokers.cards[left_index] then
left_card = G.jokers.cards[left_index]
break
end
end
end
end
if left_card ~= nil then
left_card:start_dissolve()
left_card = nil
G.jokers:emplace(SMODS.create_card({
set = 'Joker',
area = G.jokers,
rarity = left_card.rarity
}))
end
return true
end
}
----------------------------------------------
------------MOD CODE END----------------------
``` its not much else
ok ty
lemme try it now
ok now it does nothing
pluh
prob me using the stupidest way of emplacing
what about this instead
for the emplacing
wait
has to have local
yea
ok
contrary to what the name says it has nothing to do with putting a card in your deck
yup
ok imma test it
does nothing
lemme show the full updated code
--- STEAMODDED HEADER
--- MOD_NAME: H1DRO Mod
--- MOD_ID: H1DROmod
--- MOD_AUTHOR: [H1DRO]
--- MOD_DESCRIPTION: Interesting, or extremely dumb stuff..
----------------------------------------------
------------MOD CODE -------------------------
SMODS.Atlas {
key = "atlas",
path = "atlas.png",
px = 71,
py = 95
}
local left_card = nil
SMODS.Joker {
key = 'jolot',
loc_txt = {
name = 'Joker Lottery',
text = {
"Destroy joker to",
"left of this card,",
"create a random joker",
"of the same rarity"
}
},
rarity = 3,
atlas = 'atlas',
pos = {x = 0, y = 0},
cost = 2,
calculate = function(self, card, context)
if context.setting_blind then
for i = #G.jokers.cards, 1, -1 do
if G.jokers.cards[i] == card then
local left_index = i - 1
if left_index > 0 and G.jokers.cards[left_index] then
left_card = G.jokers.cards[left_index]
end
end
end
end
if left_card ~= nil then
left_card:start_dissolve()
left_card = nil
local new_card = SMODS.create_card({
set = 'Joker',
area = G.jokers,
rarity = left_card.rarity
})
G.jokers:emplace(new_card)
new_card:add_to_deck()
end
end
}
----------------------------------------------
------------MOD CODE END----------------------
you're saying it's not crashing?
it's just not doing anything?
yea it aint crashing, just isnt doing anything (seemingly, dont have any debug things)
i have a mad joker to the left of the joker lottery and when i play a hand, mad joker just does its thing and nothing else happens
you're checking for context.setting_blind
so yeah it won't do anything when you play a hand
OH WAIT
I FROGOT TO CHANGE THAT AFTER GOING BACK TO OLD CODE
and when you set a blind it'll crash saying "attempt to index a nil value" because you undefine left_card and immediately try to index it
so it needs to be joker_main right
oh yea
i gotta fix that lemme uh
there we go, moved left_card = nil to right after the create_card
now lemme test
IT WORKED
but it did a weird thing (im not very sure what)
this is the result
you can also just not do that
it'll get garbage collected
oh yea
i could ngl
oh wait nvm why are you defining that as a global
define it as a local that's in scope during the whole function
its not defined, its changed (if thats what you mean)
before the joker i did local left_card = nil
though i could just do local right there
oh i see
in the function
yeah that's traditionally better
like this
naw that's not in scope
oh yea it aint
also you can do local varname as a shorthand for local varname = nil
so should i do local left_card as first line for the calculate function or just put it outside like i did before
first one
ok
IT WORKED IT WORKED IT WORKED LETS GOOO
that normal joker got me a Cloud 9
tysm for the help
nice
i couldnt have done it without you
Is there a way I can overlay a sprite on top of a card (including the swiveling movement when you move your cursor on top of a card)? This is entirely separate from an Edition, Seal or Enhancement
though it was uncommon instead of common but im sure i can figure out that little issue
Is there a way I can disable all vanilla jokers from showing up in the shop and only load my mod's jokers?
card sprites are already composite, so patching in an additional sprite should be possible
the front (suit/rank) and center (enhancement) are two different sprites, as well as seals and such. a lovely patch or twelve can probably do the trick
Oh man a lovely patch? Maaan I don't know how to write those
What function or code do I get from the source code to make a patch with? There's set_seal in card.lua, set_sprites too, etc.
ok i think that was a one time bug cuz now its doing it just fine
ok nope
did an uncommon and got common
You’ll want to look in Card:draw() to where there’s a big long if chain of editions, seals, floating sprites. I’d recommend copying the seal block and modifying it for your new sprite, and then you need to figure out where in the layering you want your sprite
This one?
That’s the one but you’ll want to look at the lovely dumps instead
i noticed theres a spectrum mod now so i made my mod support it
Ah right, cheers, but I don't see any difference between the source code and the lovely dump except for the LOVELY_INTEGRITY
Huh, I was sure there were changes
Ah I see
(the text looks so funny being this tiny haha)
It seems like they are used to add existing seals, editions and stickers
But I do want to add a layer without clashing with them, if my layer is considered a seal in the backend then the card with the layer can't take in any other seals
What exactly are you trying to achieve?
sounds like a new card modifier type
It's a custom Boss Blind mechanic, a new modifier type that only appears in them
Yep exactly it
Then yeah, you don’t want to use seals
What should I go for, somehow create a brand new card modifier type, or use some other modifier as a foundation besides seals?
former
You could always use stickers
The calc is a bit jank right now though
-# better calc 2 pls
I haven't played Balatro that religiously yet, do hand cards support stickers
I know Jokers do
swag
yall know how to get a card's rarity?
I would assume Baseball Card's code would have that in there somewhere
They do but like I said, the calc is a little jank
okay yeah Baseball Card checks it by using context.other_joker.config.center.rarity == 2
tysm
so
context.left_card.config.center.rarity?
quick question where can i find all the values that context provides
I actually don't plan to do calculations on it, it sort of acts like a flag on the card and that's it
For my idea of a Boss Blind, it will mark random cards for destruction, and this sticker will be the mark, the card will be destroyed after 2 played hands unless there's a mechanic you have to do
lemme share code
--- STEAMODDED HEADER
--- MOD_NAME: H1DRO Mod
--- MOD_ID: H1DROmod
--- MOD_AUTHOR: [H1DRO]
--- MOD_DESCRIPTION: Interesting, or extremely dumb stuff..
----------------------------------------------
------------MOD CODE -------------------------
SMODS.Atlas {
key = "atlas",
path = "atlas.png",
px = 71,
py = 95
}
SMODS.Joker {
key = 'jolot',
loc_txt = {
name = 'Joker Lottery',
text = {
"Destroy joker to",
"left of this card,",
"create a random joker",
"of the same rarity"
}
},
rarity = 3,
atlas = 'atlas',
pos = {x = 0, y = 0},
cost = 4,
calculate = function(self, card, context)
local left_card
if context.joker_main then
for i = #G.jokers.cards, 1, -1 do
if G.jokers.cards[i] == card then
local left_index = i - 1
if left_index > 0 and G.jokers.cards[left_index] then
left_card = G.jokers.cards[left_index]
end
end
end
end
if left_card ~= nil then
left_card:start_dissolve()
local card_data = {}
local new_card = SMODS.create_card({
set = 'Joker',
area = G.jokers,
rarity = context.left_card.config.center.rarity
})
G.jokers:emplace(new_card)
new_card:add_to_deck()
end
end
}
----------------------------------------------
------------MOD CODE END----------------------
I've tried banned_keys and no_pool_flag and both just result in the shop being filled with just j_joker
You would want to just do left_card.config.center.rarity
so the less than obvious issue with disabling every vanilla joker is that you need to have a joker of every rarity or else suffer the jimbo
and keep in mind that any jokers you currently possess are removed from the pool
i'm trying to get the chip count for the current hand so a joker can apply a multiplier to it but i don't know how to access it
Ohh right that actually makes sense
Oh this is a deck modifier so hopefully none of the vanilla jokers should even be possessed
ok so now im getting constant rares
and i know exactly why
so no worries
basically the rarity arg uses a stupid way of getting rarities
so imma need to make a simple thing to translate them
if it tries to show you a rare joker but you have none, you get jimbo. same with uncommon and common as separate things.
halp T^T
theoretically you can just take_ownership every vanilla joker and add a yes_pool_flag that you never set
local val = self.ability.extra.mult * math.floor(hand_chips/self.ability.extra.conv)
return {
message = localize{type='variable',key='a_mult',vars={val}},
mult_mod = val
}
end```
from my \:banana\: for Emojiokers (gives 3 mult per 15 chips on the current score when the joker is calculated) 🍌
oh thanks lmao
didn't know it was a global var i thought it came packaged with context
yep lol
makes sense now that i think of it
how can I make a joker that would make 6s specifically always score? id assume maybe i could look at splash but just modify the code to only work with 6s right?
fixed it by making two little functions and using them in the create card
so i think joker lottery is FINALLY done
im so proud seeing my idea come to life in balatro (peak game)
even if its a quite simple one
Ayyyy that's sick
Oh my issue was I was also accidentally disabling my own jokers without realising it. Awesome. Lmfao
ill send the current mod (only one joker so far, will add more) tomorrow, for now i gtg to bed
happy new years yall!
happy new year!
Happy new year!
calculate = function(self, card, context, effect)
if context.cardarea == G.play and not context.repetition then
local has_adjacent_slow = false
for i, playedCard in ipairs(context.scoring_hand) do
if playedCard == card then
if (i > 1 and context.scoring_hand[i-1].config.center == G.P_CENTERS.m_fm_slow) or
(i < #context.scoring_hand and context.scoring_hand[i+1].config.center == G.P_CENTERS.m_fm_slow) then
has_adjacent_slow = true
break
end
end
end
if has_adjacent_slow then
card.ability.extra.frozen = true
card_eval_status_text(card, 'extra', nil, nil, nil, {
message = "Frozen!",
sound = "fm_freeze",
colour = G.C.BLUE
})
else
if math.random() < 1 then
G.hand:emplace(card)
card_eval_status_text(card, 'extra', nil, nil, nil, {
message = "Slowed!",
sound = "fm_slow",
colour = G.C.BLUE
})
end
end
end
end
I'm making an Enhancement that has a chance of returning to your hand when played (chance set to 1 just for debugging), it actually does return, but it comes back into the hand flipped, and unselectable, any insights?