#💻・modding-dev
1 messages · Page 664 of 1
Hook Game:main_menu and iterate over G.P_CENTERS and check if v.atlas == 'modprefix_key'
So like this?
Game.main_menu = function(change_context)
local atlas_check = main_menu_atlas_check(change_context)
for k, v in pairs(G.P_CENTERS) do
if v.atlas == 'modid_atlasname' then
local name = localize { type = 'name_text', set = "Joker", key = v.key }
print(name)
end
end
return atlas_check
end```
No, it should be function Game:main_menu(change_context)
Also it should be modprefix_atlaskey
Gotcha
Can you be more specific on what should be function Game:main_menu(change_context)?
. should be :
Are there resources anywhere for making custom UI tabs
Game.main_menu = function(change_context)
Okay, now I have something like:
function Game:main_menu(change_context)
local atlas_check = main_menu_atlas_check(change_context)
for k, v in pairs(G.P_CENTERS) do
if v.atlas == 'modprefix_atlasname' then
local name = localize { type = 'name_text', set = "Joker", key = v.key }
print(name)
end
end
return atlas_check
end```
And now it is giving this error. Is this a function error or a problem with the Jokers I am looking at?
main_menu_atlas_check(self, change_context)
That did the trick, thanks!!!
does anyone happen to know the key needed for set_scoring_calculation to reset scoring to default
'multiply'
does the apply function for a deck/back run when you hold R?
If not, how do I get something to randomize when restarting a run with R or starting a new run
Yes, it runs when a run is started with that deck.
Alright, thanks
How might I be able to make text pop up and say "Burned up!" when the card is destroyed?
this one's not good, a card shouldn't destroy itself during main scoring
also it has two identical conditions, so the second one would never run
fair, but it's a separate probability check
which means it's a 1 in 4 on top of the condition that the first check failed
which is actually a 1 in 8
my main point stands, don't ever destroy a card during its main eval
how can i prevent a card from juicing when triggered? i dont really want my card randomly jiggling while selecting cards because the hand would be debuffed
to clarify, one should use context.destroy_card for playing cards. post_joker in the non-playing card seems fishy too, not sure
I think I made it so you can destroy cards whenever and it will just work
If people do need different timings
does it not fuck up the later contexts though
It shouldn’t do
i am so sorry if i put this in the wrong channel and/or if it's really off-topic, but, good morning/afternoon, i'd really like to improve my coding skills by trying to help people code balatro mods, i was thinking of a pizza tower mod, but all the posts about it are seemingly inactive, should i still try reaching out to the creators?
what exactly is the mod you're wanting to contribute to?
oh yeah totally try reaching out to the artist
ok then, ill try
hey guys how do you destroy the lowest ranked card in the played hand
should i be using SMODS.ante_end or context.ante_end
context.ante_end is a parameter passed alongside two different contexts
i know
but SMODS.ante_end was created for the same thing because sometimes context.ante_end was broken
oh okay
I would assume you loop through every card beforehand and store the lowest rank card to destroy
okay wait i figured it out but How do i get the base nominal of a playing card
just do the raised fist thing
god fucking damnit
Can you tell me how I could make it work properly and destroy after main scoring?
is there some way to use localize() to convert a rank id number to its name? i.e 13 -> "King"
is there any way i can change wee joker's texture to this
local rank
for k, v in pairs(SMODS.Ranks) do
if v.id == id then
rank = v
end
end
localize(rank.key, 'ranks')
Hey guys.
Is there any library for these effects?
backdrop_colour = G.C.SECONDARY_SET.Tarot
alright, so no one function way. But yeah this works, thanks
pee joker
i think you mgiht need to take ownership
idk how to do that lol
what do you mean by "these effects"
backdrop_colour where
in the sense of if there are more colors
Maybe? I thought there would be more colors in the base game. I got it from here.
Or do you mean what colours there are
yeah that
G.C.SECONDARY_SET contains a colour table for every single card type
Including modded consumable types (the colour will be the defined secondary_colour on the object
And theres just a bunch of colours directly in G.C
And theres G.C.RARITY which contains the rarity colours
uuu, okay. Will play around with it. But do you know if there is a list of them somewhere?
open balatro source code
search for C = { in the code
Ya
bump because i know its super easy but i forgor (take ownership)
why would you do this to wee
Is there a way to update the blind reward $$$ text like you can with the blind chip requirement?
i think so, yeah
lemme check the code i did for it
i managed to make it work with this joker
SMODS.Joker({
key = "limepie",
config = {
extra = { dollars = 8, discard_sub = 1 },
},
loc_txt = {
["name"] = "Lime Pie",
["text"] = {
"Earn {C:money}$8{} at end of round",
"Payout {C:attention}reduced{} by {C:money}$1{}",
"per discarded hand",
"{C:inactive}(Payout is currently $#1#){}"
},
},
pos = { x = 2, y = 5 },
cost = 5,
rarity = 1,
blueprint_compat = true,
eternal_compat = true,
perishable_compat = true,
unlocked = true,
discovered = false,
atlas = "CustomJokers",
loc_vars = function(self, info_queue, card)
return { vars = { card.ability.extra.dollars, card.ability.extra.discard_sub } }
end,
calculate = function(self, card, context)
if
context.discard
and not context.blueprint
and context.other_card == context.full_hand[#context.full_hand]
then
local prev_gold = card.ability.extra.dollars
card.ability.extra.dollars = math.max(0, card.ability.extra.dollars - card.ability.extra.discard_sub)
if card.ability.extra.dollars ~= prev_gold then
return {
message = "-$1",
colour = G.C.YELLOW,
}
end
end
if context.end_of_round and context.game_over == false and context.main_eval and not context.blueprint then
if card.ability.extra.dollars - card.ability.extra.discard_sub <= 0 then
SMODS.destroy_cards(card, nil, nil, true)
return {
message = localize("k_eaten_ex"),
colour = G.C.RED,
}
end
end
end,
calc_dollar_bonus = function(self, card)
return card.ability.extra.dollars
end,
})```
no idea how you would make it work though
For blinds, it definitely works different. I can update the dollar value just fine, just need to update the display text somehow
Managed to get it working 
G.GAME.current_round.dollars_to_be_earned = G.GAME.blind.dollars > 0 and (string.rep(localize('$'), G.GAME.blind.dollars)..'') or ('')
what why i dont understand ui
in the code youre only defining two rows inside a column
how do you want it to look
then each thing needs to be in its own row
like
C = {
R = { T= credits },
R = { T= staff },
R = { T= staff names },
R = { T= contributors }
R = {
C = { T = textwrapped1 }, -- although idk if the wrap will have the correct node formatting
C = { T = textwrapped2 },
C = { T = textwrapped3 },
}
}
how get I get the current blinds image for use in a node object?
key is the blind key
also pretend I put hover and obejc tin config
awesome that fixed it thank you!
I am making a joker that turns shop jokers negative if you have that joker already in your bought joker area (Yes this is only useful if you have Showman). I cannot find any examples of code that checks for joker IDs in your main joker area, neither for all of them, or individual ones (Individual as in making a shop joker Cavendish turn negative if you have a Gros Michel). I am hoping to make use of both types of checks, but right now I just want to know if either is even possible. The negative shop joker part is simple, I'm purely stuck on how to begin comparing joker IDs.
local keys, for i,v in ipairs g jokers cards do keys[v.config.center.key] = true end
that might have to be global actually
(don't call it just "keys" in that case obvs)
if next(SMODS.find_card(card.config.center.key))
okay this looks disgusting but it works
The Hook
-# Retrigger 2 random cards
-# held in hand
si
thank you
thank you.
how do i underline ui text
progress
put {u:color} in your loc
Im doing that but im just getting
is it in config.text or your localization file
i'm getting this orange text via my localization file
loc file
how are you getting it out of the file?
{ n = G.UIT.T, config = { text = localize("spox_contributers_tab_name"), colour = G.C.UI.TEXT_LIGHT, scale = 0.6, align = "cm" } },
spox_helpers_tab_name = "{U:white}Project Staff{}",
spox_contributers_tab_name = "{U:white}Contributers{}",
thats the issue
you're basicly plugging those formats into the UI
instead of giving it nodes
lowercase u
i tried lowercase first
but also what foo said
local N = {}
localize{type = "other", key = "ba_" .. key, nodes = N}
local B = G.P_BLINDS[key]
local out = {n = G.UIT.C, config = {colour = G.C.WHITE, maxw = 4, padding = 0.1, r = 0.1}, nodes = {
{n = G.UIT.R, config = {colour = get_blind_main_colour(key), r = 0.1, padding = 0.1}, nodes = {
{n = G.UIT.O, config = {over = true, object = SMODS.create_sprite(0,0, 1.4, 0.5, SMODS.get_atlas(B.atlas) or 'blind_chips', B.pos)}},
{n = G.UIT.T, config = {text = SMODS.Blind:get_obj(key).name or "ERROR", scale = 0.5, colour = G.C.WHITE}}
}}
}}
for _, line in ipairs(N) do
out.nodes[#out.nodes + 1] = {n = G.UIT.R, nodes = line, config = {align = "cm"}}
end
this is what mine does
Other = {
ba_bl_hook = {
text = {
"Retrigger {C:attention}2{} random cards",
"held in hand"
}
}
}
what is over = true in G.UIT.O
that should be hover whoops
you need to give localize a table of nodes that it will populate for you
this doesnt work for G.UIT.O since it dictated by object itself
So sprte should be hoverable instead
speaking of this how do I change the size of the sprite
its doing this rn
You calling create_sprite function incorrectly tho, it's 4 number values and only after that atlas and pos
oh i copied it from the UI_definitions file
oh wait I see why its not scaled
i thought 0,0 was 0.0 lol
yay
SMODS.Sound({
key = "cocosmod_music_boostersong",
path = "cocosmod_boostersong.ogg",
pitch = 1,
volume = 1,
music = true,
select_music_track = function()
if G.STATE == G.STATES.SMODS_BOOSTER_OPENED then
return 1337
end
end
})
frick
I think it’d look better if the background colour wasn’t behind the sprite
Or if it was darker/lighter
okay better
yea G.STATES.SMODS_BOOSTER_OPENED is whenever any booster pack is open
here's what you'll want to do
if G.STATE == G.STATES.SMODS_BOOSTER_OPENED then
local booster = G.pack_cards and G.pack_cards.cards and SMODS.OPENED_BOOSTER
if booster and booster.config.center.key == "p_modprefix_boosterkey" then
return 1337
end
end
instead of literally checking for "p_modprefix_boosterkey", you'll want to put in your own mod's prefix and then the full key of the booster pack you've created
hmmm
lemme figure out how to use the blend color function or whatever its called
why are these horizontal 😭
they should be in a collumn
?????
the data is in a collum
why is it sideways 😭
does anyone know how to fix this?
wtf is this
I mean, it renders as intented, G.UIT.C elements placed horizontally
aren't the collumns supposed to be vertical though?
Content in it, not column itself
columns placed horizontally next to each other and render content inside vertically
That's the logic
In excel spreadsheet rows placed vertically (0, 1, 2...), columns horizontally (a, b, c, d...)
Same here
trying make a Xmult version of misprint
is it possible to put the red box around the changing text?
okay good news I got them vertical
bad news I have 0 clue why they are indented
x1-6 mult
-# 1-6=-5 so X-5 mult?
can't use 0 because anything x0 is 0
lol
anything x1 is itself
so basically no mult
a random number between 1 and 6
Hey, is this good enough to signal I don't want a joker to appear randomly? Does it even work.
only_shop_pool = true,
only_booster_pool = true
},```
trying to but the xmult box around the number text
but way that it's done uses UIT
instead of loc_text
i'd like to make a new AltTexture using Malverk. the texture should replace one of Cryptid's textures. what do i do?
i can replace vanilla textures just fine, but am unsure what the procedure is for other mods
if next(SMODS.find_mod("Cryptid")) then
-- define the AltTexture
end
(also hai meta :3)
hiii
ya that's the part i knew actually 😭
oh my bad lol
so i have this so far
copied from the vanilla one, but with original_sheet = true removed
(oh and it's wrapped in the mod check)
i think maybe you wanna add keys = { "j_cry_joker1", "j_cry_joker2", ... }? and then you might not even need display_pos at all
oh hmm, so like, add the jokers manually
i think so yea
are you planning to replace all the cryptid jokers
yep ^^
yea i'm not sure if there's a good way to do that then without manually specifying all the jokers, sorry
being able to specify a whole atlas to replace would be cool
yeahhhh it'd be awesome ^u^
judging by the way it shows texture packs, though, it can't do that right now
as a guess
it might be undocumented
i don't wanna pester eremel about it tho bc I know he's busy finishing up the smods update lol
o tru
is there a simply way to make an aniamted jokers
like know how to make a sprite sheet for animations
but how would you changed the pos of the sprite in real time
atlas_table = 'ANIMATION_ATLAS'
and this is for say I wanna make a joker look like it's moving left and right
nvm found the smod wiki page
yeah this is what I needed
for frames do I still use x, y or just frames = 8 for the amount of frames?
nvm figured it out lol
:D
I was wondering how I get into the sorce code to see the Hiker Joker
thanks
isnt dinner just a worse bull joker
It's just a straight copy of bull
Just picked a random joker to copypaste to try out animated sprites
oh ok
no it's +2
i know the answer is probably no but i figure i should ask, is there any reliable way to detect jokers that copy effects (blueprint-likes)
no, like if a joker copies like blueprint
u want joker to copy another joker like blueprint or
oh nvm i am wrong lmao, ig i got it confused with the $5 bootstraps needs
i already know how to do that
i'm asking if there's a way to detect whether a joker copies cards like blueprint
so i don't have to manually put in every single modded copier joker's key
probably make a check for SMODS.blueprint_effect and if it triggers do what u need it to do
I don't think so
is this some sort of behavior that you can disable within the calculate function? because you can just do if not context.blueprint lol
this card specifically "matches" any +mult or +chips given by any joker, so i'd like it to "match" mult and chips given by blueprint-likes but not be copied by them (to avoid infinite loops)
obviously that's a bit difficult lol, might just settle for manually checking copier keys
well i suppose adding a not context.blueprint should work
hmm
yea I don't see any reason it won't work
idk why ihad it structured like that, im returning to half a year old code lol
seems like i had it the opposite before, it wouldn't match blueprint-likes but could be copied by them
now i'm not sure which to go with
it's not like this card is itself doing a blueprint effect, it should just be fairly standard post trigger stuff
and context.other_card:get_id() >= card.ability.extra.value
Is there a way to see how many chips scored as I would like to use that rather than the cards base value.
card:get_chip_bonus()
thank you
calculate = function(self, card, context)
-- Only triggers on cards that actually score
if context.individual and context.cardarea == G.play
and card:get_chip_bonus() >= card.ability.extra.value
then
context.other_card.ability.perma_mult =
(context.other_card.ability.perma_mult or 0)
+ card.ability.extra.mult_gain
return {
message = "+Mult",
colour = G.C.MULT
}
end
end
Now it doesn't give anything, am I using it right?
It should be context.other_card:get_chip_bonus()
thank you
Does this joker seem balenced?
It is similar to the hiker and has good synergy with it.
calculate = function(self, card, context)
if context.before and not context.blueprint then
for _, scored_card in ipairs(context.scoring_hand) do
local enhancements = SMODS.get_enhancements(scored_card)
if enhancements
and enhancements.m_stone
and not scored_card.debuff
and not scored_card.jacked then
scored_card.jacked = true
-- Reset to base (removes Stone)
scored_card:set_ability('c_base', nil, true)
end
end
end
end,
how can I make the card become a jack after it is hammered out?
I believe 1 mult = 5-8 chips when it comes to balancing jokers that do one instead of the other. So while the conversion varies, with mult gaining in chip value at higher amounts, it seems like it means this card is definitely on the weak side. Unless I'm overlooking something.
anyone know how one would "dynamically" add retriggers to a card? i have a joker with a 1 in 2 chance to retrigger a card with a red seal, that then increases to 1 in 3, and so on, but i can't figure out how to retrigger multiple times without knowing exactly how many retriggers will be needed
the idea is: 1 in 2 chance - > retrigger -> 1 in 3 chance -> retrigger -> 1 in 4 chance... and so on
i'm coming back to modding after like 2 months away lol so sorry if the solution is obvious
assert(SMODS.change_base(scored_card, nil, 'Jack'))
Probably. I'm not a coder but I have this code right infront of me so it might be it.
for loops
that is it, thank you, tho there is a visual bug where the jack is overlayed ontop of the stone texture, is there any way to make it wait till the stone enhancement is removed before apearing?
local count = 0
while SMODS.pseudorandom_probability(card, "identifier", 1, count + 2) then count = count + 1 end --- i forget what the actually function is but ik the arguments are correct
return {repetitions=count}
while do, not while then
I wish I knew how to adjust timing. Been at it for hours on my "similar" joker and had no success. So I wish you more luck.
ok, thank you, I let yk if I find a way
Thanks
It happens in vanilla Balatro too with the Vampire joker, because of that I am just going to let it be as Im working on a mod that is trying to stay close to vanilla
works perfectly, thanks!
Do quantum enhancements apply to modded enhancements, and if an edition is polled, can a card count as said enhancement if it's stored as an extra config variable?
that would be called quantum edition and it's non-existent
Is there a way through smods that you can change how much space negative edition gives, or do you have to do it with a patch?
take ownership of negative
but be careful; it uses a metatable so your override must also contain a metatable
Thanks a thousand!
meant enhancements for each one, typo
i.e. with Ortalab enhancements, having a quantum enhancement Sand Card
I took a look at how quantum enhancement works
Sand cards reduces xmult gradually
except that might not be the case if applied as a quantum enh
it's always X2 Mult with no downside
quantum enhancements are handled in a context thing, so you should be able to do it in an edition
I'm confused
did the original question mean to ask whether it's possible to apply quantum enhancement via an edition
my original question is if it's possible to apply quantum enhancements for modded enhancements
i ask since my current implementation is very bruteforce and only applies to vanilla enhancements
the voucher that makes 5 random cards in deck act as Wild and Index cards
that's a usage of quantum enhancement
what exactly are you trying to do
my joker is "stone cards additionally act as [enhancement], [enhancement] changes every round"
if context.check_enhancement and context.other_card.config.center_key == "m_stone" then
return {
[card.ability.extra.enhancement_type] = true,
}
end
bruh
that's it
any variable type can become a table index, not just strings
-# this is a string though?
yea, I spoke it at the wrong context lmao
basically this is how Lua works
local a = {b = 1}
local c = a.b == a["b"] --true
local d = "b"
local e = a.b == a[d] --true
you can directly call a.b to grab the b index of table a
a["b"] also works
for more complex keys like strings that contain space, only a["contains space"] works
are there any way to make a joker probability like "Oops ! All 6"?
if context.mod_probability then
return { numerator = context.numerator * 2 }
end
1x file in 2x folder
is there a loop funtion for play_sound
you might wanna specify your sound as bg music, it does the looping automatically
using sync?
sync just makes it transition seamlessly between it and the current track
it's mainly used for music tracks that are somewhat a modified version of Balatro's main track
what's the way to specify music
define select_music_track field
it's a function that may return the number specifying its playing priority (higher is better)
here are some examples
key must contain music btw
path may not, though. 
just tells me it's not a music track
i'll figure this out more tomorrow it's late as is right now
too late now
it's simply easier to copy key over if I set the file names like that
Is there a limit on how long a sprite sheet can be
In terms of width
Like say could I theoretically put 10000 jokers on the name line or would that be too much for balatro to handle
the only limit I know of is your device's capability
i need to access all loaded centers, how can i do that?
G.P_CENTERS isn't working when my mod is being loaded
print(inspect(ghostcards_find_all_on_sheet("Cryptid", "cry_atlasone"))) works once the game is loaded, however it doesn't when the game isn't loaded
function ghostcards_find_all_on_sheet(mod, sheet)
local atlas = {}
for _, v in pairs(G.P_CENTERS) do
if v.original_mod and v.original_mod.id == mod and v.atlas == sheet then
atlas[#atlas + 1] = v.key
end
end
return atlas
end```
SMODS.Centers
ah, cheers ^u^
hmm. a new bug presents itself
i might've solved the issue, but Malverk's wiki was a little misleading
original_sheet needed to be true, because the positions matched those on the original sheet
there we go!
Could someone help me resolve an issue I'm having with understanding some game/lua logic? I'm trying to make what I believed to be a simple joker concept and it's instead hurting my brain and crashing my games.
what's the issue?
do you have the crash log?
Wanted to make a card that functioned like obelisk, but reset if you DIDN'T play your most played hand.
Copy and pasted the reference for Smod code in their "VanillaRemade" library and tried to flip the true/false for reset.
SMODS.Joker{
key = "monolith",
config = {
extra = {
Xmult_gain = 0.2,
Xmult = 1
}
},
loc_txt = {
['name'] = 'Monolith',
['text'] = {
[1] = "This Joker gains {X:mult,C:white} X#1# {} Mult",
[2] = "per {C:attention}consecutive{} hand played",
[3] = "while playing your",
[4] = "most played {C:attention}poker hand",
[5] = "{C:inactive}(Currently {X:mult,C:white} X#2# {C:inactive} Mult)",
}
},
pos = { x = 0, y = 0 },
rarity = 3,
cost = 8,
blueprint_compat = true,
eternal_compat = true,
perishable_compat = false,
unlocked = true,
discovered = true,
effect = nil,
atlas = 'monolith',
loc_vars = function(self, info_queue, card)
return { vars = { card.ability.extra.Xmult_gain, card.ability.extra.Xmult } }
end,
calculate = function(self, card, context)
if context.before and not context.blueprint then
local reset = false
local current_played = (G.GAME.hands[context.scoring_name].played or 0)
for handname, values in pairs(G.GAME.hands) do
if handname ~= context.scoring_name and values.played >= play_more_than and SMODS.is_poker_hand_visible(handname) then
reset = true
break
end
end
if reset then
if card.ability.extra.Xmult > 1 then
card.ability.extra.Xmult = 1
return {
message = localize('k_reset')
}
end
else
card.ability.extra.Xmult = card.ability.extra.Xmult + card.ability.extra.Xmult_gain
end
end
if context.joker_main then
return {
xmult = card.ability.extra.Xmult
}
end
end,
}
Error code said I was comparing nil to a number, not sure where I did that
play_more_than is not defined
woopsies, accidentally changed play_more_than with current_played when I was fiddling around with stuff
Thank you N'
yo where's my cotton candy
the suspiciously cotton candy shaped egg:
anyone know why this isnt working? the files are in the right spot
what exactly isn't working? you're just showing how you create the images, which has no effect by itself. we're gonna need a bit more information than that
oh mb it's more obvious, thanks Discord mobile for weirdly cropping images
you're files are in assets/shaders
i keep getting the "file does not exist" error
you're telling the game that the files are directly in assets, which they aren't
in other words, it says the file doesn't exist because it doesn't
still seem to get an error
im assuming you have show file extensions on?
can you screenshot the folder in vs code?
what's to stop you from using an image atlas, anyway
its for a shader?
how do i get the english localized name of a card
though i guess you could grab the image out of it
local function get_image(path)
local file_data = NFS.newFileData(path)
local tempimagedata = love.image.newImageData(file_data)
return love.graphics.newImage(tempimagedata)
end
local xyz = get_image(path .. "/assets/shaders/whatever2x.png")
``` ?
that matters how
this is just a reimplementation of what SMODS.Atlas does under the hood
right
alr
nothing im just slow and kind of just going off what was given to me
but yeah ill try that
AT LASTTTT
it took me so long to find out that Malverk doesn't set default_soul on modded Jokers 😭
what if cryptid was good...
thatd be an oxymoron
cryptid 2:
ok im sort of dumb, how would i go about replacing the sprite with the atlas
itd be G.ASSET_ATLAS["glaze"], though you may want to make one atlas for each glaze
alright
yeah there's no dialogue because it's never happening, and i won't believe it until i see it
pretty sure you'd need to send the image and not the atlas itself though, so G.ASSET_ATLAS["glaze"].image
shaders aren't pngs
ough ok there we go, thanks you two
my head hurts so much i hate code
the images themselves aren't shaders, they're data used by a shader
right, my bad
Could anyone help me with this error I'm getting? I can't solve whats going on and I copied all of this from another mod and edited it to work for what I've made. All I did was change names and texts, not any of the code or any brackets.
syntax error
Yeah but like, whats the error
need a comma after the second name
in texture_pack loc_txt
whatever you have is no good
thats dumb, it tells me I'm missing a }
its expecting the table to end
so it thinks there should be a }, not some words
I'm using note pad because I don't want to do coding and don't intend to do more beyond just this 1 mod, plus I have storage issues
up to you, just my recommendation
you'll have a bad time using notepad, but if you so choose that's up to you
Yeah I understand there's significantly better options but my laptop has ghosts that eat my C drive
So, where does the comma go sorry?
after the name in the last loc_txt
name = '...',
Here?
yep
show the whole thing again
oh
quotes
the text in that same table is delimited with single quotes
yet it contains single quotes within it, which is bad syntax
you need to sub them for double quotes
As in " not '
yeah
for the "name"?
the delimiters in the text
text = {"..."}
-# Alternatively you can escape the inner single quotes with a \, just so you know
Interesting
Because this is working off a mod I downloaded to look at how it works, and that ones using '
yeah both are fine to use
you just can't have whatever delimiter you're using occur unescaped inside the string
Whats a delimiter?
by that I mean whatever you have at the start and end of the string
in 'text', the single quotes are delimiters
Darn, I assume I failed at doing what the other mod did
It should be 50BlessingsEnhancers_enhancement_tex
in textures
Oh the prefix at the top
yeah these need to match
Malverk is badly made in that regard 😭
take inspiration from applied_stakes I guess
Yippee I'm so good at this and did everything 100% on my own cuz I'm big brain
(I literally only did 1 thing on my own 2 weeks ago)
all this just to put a gradient over my cards to make them look like hotline miami stuff
reminds me that the prefixing stuff is badly made too and really not extensible
good job
Out of curiosity, can I put 2 .luas in one mod's folder?
currently it's 2 mods, one for the actual deck and one for the enhancers
if they both have headers, they can coexist but will be disabled together if you do disable them
you can however load more files from the main file
Are they both texture replacements?
Would I be able to put the malverk .lua stuff inside of the normal deckskin one and it all read okay?
Yeah that’s fine
One is just the cards
The second one has way more in it
that's a pretty old template oml
I am doing my best 😢
eh it's fine
use this in a mod.json file
gtg anyway
having some trouble hijacking the sell price for a joker.
when buying it in the shop, it'd cost the player $20, but upon being added to the inventory would have its sell price locked to 0
Hook Card:set_cost
Anyone know how to give Boss Blinds custom reward text?
Cos I have Blinds that grant Jokers when defeated
Also how do you make it so a Joker is unlocked when you unlock all spectral cards?
My suggestion for this, use Notepad++; It's free, lightweight, and it reads and saves .lua files fine. Don't ever wanna use for coding again after this? That's ok, keep it to format Markdown text for Discord or just uninstall it, it leaves no residual files and doesn't try and get you to install a bunch of random crap on installation.
i had that exact same question too and never got it to work :/
Actually I'm cooking smth myself, I'll share the code when I'm done
check_for_unlock = function(self, args)
if args.type == 'discover_amount' then
local threshold = 0
local count = 0
for _,v in pairs(G.P_CENTERS) do
if v.set == 'Spectral' then
threshold = threshold + 1
if v.discovered then
count = count + 1
end
end
end
return count >= threshold
end
return false
end,
doing a blind where xmult effects increase the required score by 30%, though this doesn't seem to be working. anyone know why?
SMODS.Blind {
key = "Delta",
atlas = "blinds",
pos = {
x = 0,
y = 6
},
boss = {
min = 6,
},
boss_colour = HEX("7db450"),
}
local eval_card_ref = eval_card
function eval_card(card, context)
local eff, post = eval_card_ref(card, context)
if G.GAME and G.GAME.blind and G.GAME.blind.name == 'bl_biasedBalance_Delta' and G.GAME.blind.ready and not G.GAME.blind.disabled then
local x_mult = card:get_chip_x_mult(context)
if x_mult > 0 then
G.GAME.blind.chips = G.GAME.blind.chips + G.GAME.blind.chips * 0.3
G.GAME.blind.triggered = true
end
end
return eff, post
end
Ok running into a very big problem here
Whenever I disable my mod, the patch that adds multirank support is still applied for some reason, causing the game to crash every time I do smth such as play a hand
Does anyone know how to fix this?
does the game crash if you dont have an atlas set for a blind? im just creating some temporary dummy blinds for testing and im wondering if i actually need an atlas
i know it doesnt crash for other objects but i know blind sprites are also a bit jank sometimes
No, it doesn't.
Is it only that patch or all patches?
Considering this happened with another patch, probably all patches from the mod
how are you disabling it? from the smods menu?
ye\
why does the top blind crash but the bottom one doesnt
for some reason bottom crashes in mix_colours despite nothing that matters for vanilla being different
what if you add boss_colour
i downloaded the deckskintemplate, it seems pretty simple and straightforward but
there are two files named icon_lc and icon_lq
what are their usages?
<- has no idea how modding works btw
its the atlas for the suit icons in the bottom left of the deck view, one for both low contrast (lc) and high contrast (hc)
the icon for the deck view iirc
you can omit them if you dont change them
ooh
cool
my english is not very good, what does omit mean btw
leaving them out
i meant like you can just remove them to not change the suit icons
got it ty
okay, so it's never going in side the if G.GAME ...etc loop. hmm
thank you so much actually
Trying to make a blind that makes your lowest rank held in hand give decimal mult, and I want it to give xmult for each card of that rank. However, it only works once. I would like this effect to trigger on every card if possible (another question is if I can use context.individual on this?)
calculate = function(self, blind, context)
if context.final_scoring_step then
local temp_ID = 15
for i = 1, #G.hand.cards do
if temp_ID >= G.hand.cards[i].base.id and not SMODS.has_no_rank(G.hand.cards[i]) then
temp_ID = G.hand.cards[i].base.id
end
end
for i = 1, #G.hand.cards do
if G.hand.cards[i]:get_id() == temp_ID then
return {
xmult = blind.config.blind.config.extra.xmult,
message_card = G.hand.cards[i]
}
end
end
end
end,
you can use individual
if you want to keep using final_scoring_step you would need to not return in the loop
okay, i wasn't sure if i could. i'll have to try something else
the first 2 prints of this trigger, but the one signifying that the event is running never happens. how can i make the event run?
I think the issue aside from your horrid indenting is that you put Event{{}} instead of Event({}) as it should be.
what's wrong with my intenting? FHDJFDS
Doesn't seem to be getting past the initial checks. I don't think individual and final_scoring_step are compatible
calculate = function(self, blind, context)
if context.individual and context.cardarea == G.hand then
if context.final_scoring_step then
local temp_ID = 15
for i = 1, #G.hand.cards do
if temp_ID >= G.hand.cards[i].base.id and not SMODS.has_no_rank(G.hand.cards[i]) then
temp_ID = G.hand.cards[i].base.id
end
end
if context.other_card:get_id() == temp_ID then
return {
xmult = blind.config.blind.config.extra.xmult,
message_card = context.other_card
}
end
end
end
end,
I think they meant you should use context.individual instead of context.final_scoring_step, not both at once.
Right now I do have it set up for working with individual, and it works just fine. I just would have liked the xmult to be applied after scoring just to make it a bit more effective
is xmult text like collapsed like no whitespace allowed
okay would you prefer that or this (ill probably make the text smaller so it can fit one line)
elaborate if you do remember?
Is that frieza joker
Is that black ops joker
return a colours subtable in loc vars and then use e.g. {B:1} to get the first color as background
Also that's just worse idol
Is that a tiny dog in a big mattress joker
Rebate is infinitely more useful
i mean i can increase it to 6 dollars but there are retriggers
Yeah so does rebate
godspeed 🙏
okay but does it automate to my timezone
Why do they all look like that
What do you mean
Hey guys, do you know where I can find more about this.
SMODS.smart_level_up_hand
deprecated in favor of https://github.com/Steamodded/smods/wiki/1221a#level-up-hands-with-smodsupgrade_poker_hands
I see. Thanks.
Can I input most played hand or current hand in the first argument? or does it need to be a function?
hands is a string or table of strings for the keys of the hands
oh I see. Let me look around. thanks.
is there a better way to do this? hooking into eval_card is causing a lot of random crashes
intended to prevent card modifiers from triggering when scored
SMODS.Blind {
key = "Gamma",
atlas = "blinds",
pos = {
x = 0,
y = 6
},
boss = {
min = 4,
},
boss_colour = HEX("7db450"),
}
local eval_ret = eval_card
function eval_card(card, context)
local ret = eval_ret(card, context)
if (not G.GAME.blind.disabled and G.GAME.blind.name == 'bl_biasedBalance_Gamma') then
ret.edition = nil
ret.enhancement = nil
ret.seals = nil
end
return ret
end
How would i set up a legendary joker, I have the background and the joker face, but I dont understand what soul_pos does
Ik thats what I need for it to float off the card background, I just dont know where to put things to make it work
the background and the joker face need to be treated like two separate sprites on the same spritesheet. the joker will have its pos set to the background and its soul_pos set to the joker face
-- Icarus
SMODS.Atlas {
key = "icarus_atlas",
path = "jokers/icarus.png",
px = 71,
py = 95
}
Do I change something here?
no, don't touch the atlas. just make icarus.png 142x95, and the right half of the image is the joker face sprite
ohhh I see
really you should have all your jokers on one sheet, it's super not efficient to load a different atlas for each joker
atlas = "icarus_atlas",
pos = { x = 0, y = 0 },
soul_pos = { x = 1, y = 0},
yep!
thank you
no problem
If the first reroll is made less expensive does that mean all rerolls after would be less expensive than if the first was normal price
Yes.
Ok
i want to make a joker that lets straights wrap around. i need to find the code for determining what hand is being played but im not finding it anywhere. does another know where the game determines which hand is played?
return { vars = { card.ability.extra.mult } }
end,
calculate = function(self, card, context)
if context.individual and context.cardarea == G.play and context.other_card:get_id() == 12 then
return {
mult = card.ability.extra.mult,
}
end
end
}```
how would I also have this effect affect cards with red seals?
i believe you want context.other_card.seal == "Red"
SMODS has already implemented such thing:
function SMODS.wrap_around_straight()
return false
end
all you need to do is to hook this function here, like this:
local wrap = SMODS.wrap_around_straight
function SMODS.wrap_around_straight()
local ret = wrap()
if next(SMODS.find_card("j_modprefix_key")) then
return true
end
return ret
end
that's neat. my current mod isn't using SMODS. do you know where the code is?
thank u
yeah, im just using lovely

are you making a content mod
doing that with lovely alone is an extremely tedious work
im just making some tweaks to things and like doing things my own way. if i can find the code for it i can just make it do exactly what i want
it should be get_straight in misc_functions
you'll want to look at get_straight in misc_functions.lua
the way SMODS overrides it is quite complex
oh hey that's my new comment
thanks. ill poke around in there and if i cant figure it out i know i can rely on SMODS
at this point just use smods
allowing straight to wrap around isn't an easy feat
I wouldn't say it's a small tweak
No, it's context.other_card:get_seal() == 'Red'
ive been using lovely because SMODS is just so much more complicated and it's easy to just change the game code that i can see. i just want to change Superposition from its current effect to making straights wrap and be worth extra if they contain an ace.
in lovely i can just replace the game code. but i agree that the wrap around code isn't simple. so how do i highjack a joker's effect in SMODS?
i couldn't get this to type in quotation marks ```toml
[manifest]
version = "1.0.0"
dump_lua = true
priority = 0
[[patches]]
[patches.pattern]
target = "functions/button_callbacks.lua"
pattern = '''if args.key == '[' or args.key == ']' then return end'''
position = "at"
payload = ""
match_indent = true
overwrite = false
[[patches]]
[patches.pattern]
target = "functions/button_callbacks.lua"
pattern = ''' local lower_ext = '1234567890-=;',./'
local upper_ext = '!@#$%^&()_+:"<>?'
if string.find(lower_ext, args.key) and args.caps then
args.key = string.sub(string.sub(upper_ext,string.find(lower_ext, args.key)), 0, 1)
end'''
position = "at"
payload = ''' local lower_ext = "1234567890-=;',./[]"
local upper_ext = '!@#$%^&()_+:"<>?{}'
if string.find(lower_ext, args.key, nil, true) and args.caps then
args.key = string.sub(string.sub(upper_ext,string.find(lower_ext, args.key, nil, true)), 0, 1)
end'''
match_indent = true
overwrite = false
[[patches]]
[patches.pattern]
target = "functions/button_callbacks.lua"
pattern = '''if args.key == '0' then args.key = 'o' end'''
position = "at"
payload = '''if args.key == '0' and G.CONTROLLER.text_input_hook.config.ref_table and G.CONTROLLER.text_input_hook.config.ref_table.ref_value == "setup_seed" then args.key = 'o' end'''
match_indent = true
overwrite = false
i dead hella don't know what i'm doing wrong
i need help
pls
wheres your ui code
version = "1.0.0"
dump_lua = true
priority = 0
[[patches]]
[patches.pattern]
target = "functions/button_callbacks.lua"
pattern = '''if args.key == '[' or args.key == ']' then return end'''
position = "at"
payload = ""
match_indent = true
overwrite = false
[[patches]]
[patches.pattern]
target = "functions/button_callbacks.lua"
pattern = ''' local lower_ext = '1234567890-=;\',./'
local upper_ext = '!@#$%^&*()_+:"<>?'
if string.find(lower_ext, args.key) and args.caps then
args.key = string.sub(string.sub(upper_ext,string.find(lower_ext, args.key)), 0, 1)
end'''
position = "at"
payload = ''' local lower_ext = "1234567890-=;\',./[]"
local upper_ext = '!@#$%^&*()_+:"<>?{}'
if string.find(lower_ext, args.key, nil, true) and args.caps then
args.key = string.sub(string.sub(upper_ext,string.find(lower_ext, args.key, nil, true)), 0, 1)
end'''
match_indent = true
overwrite = false
[[patches]]
[patches.pattern]
target = "functions/button_callbacks.lua"
pattern = '''if args.key == '0' then args.key = 'o' end'''
position = "at"
payload = '''if args.key == '0' and G.CONTROLLER.text_input_hook.config.ref_table and G.CONTROLLER.text_input_hook.config.ref_table.ref_value == "setup_seed" then args.key = 'o' end'''
match_indent = true
overwrite = false```
no, your ui code
like for the box?
k cya
look at
.. (hook.config.ref_table.extended_corpus and " 0!$&()<>?:{}+-=,.[]_" or "")
change it to
.. (hook.config.ref_table.extended_corpus and "\" 0!$&()<>?:{}+-=,.[]_" or "")
@pastel kernel
nothing
wait i can put quotation marks with that text_input_key?
u sure the init is called?
try adding print in the init
like the corpus thing?
no like
init = function()
--some code to make typing more characters better
print("init called")
it's not printing
the init is not called then
atleast youve gotten somewhere
🤷♂️
how do you load the file?
or just, dont put it in the init i guess
i gtg
...k
it works without it
but i'm still troubled with the apostrophe
and the quotation marks
unless somethingcom comes to the rescue and types in a behemoth of code for me to use, i'm stuck and stumped
local a = [[this is a string]]
use the illegal stringify method 
Here is an odd question. I have a Joker that has multiple forms depending on how it is gotten. It uses the key = self.key .. method of giving a unique description for each one. When I try to info queue the loc text for those forms using G.P_CENTERS, I get nothing in return. Is there a way that I can get those to appear?
info_queue[#info_queue+1] = {set = "Joker", key = "j_modprefix_key_alt"}
Thanks!
I deal with that a lot lmao
also
info_queue[#info_queue+1] = {set = "Joker", key = "j_modprefix_key_alt", specific_vars = {--[[your variables go here]]}}
in case your alternative key has variable slots
It did! Thanks for saving me the headaches!
I'm kinda struggling a bit with the specific_vars. Imagine my default Joker has the key of "j_mymod_joker" and I want to get the description of one of its forms. So far my info queue looks like this:
info_queue[#info_queue+1] = {set = "Joker", key = "j_mymod_joker_key1", specific_vars = {5}}
What would I need to do to grab the variables of the base Joker to fill the variable slots in the description?
card:generate_UIBox_ability_table(true)
Sorry, I don't quite understand. Where would we put this?
Would you guys know why this crashes? When I try to use the consumable and there is no more possible jokers to apply the perishable it tells me that line 37 is nil.
The joker:add_sticker and I don 'know why
first time doing things with stickers.
that is exactly what happens to joker when you pass an empty table to get a random element out of
it's nil
i want to change Judgement from its normal create a random joker effect to instead immediately create and open a buffoon pack. how do i get the game to just make and open a booster?
I have the exact card in my mod, except I have to do a lot of specal casing to make sure the opened buffoon pack doesn't corrupt another opened pack
are you sure you want that
why would it corrupt other packs?
oh, do you just prevent it from letting you use the card if you're already inside the pack screen?
the code that handles opening said buffoon pack scatters across the place, so I can't really point to an exact one
i see
question for a possibly easier solution for me. can i make a new tag that creates a normal buffoon pack and just grant one of those tags? that should just make it open the pack automatically once its safe, right?
yea, that's the easier way
I chose the hard way and believe me, it's not beginner-friendly
makes sense
ooh, I see now. Do you know how I could fix it?
I've been trying to find examples of this code in use and no luck.
local joker, pos = pseudorandom_element(available_jokers, pseudoseed('summon_perish'))
if joker then
joker:add_sticker('perishable', true)
-- your next stuff
end
okay, for now can you tell me how to just grant the existing mega buffoon pack tag and ill switch it to a normal pack later
great, thanks
it's "tag_buffoon"
Ik what I'm doing, it's my PR to SMODS anyway
it's just not big enough to be mentioned in the release notes
if you're using 1224a that is
doesnt add_tag take additional arguments
omg,omg.
It worked and I also learned that you need to put the end before the return.
thanks mr jonh
no, add_tag only takes one argument, which is the Tag object
I expanded it to also take a table, letting it do the Tag init for you
i'll just steal the code from Diet Cola's sell effect and change the key
G.E_MANAGER:add_event(Event({
func = (function()
add_tag(Tag('tag_double'))
play_sound('generic1', 0.9 + math.random()*0.1, 0.8)
play_sound('holo1', 1.2 + math.random()*0.1, 0.4)
return true
end)
}))
end```
that works too
thanks for all your help so far
Another question guys.
Do you know what's the info_queue for perishable? Can't find it.
info_queue[#info_queue+1] = {set = "Other", key = "perishable"}
it's the same for every other sticker
uuu, nice. Thanks.
It's not common to see it in mods.
umm, It makes the game crash. Do I have to enable something first?
Hold on. I think I found how to add it to the localization.
Never mind guys.
It doesn't work if you put it in localization it needs the variable and #1# doesn't work. 😭
Life
Thanks anyway for all the help you guys give though. 
how do i remove the extra space on the left and right sides of the card area objects
if i set the width to be based exactly on the number of intended cards, 2 cards stack on each other
very awesome how config.lr_padding is unused
Im even not know about existence of this one
I am considering making my own mod, how would I start?
add a few joker cards, to start
do you know what u want them to do
I have some Ideas
what should I look for. nvm
are pretty much your starting points
Cutting-edge technology goes into next level: now it's a config property which can be applied to any element
What
I'm not kidding, it's a valid string in lua
On the toml?
you prepend 2 dashes and the entire string becomes a multi-line comment
that's lua for you
So just use [[]] on the ext?
yep
why does this code create Gold cards with invisible fronts? (no rank or suit)
if context.first_hand_drawn then
local _card = SMODS.create_card {
set = "Base",
enhancement = "m_gold",
area = G.discard,
}
G.playing_card = (G.playing_card and G.playing_card + 1) or 1
_card.playing_card = G.playing_card
table.insert(G.playing_cards, _card)
G.E_MANAGER:add_event(Event({
func = function()
G.hand:emplace(_card)
_card:start_materialize()
G.GAME.blind:debuff_card(_card)
G.hand:sort()
if context.blueprint_card then
context.blueprint_card:juice_up()
else
card:juice_up()
end
SMODS.calculate_context({
playing_card_added = true,
cards = { _card },
})
save_run()
return true
end,
}))
if G.GAME.dollars > card.ability.extra.money then
card:start_dissolve()
card_eval_status_text(card, "extra", nil, nil, nil, {
message = localize("k_eaten_ex"),
colour = G.C.FILTER,
card = card,
})
end
return nil, true
end```
frost suggested i don't put it in the init, so i removed it.
i thought he meant to delete it
what do i do from here?
damn, i looked for the Certificate wording on the wiki to see if any other mods did something similar, but uhm. both of these are mine 😭
do i need both the lua and toml?
or just the lua?
lua is code, toml is patches
yes
but i'm just trying to make ROOT ACCESS write special characters in the text box
phanta or catan
Phanta
here try this
[[patches]]
[patches.pattern]
target = 'functions/button_callbacks.lua'
pattern = '''if args.key == '[' or args.key == ']' then return end'''
position = 'at'
payload = '''if (args.key == '[' or args.key == ']') and not hook.config.ref_table.extended_corpus then return end'''
match_indent = true
# why does 0 crash the game why does 0 crash the game why does
# [[patches]]
# [patches.pattern]
# target = 'functions/button_callbacks.lua'
# pattern = '''if args.key == '0' then args.key = 'o' end'''
# position = 'at'
# payload = '''if args.key == '0' and not hook.config.ref_table.extended_corpus then args.key = 'o' end'''
# match_indent = true
[[patches]]
[patches.pattern]
target = 'functions/button_callbacks.lua'
pattern = '''local corpus = '123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'..(hook.config.ref_table.extended_corpus and " 0!$&()<>?:{}+-=,.[]_" or '')'''
position = 'at'
payload = '''local corpus = '123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'..(hook.config.ref_table.extended_corpus and " 0!$&()<>?:{}+-=,.[]_'" or '')'''
match_indent = true```
typing 0 crashes the game so sadly you can't do that
ah no i didn't put those in
apostrophes yes
you can add \" to the corpus if you wanna type quotes
i used this for the 0```lua
[[patches]]
[patches.pattern]
target = "functions/button_callbacks.lua"
pattern = '''if args.key == '0' then args.key = 'o' end'''
position = "at"
payload = '''if args.key == '0' and G.CONTROLLER.text_input_hook.config.ref_table and G.CONTROLLER.text_input_hook.config.ref_table.ref_value == "setup_seed" then args.key = 'o' end'''
match_indent = true
overwrite = false
okie doke
in the payload?
mhm
i can't believe i didn't consider asking you yet
[manifest]
version = "1.0.0"
dump_lua = true
priority = 0
[[patches]]
[patches.pattern]
target = "functions/button_callbacks.lua"
pattern = '''if args.key == '[' or args.key == ']' then return end'''
position = "at"
payload = ""
match_indent = true
overwrite = false
[[patches]]
[patches.pattern]
target = "functions/button_callbacks.lua"
pattern = '''if args.key == "'" then return end'''
position = "at"
payload = ""
match_indent = true
overwrite = false
[[patches]]
[patches.pattern]
target = 'functions/button_callbacks.lua'
pattern = '''local corpus = '123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'..(hook.config.ref_table.extended_corpus and " 0!$&()<>?:{}+-=,.[]_" or '')'''
position = 'at'
payload = '''local corpus = '123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'..(hook.config.ref_table.extended_corpus and "\" 0!$&()<>?:{}+-=,.[]_'" or '')'''
match_indent = true
[[patches]]
[patches.pattern]
target = "functions/button_callbacks.lua"
pattern = '''if args.key == '0' then args.key = 'o' end'''
position = "at"
payload = '''if args.key == '0' and G.CONTROLLER.text_input_hook.config.ref_table and G.CONTROLLER.text_input_hook.config.ref_table.ref_value == "setup_seed" then args.key = 'o' end'''
match_indent = true
overwrite = false```
i believe so?
oh you changed the first pattern
it's important it only works on extended corpus mode
where exactly do i put the quotation marks
where?
also wdym by first patten
[patches.pattern]
target = 'functions/button_callbacks.lua'
pattern = '''if args.key == '[' or args.key == ']' then return end'''
position = 'at'
payload = '''if (args.key == '[' or args.key == ']') and not hook.config.ref_table.extended_corpus then return end'''
match_indent = true```
no clue 😭
okay i seriously don't get this. this code also creates rankless gold cards
if context.first_hand_drawn then
local _card = SMODS.add_card {
set = "Enhanced",
enhancement = "m_gold"
}
G.GAME.blind:debuff_card(_card)
G.hand:sort()
SMODS.calculate_context({
playing_card_added = true,
cards = { _card },
})
if G.GAME.dollars > card.ability.extra.money then
card:start_dissolve()
card_eval_status_text(card, "extra", nil, nil, nil, {
message = localize("k_eaten_ex"),
colour = G.C.FILTER,
card = card,
})
end
return nil, true
end```
HOLY SHIT WAIT
I JUST REMOVED THE FUNCTION FROM THE RETURN
IT FUCKING WORKS
THE LUA WORKS
not the toml
BUT THE LUA WORKS
old
new
looks like setting the enhancement after the card is created fixes the issue
tho idk why it makes them rankless in the first place
Looks like I can finally add this card to the Bootleg consumables, and call it something like loadstring.
ya this worked ^u^
thanks!
np
if next(SMODS.find_mod("mod ID")) then
what about if there are other mods that i dont know the mod id of?
what's your goal
i just want to detect if there are other mods enabled
i still dont know what i want with it but atleast i know earlier than later lol
if you want to check for if any mods other than your own are active, loop over pairs(SMODS.Mods) and check if there are any other than Steamodded, Lovely, Balatro, and your own mod
if you want to have any specific crossmod interactions, just go check that other mod's source code to find its mod ID lol
thank you ^^
-- =========================
-- BURNED EDITION
-- =========================
SMODS.Edition {
key = "burned",
shader = "burned",
loc_txt = {
name = "Burned",
label = "Burned",
text = {
"Gives between {X:mult,C:white}X2-5{} Mult",
"if {X:mult,C:white}X5{} Mult then destroyed.",
}
},
config = {},
in_shop = false,
pools = {},
weight = 0,
sound = { sound = "foil1", per = 1.2, vol = 0.5 },
in_pool = function(self, args)
return false
end,
calculate = function(self, card, context)
-- SCORING PHASE
if context.main_scoring and context.cardarea == G.play then
-- Reset destroy flag safely at start of scoring (So retriggers work as intended)
if context.scoring_hand and not context.retrigger_joker then
card._burned_destroy = nil
end
local roll = math.floor(pseudorandom('burned_roll') * 4) + 2 -- 2-5
if roll == 5 then
card._burned_destroy = true
card:juice_up()
return {
xmult = 5,
message = "Burned Up!",
colour = G.C.RED
}
else
card:juice_up()
return {
xmult = roll
}
end
end
-- DESTRUCTION PHASE
if context.destroy_card
and context.destroy_card == card
and card._burned_destroy then
return { remove = true }
end
end
}
I was wondering why when this gets retriggered and one of its trigers is the x5 and it says burned up it does not get removed at the end of the hand?
context.destroy_card is only for playing cards
also you shouldn't need to reset the destroy flag if it's intended to be immediately destroyed anyway
thats what makes retriggers not work
I think I figured it out:
if context.before and context.cardarea == G.play then
card._burned_destroy = nil
end
Is the new code
how would I destroy the card then?
why are you resetting the flag at all
either it doesn't roll x5 and it's still nil, or it did roll x5 and it's destroyed before you get around to resetting it
just call SMODS.destroy_cards(card) in context.after
Still confused about this if someone can help give clarification
how do i made it so you can actually draw this card in your hand? right now it adds a card to my deck but i can't draw it in that specific round
G.E_MANAGER:add_event(Event({
func = function()
local _card = create_playing_card({
front = pseudorandom_element(G.P_CARDS, pseudoseed('cert_fr')),
center = G.P_CENTERS.c_base}, G.deck, nil, nil, {G.C.SECONDARY_SET.Enhanced})
_card:set_ability(G.P_CENTERS.m_omega_sigil)
return true
end}))
playing_card_joker_effects({true})
end```
card:generate_UIBox_ability_table(true) returns the card's loc_vars as a table.
Ok, so in my example, where would I place this?
For cards you want to add to the deck but also want to draw the same round, you want to add them to G.discard.
that.. makes no sense, then it just goes to the discarded pile never to be drawn in that round
table.insert(info_queue, {set = 'Joker', key = 'j_modprefix_key', specific_vars = card:generate_UIBox_ability_table(true)})
Thank you
Apologies, was thinking of marble Joker which just adds them when entering the blind which seems to be similar to your effect of the first hand drawn
You should be using SMODS.add_card instead of create_playing_card
and how do i add it to my deck with an enchancer? (also the suit and rank doesn't matter since the enhancer has no suit or rank)
SMODS.add_card({set = 'Playing Card', enhancement = 'm_omega_sigil', area = G.deck})
ok either im getting astronomically unlucky, or you can't draw cards added to the deck at the start of the round🙏
what context should i use instead of context.first_hand_drawn?
first_hand_drawn happens after the hand is drawn so that would be the issue
you should use context.setting_blind for the same timing as marble joker
OK yes that worked thank you
also another quick question, how do i make an enchancement remove itself (the card) at the end of round?
if context.end_of_round then
remove = true
end
end``` this didn't work
that's not how that works
what you've done there is set the global variable remove to true
also returning remove = true in an arbitrary context doesnt work
plus its playing_card_end_of_round for playing cards, which also only triggers when it is held in hand
yeah i figured, i also tried card:remove() and self:remove() but those also didn't work since the calculate function of an enhancer only activated when a card is in the hand
not in the deck
so idk
use SMODS.current_mod.calculate
And loop over G.playing_cards to remove all cards with the enhancement
In context.end_of_round there
outside of the enhancement calculate
SMODS.current_mod.calculate just allows you to run calculate code globally and not tied to an object if needed
like this?
if context.end_of_round then
if G.playing_cards then
for _, playing_card in ipairs(G.playing_cards) do
if SMODS.has_enhancement(playing_card, 'm_omega_sigil') then
playing_card:remove()
end
end
end
end
}```
Yeah
You might want to add all of them into a table and then call SMODS.destroy_cards on that though
So you get the destruction animation
it's crashing tho
Oh
Try also checking for context.main_eval
Ig
Oh wait
You didnt make it a function...
java ahh
Or whatever language does code blocks like that idk
Here is the Example Joker definition, fully fleshed out. In my example, I am trying to get the info queue of the other forms it can have. When viewing it when it is set up like this, it gives me a nil error because it can't find the table. How can I make it grab the table of the original Joker?
like adding a local "something something" = SMODS.current_mod.calculate{?
What is line 3069 in functions/common_events.lua?
I'm not sure. Is there an easy way to view that file after it has been modified at run time?
Mods/lovely/dump/functions/common_events.lua
Thank you so so so much!
How do I reroll a boss blind without using up Director's Cut
local thunk = G.GAME.round_resets.boss_rerolled
G.FUNCS.reroll_boss()
G.GAME.round_resets.boss_rerolled = thunk
Thanks!
Lines 3066 to 3070 are:
if not card then
local ability = copy_table(cfg)
ability.set = 'Joker'
ability.name = _c.name```
if you want to account for the possibility of having previously used director's cut, store the variable first instead of setting it to false unconditionally
What does G.GAME.spectral_ratemodify?
The pack weight?
no, i think it's the weight for spectral cards to appear in the shop
(so 0 most of the time)
Makes sense. Do you know if there is any way to modify spectral pack rate?
don't think there's anything as easy as doing it for the cards themselves in shop
you'll probably have to patch into the code where the shop creates the packs and add a rate value you can change
get_weight = function(self)
if G.GAME.stake >= 5 then
return self.weight * 2
end
return self.weight
end
}, true)```
I had been using this and it works, but the problem I have with it is that I can't get it inside of a stake.
So I assume that if the player has other mods that modify the stake it won't be able to override it.
Actually, do you know if I can make it so the player can "turn off" the lua with a config change.
Does it make sense.
This set me back a round somehow? Like, I was in the shop headed into the boss blind and I'm now back at the Small Blind
calculate = function(self, card, context)
local end_of_ante = context.end_of_round and context.game_over == false and context.main_eval and
context.beat_boss
if end_of_ante and not context.blueprint then
card.ability.extra.rerolls = card.ability.extra.rerolls_max
return {
message = localize('k_reset'),
colour = G.C.GREEN
}
end
if context.before then
if card.ability.extra.rerolls > 0 and next(context.poker_hands["Flush"]) and G.GAME.blind:get_type() ~= "Boss" then
return {
message = localize("j8mod_flushed_ex"),
colour = G.C.GREEN,
func = function()
card.ability.extra.rerolls = card.ability.extra.rerolls - 1
G.from_boss_tag = true
local thunk = G.GAME.round_resets.boss_rerolled
G.FUNCS.reroll_boss()
G.GAME.round_resets.boss_rerolled = thunk
end
}
end
end
end
code for context
additionally, I'm curious if the boss blind can be rerolled during a boss blind
rerolling outside the select screen is kinda jank
if you reroll in the middle of the blind it would do nothing afaik
if you put it in calc_scaling it will create an infinite loop since thats the function scale_card calls
you are meant to put that in calculate
you can work with this, just a few changes needed.
- hook the function instead of straight up overriding it and use the old result in place of self.weight
- get the value from a function you define on the stake and defer to that instead of I lining it to the booster get_weight function
check if the stake is active based on a flag you set when the stake is applied instead of using stake_level, too
it's unreliable because stakes can branch
you should also search for Game.draw just in case
good point, no results
I guess we'll figure out where to put all this code inside PR, I'll create it as draft first
Biggest concern I have is this specific patch
it works but it feels somewhat wrong
thunk
how do i make a clone a joker
Apparently the issue was that the priority was a really high value
I set it to -1 and it works well
local function better_copy_card(card, new_card, area)
if not card then return nil end
local area = area or (new_card and new_card.area) or card.area or G.jokers
local cardwasindeck = new_card and new_card.added_to_deck or nil
local copy = copy_card(card, new_card)
if new_card and cardwasindeck then copy:remove_from_deck() end
if card.playing_card then
G.playing_card = (G.playing_card and G.playing_card + 1) or 1
copy.playing_card = G.playing_card
G.deck.config.card_limit = G.deck.config.card_limit + 1
table.insert(G.playing_cards, copy)
end
if (new_card and cardwasindeck) or not new_card then copy:add_to_deck() end
if not new_card then area:emplace(copy) end
return copy
end
better_copy_card(card)
checking in on this, savign the boss_rerolled thing still sets me back to the beginning of the ante
??????
oh
wait nvm
im stupid
okay why is this extremely janky
it starts drawing cards extremely slowly
and theres a ghost card in there
for some reason
and it doesnt even draw a full hand
okay it appears to only do that after a discard
which is good because i only want it to trigger after hands
still wonder why it did that though
i just find it wierd that its only on discard
janky hack mate
what
Really weird issue: my calculate function works fine if I spawn in my consumable card via DebugPlus, but spawning it in using add_card within another consumable just doesn't trigger calculate at all.
The other card spawning this one puts it in a separate custom CardArea. Dunno if that has anything to do with it potentially?
The one in the default consumable area reaches both calculate and before prints, but the one in my custom CardArea reaches neither
You need to use a lovely patch to make your custom cardarea to work with calculate (replace cardarea below with your custom one)
[[patches]]
[patches.pattern]
target = '=[SMODS _ "src/utils.lua"]'
pattern = '''-- TARGET: add your own CardAreas for joker evaluation'''
position = "before"
payload = '''
if cardarea then
table.insert(t, cardarea)
end
'''
match_indent = true
What is this supposed to do?
Draw an extra card after hand for each held 8
It works fine after a hand but not after a discard
Discard isnt relevant for my purpose but it happened while i was testing because i forgot a check
Hmm I wonder if discarding uses a different draw function
Haven't worked with patches yet, how do I use this?
All I know about them is that they're related to .toml files, I think
yeah you would make a file in your mod folder called lovely.toml , vanillaremade explains it pretty well
https://github.com/nh6574/VanillaRemade/wiki#whats-a-patch
You could also hook SMODS.get_card_areas
or make a folder called lovely with the patch files in there
If you want to actually organize the patches
true
Nice, this worked! Now they're both marked as "Complete"!
This is what I ended up doing
Anyhow, thanks people 
going ahead and planning out my mod before working on it, what do you think about this?
select_music_track = function(self)
if joker_main == G.GAME.blind then
return 1337
end
end
})
just since it's been a fairly common issue with some of my Jokers here and there, is there any way to update a card's edition/enhancement/etc. mid-scoring without it counting as the previous edition
i.e. turning a stone card into a glass card, and a retrigger has it count as glass instead of stone
Yes, don't do it in an event.
that tracks, yeah
progress on blind ideas (for the must play a X card, i might have to see if i can make where it will only appear in pool if you have it in your deck to prevent decks like abandoned and checkered from being screwed)
Doing so with Stone Cards becoming other cards makes them immediately show off their rank when playing while still being a Stone Card
is there any way i could make the front invisible before it upgrades?
Hook Card:should_hide_front
gotcha
fwiw, this does happen in vanilla too iirc- if you play stone cards while you have vampire, the front appears before the enhancement visually disappears
it's less relevant with vampire tho because the enhancement is removed before cards score
formatted it better, im going to get something to eat
Does anyone have an example of drawing a sprite ontop of a joker? I want to draw depending on a joker card's ability but I can't seem to wrap my head around it
local oldmainmenu = Game.main_menu
function Game:main_menu(change_context)
local g = oldmainmenu(self, change_context)
G.shared_sprite = SMODS.create_sprite(0, 0, G.CARD_W, G.CARD_H, 'modprefix_atlaskey', {x = x, y = y})
return g
end
SMODS.DrawStep{
key = 'key',
order = -9,
func = function(self)
if self.ability.condition then
G.shared_sprite.role.draw_major = self
G.shared_sprite:draw_shader('dissolve', nil, nil, nil, self.children.center)
end
end,
conditions = {vortex = false, facing = 'front'},
}
Thank you! It seems my hook to the main menu fails though (attempt to index nil field shared_sprite), is the jokers lua file the wrong place to do all this?
You can call G.shared_sprite whatever you want, specifically the "shared_sprite" part (and honestly should be renamed), and this hook should be done in whatever your main file is as defined by your metadata .json
