#💻・modding-dev
1 messages · Page 693 of 1
how can i detect the editions and stickers of jokers, and then remove/ shuffle said stickers and editions?
if context.individual and context.cardarea == G.play then
local suits = {}
for k, v in pairs(G.playing_cards) do
for kk, vv in pairs(SMODS.Suits) do
if v:is_suit(vv.key) then
suits[vv.key] = (suits[vv.key] or 0)+1
end
end
end
local suit, count = 'Spades', 0
for k, v in pairs(suits) do
if v >= count then
suit, count = k, v
end
end
if context.other_card:is_suit(suit) then
return {xmult = 1+(0.1*count)}
end
end
how do i make custom ui for a watermark for a demo of my mod? [i need full script thx]
the ever-reliable video editor
okay cool also had to fix the localization shit being wrong and now it's good to go
might nerf it to 0.05x per ngl
local modifiers = {}
for k, v in pairs(G.jokers.cards) do
if v.edition then
table.insert(modifiers, {edition = true, key = v.edition.key})
v:set_edition(nil, true, true)
end
for kk, vv in pairs(SMODS.Stickers) do
if v.ability[vv.key] then
table.insert(modifiers, {sticker = true, key = vv.key})
v:remove_sticker(vv.key)
end
end
end
pseudoshuffle(modifiers, 'seed')
for k, v in pairs(modifiers) do
local eligible_jokers = {}
for kk, vv in pairs(G.jokers.cards) do
if (v.edition and not vv.edition) or (v.sticker and not vv.ability[v.key]) then
table.insert(eligible_jokers, vv)
end
end
if next(eligible_jokers) then
local joker = pseudorandom_element(eligible_jokers)
if v.edition then
joker:set_edition(v.key)
end
if v.sticker then
joker:add_sticker(v.key, true)
end
end
end
Why the fuck is this here? I set its weight to 0. (This is supposed to be a Challenge-exclusive version of another Joker.)
per-object weights only work if you enable the optional feature
add this to your mod (just in the main lua file or whatever)
SMODS.current_mod.optional_features = {
object_weights = true
}
i'm looking into global variable shenanigans and one modpack i'm seeing has their global variables and functions all in a functions.lua file. is having a separate file for global variables necessary or can i just define them in a standard joker.lua file?
oh sweet
You should be doing in_pool = function(self, args) return false end instead of weight = 0
You can define them anywhere.
im talking about IN GAME
do loc_vars have to start with card.ability.extra.xxx?
no
you can put just about anything
even non-existent values, in which case it gives nil in the description
second question, i'm trying to have some variables that are just for the description of the card and i'm getting errors when i try to do this (it's the commented out lines). where should i instead do the arithmatic so that it doesn't throw an error?
i'd do it in loc_vars before the return
the code in loc_vars runs when the joker is hovered over
you were trying to execute code inside table definition, which doesn't work of course
would this work then?
No, the problem is those variables don't exist.
ah, you mean num_inc and denom_inc, which lua consider globals instead
update: no, they're showing as nil values
loc_vars = function(self, info_queue, card)
card.ability.extra.num_ex = card.ability.extra.num_inc + 1
card.ability.extra.denom_ex = card.ability.extra.denom_inc + 4
return {vars = {card.ability.extra.num_ex, card.ability.extra.denom_ex}}
end
yea, you got the wrong idea when I said you can put anything
so in this case, i do need to use the card.ability.extra prefix?
anything works, even globals
for local storage inside the card, refer to card.ability
stuff in config (prototype values) gets copied over to card.ability (modifiable values)
i replaced my loc_vars with this, and now every value in my description is returning nil
ah, I forgor
the return values were remnant code from my previous interpretation
there, try again
i still have nil values in the description
yeah
yikes, the above code would not respond to SMODS' probability mechanic
ahh
i'm gonna try putting the arithmatic calculations in the set_ability function, maybe that'll work?
set_ability is called once upon card creation
so that wouldn't work then?
keep it in loc_vars
when changes are made in calculate, just update the values again
Is it worth the effort to make only the rekoj inside grade 10 to have the edition visual applied if possible
is it a separate draw layer
then it wouldn't be so hard to do
another DrawStep should easily do it
my enhancement doesn't give Xchips when in hand, even though it's supposed to do that, can someone help?
Remove calculate and move h_x_chips out of extra
ah ok
how can I remove enhancements and seals from cards held in hand after pressing play, for a blind qwq
does doing get_suit() on a wild card always return "true" or does it only return true if the original card was that suit?
I'm trying to make the base blind size scale slower so that on ante 8 the base is 25,000 but it didn't work
The base is 570 on ante 8 rn
Which is definitely not what I wanted

Is the (G.GAME.modifiers.scaling or 1) - 0.5 the wrong move
press_play = function(self)
G.E_MANAGER:add_event(Event({func = function()
local triggered = false
for _, v in ipairs(G.hand.cards) do
local has_modifier = false
if v.config.center.key ~= 'c_base' then
triggered = true
has_modifier = true
v:set_ability('c_base', nil, true)
end
if v.seal then
triggered = true
has_modifier = true
v:set_seal()
end
if has_modifier then
G.E_MANAGER:add_event(Event({func = function()
v:juice_up()
return true end }))
end
end
G.GAME.blind.triggered = triggered
return true end}))
return true
end

_ _
No, it should be v.config.center.key ~= 'c_base' instead of next(SMODS.get_enhancements(v))
If you mean Card:is_suit then yes, it does, unless it is debuffed.
G.hand is all the cards held in hand, right? if i have a joker that does money calculations at the end of round (akin to golden joker, delayed grat, e.g.), does G.hand still work?
gotcha, thanks
No, because the cards would be in the deck.
oof

thanks
you can save the number in context.end_of_round and then use it later to give the money
I'll try this, thanks!
yeah, that's what i'm gonna do
whats an easy solution here to prevent this jokers from "eating" an edition when it randomizes the editions of cards
Remove base from the possible editions applied
not quite what i did, but got it working so it doesnt matter
apologies for my very uncondensed coding, but i'm running into an issue where it seems my variable card.ability.extra.largest always is 0 when i get to the money calculation. i'm thinking it's either a syntax issue, a variable issue, or a flaw in my logic
ipairs(G.hand.cards)
hooray, thank you
G.hand is just the area, and G.hand.cards is referring to the cards themselves
i'm learning lol
So I'm currently trying to make a custom back. When I start a run with it, the blinds don't pop up so the game is softlocked. I'm guessing the problem is with the events I'm trying to have happen. The consumable I want is also not appearing. Do I need to add an event for that as well?
without opening the file i guess the event doesn't return true
opening the file i see the event doesn't return true :3
yes, the function of the event should return true
if it doesn't then it keeps running
oh that makes sense
thank you
yep sure enough adding the line worked.
thanks again
I love how tutorial utilizes this for pausing quips and waiting for human inputs
yeap, works just as is, thank you :D
ok so for context:
i have no idea what im doing
i am literally using jokerforge as a base cause i dont know what im doing
ive never touched coding like properly ever
anyway why is this destroying all the jokers instead of just one
i am literally using jokerforge as a base cause i dont know what im doing
i ould
would heavily recommend you do not do this
jokerforge's code uses so many unneeded redundancies because of its nature
a h
it teaches bad practice
Might I suggest #1486847115127947374 instead of JF?
alright good thing it was caught ahead of time
vanillaremade s a great resource for code references
but you can just look at other mods' code
VanillaRemade is also great
Yup lol
it's pretty easy to pick up
It is, Lua is a very good beginner language, and Balatro is an easy game to mod relative to other games
Give a modder a jokerforge and they code a joker for a day
teach a modder to code and they make jokerforge
should I be using events or the initial_deck function to reduce the number of starting cards in a deck?
Probably initial_deck
ok so if i wanted to remove an entire suit what would that look like?
would it be
initial_deck = {
suits = {'Heart'},
exclude = true
},
That looks right aside from “Hearts” needing to be plural
ah yes I've since fixed that
hmm when I run it like this the deck still contains all suits
Where is your initial_deck being set? It shouldn’t be in a function or anything, it should just be an attribute of your SMODS.Back, much like a config table
I believe I have it as an attribute
well next I'll disable other mods
thank you for helping make sure my formatting was correct
👌
your beginner video guides were also most helpful
Very glad to hear people are getting the most out of those. I really need to get onto adding more episodes, this damn event mod just been taking up too much of my time lol
ok I disabled everything and it still doesn't work but it's pretty late I'll try more tomorrow
still no clue how to change the blind icon
i can change it if i reload the blind
but its always one off
and i can never change it back to the original
i removed the code because it didnt work but
like
i cant figure ts out
😭
bump
Is there a way I could do a “take “ feature like how there is in cryptid
In booster packs
how do i make these things appear
hi i was making a joker that transforms into another joker and it gets a flip animation in between, the thing is that i wanted to make the joker stay flipped during like 2 secs how could i do it?
this is what i have now
select_card = "consumeables" in the booster pack
use events
if context.after then
local percent = 1.15 - (1 - 0.999) / (1 - 0.998) * 0.3
G.E_MANAGER:add_event(Event({ -- flip to back
trigger = 'after',
delay = 0.15,
func = function()
if card.facing == "front" then
card.genuine_flip = true -- flag to indicate this flip belongs to this effect
play_sound('card1', percent)
card:juice_up(0.3, 0.3)
card:flip()
end
return true
end
}))
G.E_MANAGER:add_event(Event({ -- transform
func = function()
card:set_ability('j_pjok_elevado')
card:set_cost()
SMODS.calculate_effect({message = localize('k_transform') --[[you used hardcoded text in non-English, which isn't recommended]], sound = 'pjok_elevado_sound', instant = true}, card)
return true
end
}))
G.E_MANAGER:add_event(Event({ -- flip to front
trigger = 'after',
delay = 0.15,
func = function()
if card.genuine_flip then -- check the flag instead of card.facing
card.genuine_flip = nil
card:flip()
play_sound('tarot2', percent, 0.6)
end
return true
end
}))
end
oh wow thank you so so much
im not really used to work with events
thanks :)
okay i customized a little bit and its woking perfectly!! thanks again!!
havent modded in a while, how do i load all the files from a specific folder?
in my case a "decks" folder
check the bottom of that question
need these because they carried me in learning luau
which is lua but in roblox studio
Assuming you're using VSCode or a derivative of it, you'll need to install the Lua extension by sumneko
I think
its been about an hour since i started trying to learn modding and its not even showing my mod in balatro let alone the mod launcher i use
🥹
what did i do wrong....
i assume you see the mods button?
do you have a .json in your mod folder
yes
can you post it
hmm can you post the latest log in lovely/log
Mods/lovely/log look for the one with the latest date
ah lol
LMAOO
didnt notice
okay NOW it appears
the fact i went that long without noticing is a crime
yayyyy it work
and the custom icon too
I tried making a fortune teller for spectral cards and it upgrades and adds the chips but it doesn't score, I used the fortune teller code for the base but idk qwq
yup
ok wait
can you post the whole thing
i downloaded it now
oh wait i didnt know vanilla remade adds the library for smods too
smods adds the library for smods, vanillaremade has a guide
i was a little too lazy to set it up
yesh
name = "Mermaid",
text = {
"{C:chips}+20{} chips per {C:chips}spectral{}",
"cards used this run",
"{C:inactive}(Currently {C:chips}+#1#{C:inactive})"
}
},
calculate = function(self, card, context)
if context.using_consumeable and not context.blueprint and context.consumeable.ability.set == "Spectral" then
card.ability.extra.chips = card.ability.extra.chips + card.ability.extra.chip_mod
return {
message = localize('k_upgrade_ex'),
colour = G.C.CHIPS
}
end
if context.joker_main then
return {
chips = card.ability.extra.chip_mod * (G.GAME.consumeable_usage and G.GAME.consumeable_usage.spectral or 0)
}
end
end,```
you need to return the value you're scaling
chips = card.ability.extra.chips
will that account for spectrals used before buying the joker?
how would i make a deck that selects 13 random cards and turn them into a (weighted) random edition?
and with weighted i mean like the wheel
bwehhh
i think it is G.GAME.consumeable_usage_total.spectral
but then you need to not scale a value
which part are you having problems with
the part where i make the deck lmfao
i pretty much forgot all the previous knowledge i had
well im not making it for you, i can point you out to guides depending on the speficic knowledge youre lacking
apply = function for i,v in g deck cards do v: set edition(poll edition{guaranteed = true})
something shaped vaguely like that
like do you know how to make a basic deck
i guess yeah
(that is not valid Lua syntax do not copy paste that)
mostly it's the card selection and editioning along with the formatting of the code
is there like an easy way to hook functions for boosters with take_ownership_by_kind like with regular taking ownership
also just to be sure take_ownerships run after other injection right
for the editioning i could just use wheel's code probably but idk how to rngselect
random selection: https://github.com/nh6574/VanillaRemade/wiki#how-do-i-get-a-random-numberelement
random edition: https://github.com/nh6574/VanillaRemade/wiki#edition
this bit of code is giving me some trouble. when a joker is added, i want to iterate through all the jokers in your possession and give them the eternal tag. i think the problem is with my for loop because i'm not doing anything with the jokers variable at the moment
because youre checking for two contexts that dont happen at the same time
context.check_eternal is unrelated to actually applying the sticker
I think I didn't use the total cuz it gives a nil value for some reason
poll_edition uses the regular weights, yes
you want to be doing jokers:add_sticker("eternal", true)
it will be nil when no spectral is used im pretty sure
so that's different than no_destroy = true? when would you instead use that?
when you want the joker to act like its eternal at a specific moment without having the sticker
yes
gotcha
it's crashing tho ; ~ ;
show code and log
key, value
key is a number in this case while value is the card
i should give them better names and use ipairs, i think thats just copied from vanilla
for _, jokers in pairs(G.jokers.cards) do
if context.check_eternal == true then
jokers:add_sticker("eternal", true)
end
end
end```
it's still not working. and just fyi i do know that check_eternal just checks whether a joker CAN have an eternal sticker, not if it currently does
card_added is the correct context though, right?
consumeable_usage and consumeable_usage_total are two different values
youre checking for the former when you should be checking the latter
context.check_eternal does not check that
its for checking when a joker is being checked if its considered eternal
which is not relevant here
i forget whats used for checking sticker compat though
so how would i make this only select 13 to convert?
joker.config.center.eternal_compat
make a copy of the list with all the cards and then select 13 from it while removing the indices
or select 13 different numbers in the range of 1 to 52 and index those
bump 🥺
elaborate?
on what
i have no idea what you said
do you know what a table is
how do i check if the joker is a specific joker
like if its brainstorm it do the thing
G.jokers.cards[i].config.center.key == whatever key
do you know what an array is
before I had everything as total and it would still crash but now I changed everything back to total and it worked fine??? I mean if it works it works but I completely missed what happened qwq
ok yeah i do
is the key a string or
it is right
well G.playing_cards is an array with indices 1 to 52 for all the cards (at the start without modifying the deck)
you can pick 52 different numbers that correspond to 52 different cards
so you want 13 of those
yep
what's the part that you're having problems with then?
lua formatting
yeah
i gave you a link?
right
you are missing a couple of ends
Looks like it's missing a few ) too I can't help but notice
for _, jokers in ipairs(G.jokers.cards) do
if joker.config.center.eternal_compat == true then
jokers:add_sticker("eternal", true)
end
end
end```
what's the correct way to format this?
jokers.joker.config.center.eternal_compat?
no, just jokers.config.....
like this?
the last } should be an end too
and the end one line above that should be }))
because you have parentheses without closing for the event
There's a missing in keyword I'm pretty sure
oh yeah
Before ipairs
Also I was gonna ask how would I go around to disable cards from scoring via a joker
like this?
like make them unscore (like anti-splash) or make them debuffed?
Yea
do packs default to using vanilla Card:open or whatever if the create_card function exists but return nothing
Antisplash
ok wait i added another } after end and now there's no errors
so this would make all clubs have an edition right?
i dont think so
no, you are polling a random enhancement and doing nothing with it
fuuuuuuuuuuck
okay so
how can i make packs run the original thing anyway
after take ownership does its thing with the function
So would I have to use context.evaluate_scoring_hand and chuck all of the context.scoring_hand contents?
Or something along the lines
are my links broken
?
I mean you sent calculate functions
this one
i read past it lol my bad
for _, jokers in ipairs(G.jokers.cards) do
--if jokers.config.center.eternal_compat == true then
jokers:add_sticker("eternal", true)
--end
end
end```
alright, i found the source of my issue. even with the eternal_compat filter removed, the code never seems to run the loop. or if it does, it's not giving the stickers. do i just have my for loop set up wrong?
I'm making a thing that optimizes retriggers by instead of executing each retrigger individually it only executes one and then the values are multiplied by the amount of retrigger
the way I'm doing it currently for card retriggers(example: hanging chad) is checking context.other_card and adding the last retriggers of that card to the current joker
could checking only for context.other_card for adding the retriggers glitch something?
just to be sure, you want all jokers to be eternal with this card is bought/added?
or when any card is added
right now, i'm just trying to have all jokers become eternal when you acquire them. ideally, i'd want all your jokers you already have to become eternal when you buy this one, but i hadn't gotten there yet
OHHHH
I JUST FIGURED IT OUT
when you buy a joker, it's not included in the set
so i'll need to include that newly bought joker in with the set
yeah, you can also use an event
should i just put my whole loop in an event then?
yes
well this doesnt work
just trying to make it apply editions rn
nvm i got it
your sources lied to me smh my head
no
it said card:set_ability which crashed
playing_card:set_ability worked tho
i linked to that
well thats on you lol
card is a generic name
i read the wrong thing 😭
it would be whatever name you give the variables
does context.buying_card only trigger if it's bought from the shop? if this card were to be spawned randomly via tarot card, would it go off?
no, thats what card_added is for
ahh, i imagine adding in a card via debug mode wouldn't trigger card_added then lol
i think it does
can i add a line break to the deck name in localization?
im pretty sure yes
works nicely, is it normal for it to ignore debuffed cards tho
interesting
so what should i do then, just give it a different name?
no worries
ok so uhh
when i select the deck it doesnt let me play once i start the run
the event has to return true, otherwise it runs again next frame
anyone know why this doesn't remove suits from a deck?
initial_deck = {
suits = { 'Clubs', 'Hearts', 'Spades', },
exclude = true
},
has to be Suits uppercase iirc
oh like all caps?
i think i fixed the docs yesterday
set_edition has a silent parameter somewhere
Suits
read the message again
ooooh
that worked thank you so much :)
honestly, i will just make smods take both
hm? where?
i think that the uppercase one is weirdly inconsistent
don't recall offhand, check the function definition
in the vanilla code, probably, unless smods hooks it
ok now how do i make it select 13 random cards instead of only clubs
there's nothing built-in for this, but what i'd do is pick 13 unique random numbers from 1 to #G.playing_cards and then check if the index variable is equal to any of those numbers
(the index being the underscore in for _,playing_card in ipairs, i would rename this since you're actually using it now)
huh so what do i do?
you got explained the same thing by two different people, if you want more guidance you will need to be more specific
or do you just want it coded for you
can i have some more guidance
also i'm sorry if i'm a little- stupid for a lack of better words
i dont mean specific about wanting guidance lol, i mean specific at what you're confused about
not sure how to code the random cards thing
i think so yeah
holdon lemme try smth
this deck wouldnt need any loc_vars right?
are those just for tooltips?
i do think this is something you should take a crack at on your own first, a very important part of writing code is being able to break down a big task like this into smaller subtasks and then write the code for each block
the loc_vars function is for tooltips and any text in the description that you want to be a variable instead of hardcoded
yeah i'll try, i'm just confused sometimes on what specific things mean
so stuff like the chip count on ice cream
ye
could you help me with the subtasks?
no idea where to start lol
first step would be to, as mynty said, pick 13 random numbers and make sure they're all different from each other
alright
i uh,. dont know how to do that actually
i could probably make it pick 13 random numbers but idk how to make it so theyre all different
yeah no i have no idea how to start lol
not sure if someone writing it for me and then me reading through it to understand would help
i feel like to do this i could make an array with all cards, and then pull 13 from them
though i have no idea how to actually translate it into code
this is how i would so this
G.E_MANAGER:add_event(Event({
func = function()
local all_cards = SMODS.shallow_copy(G.playing_cards)
for i = 1, 13 do
local chosen_card, chosen_index = pseudorandom_element(all_cards, "seed")
if chosen_card then
local random_edition = SMODS.poll_edition({ key = "modprefix_seed", guaranteed = true, no_negative = true } )
chosen_card:set_edition(random_edition, true, true)
table.remove(all_cards, chosen_index)
end
end
return true
end
}))
copies the table without copying the tables inside
basically so you dont remake the cards inside G.playing_cards
exactly like this loop you have
neat
thanks for the help!
sorry if i was difficult to work with lol i still have a long way to go
how do it work for rarities
oh wait
its 1 not r_common
i think
bump
EXTREMELY IMPORTANT BUMP
How do you code decks?
So, why won't this work? Doesn't crash the game, just doesn't show up
is the file loaded
What does that mean again?
Where do I put that into my code?
your main file
oh yeah that page exists
Thanks
would a modded pool with vanilla jokers look like this?
SMODS.ObjectType {
key = 'lennypool',
default = 'seltzer',
cards = {'seltzer', 'diet_cola'},
inject = function(self)
SMODS.ObjectType.inject(self)
end,
}```
No, it should be j_key
it also has to be j_selzer because thunk moment
ight
local joker_card = SMODS.add_card({ set = 'shit_lennypool' })
so this would look like this?
if i wanted to create one of the two jokers?
No, SMODS.ObjectTypes don't have mod prefixes.
oh ight
key = "lenny",
config = {
extra = {
}
},
loc_txt = {
['name'] = 'Lenny Leonard',
['text'] = {
[1] = 'If {C:attention}Glass Card{} breaks in {C:legendary}The Eye{}{} {C:attention}Boss Blind{},',
[2] = 'Create a {C:dark_edition}Negative{} {C:attention}Diet Cola{} or {C:attention}Seltzer{}.',
[3] = '',
[4] = '{C:inactive,s:1.2}(Ow my eye, I’m not supposed to get {C:attention,s:1.2}[Glass Card]{}{C:inactive,s:1.2} in it!){}'
},
['unlock'] = {
[1] = 'Unlocked by default.'
}
},
pos = { x = 0, y = 0 },
cost = 20,
rarity = 4,
blueprint_compat = false,
eternal_compat = true,
perishable_compat = true,
unlocked = true,
discovered = true,
atlas = 'lennybg',
pools = { ["shit"] = true },
soul_atlas = 'lenny',
soul_pos = { x = 0, y = 0 },
in_pool = function(self, args)
return (
not args
or args.source ~= 'sho'
or args.source == 'buf' or args.source == 'jud' or args.source == 'rif' or args.source == 'rta' or args.source == 'sou' or args.source == 'uta' or args.source == 'wra'
)
and true
end,
calculate = function(self, card, context)
if context.remove_playing_cards then
if SMODS.get_enhancements(removed_card)["m_glass"] == true and to_big(G.GAME.blind.config.blind.key) == to_big("bl_eye") then
return {
func = function()
if #G.jokers.cards + G.GAME.joker_buffer < G.jokers.config.card_limit then
G.GAME.joker_buffer = G.GAME.joker_buffer + 1
G.E_MANAGER:add_event(Event({
trigger = 'after',
delay = 0.4,
func = function()
play_sound('timpani')
SMODS.add_card { key = "shit_lennypool" }
card:juice_up(0.3, 0.5)
return true
end
}))
end
return true
end
}
end
end
end
}```
im having issues is there something wrong with it
SMODS.ObjectType {
key = 'lennypool',
default = 'j_seltzer',
cards = {'j_seltzer', 'j_diet_cola'},
inject = function(self)
SMODS.ObjectType.inject(self)
end,
}```
removed_card doesn't exist also it should be j_selzer
ight
what should the if SMODS be then
with the m_glass
Does anyone know why my deck won't show the text?
the first line in your first screenshot should be Back = {, singular
not "Backs" plural
Tried that, still doesn't work
could you post your full localization file
why is apply inside of 2 tables
here
i mean just post the file lol
anyway the Back table is supposed to go inside the descriptions table, it's currently coming after it
Oh, thanks
Am I not supposed to use the {{?
no 😭
I tried it, it works
oh
the apply is ignored
yeah
ok
oh, yeah, that's it
yeah thats just to comment it out
Oh, that makes more sense
Just fixed it, thank you
does a higher weight number make an item rarer or more common?
common
this crashes with Cryptid's consumable-ized cards, seemingly due to the can_use function not properly accounting for the consumable itself being a playing card but I don't know how to do that
and the crash log from trying to use it on itself (which is the only thing it allows in that context)
can_use = function(self, card)
if card.area ~= G.hand then
return G.hand and #G.hand.highlighted > 0 and #G.hand.highlighted <= card.ability.max_highlighted
else
return G.hand and #G.hand.highlighted > 1 and #G.hand.highlighted <= card.ability.max_highlighted+1
end
end
does context.joker_type_destroyed refer just to destroying or does it also happen when a joker is sold?
sold is different than destroyed
and it also checks consumables
so if i wanted to know if a joker got sold or destroyed, i'd have to use 2 different contexts then
ok gotcha
what would that be?
card.ability.set == 'Joker'
if i want to check if the card being sold or destroyed is itself, would using context.card work for that?
check the wiki
the wiki says it should, but i'm a bit confused as it seems context.card is listed a lot
Yes.
if card.ability.set == 'Joker' then
if context.card ~= true and context.selling_self ~= true then
G.jokers:change_size(1)
card.ability.extra.extra_slots_given = card.ability.extra.extra_slots_given + 1
end
end
end```
i have this right now, however, it seems that it is ignoring the selling self and context.card line
i think i'm just using these incorrectly
context.card is never true, because it's either a table or nil
instead of checking something ~= true you should just do not something
if (context.joker_type_destroyed or context.selling_card) and context.card.ability.set == 'Joker' and context.card ~= card
For some reason this shader makes all #FFFFFF transparent
ahh, i see now
is there a way to determine what boss blinds can appear on a challenge
like only the debuff bosses (example)
You can disable all other blinds if need be
Basically lol
what's the best way to move a card from one card area to another? for example, i have a card in G.hand that i want to move to G.discard
isn't it G.hand:emplace ,? I haven't mod in a while
draw_card(G.hand, G.discard, 90, 'up', nil, card)
thank you!
makes sense oops
thank you!!
could i somehow pull the 8 here into a loc_vars so i can access it in the description?
You would make it a variable in config then put that in loc_vars
for some reason every time i start up balatro it doesnt save my progress
typically I base the object off of its name
just a question but uhhh
how do i make high res textures in balatro for a texture pack
high resolution textures r just the original ones upscale from 71x95 to 142x190 no changes
and they go into 2x folder instead of 1x
initial_deck = { Ranks = { 2, 3, 4, 5, 6 } }
the ranks might need to be strings im not sure
"Ace"
ok well now i have a deck with no cards
have you tried this
iam trying to make baseball card but instead of uncommon jokers its for a custom pool of jokers i have, how do i check if a joker is in my pool?
if (joker.config.center.pools or {}).yourpoolname then
wouldnt it be "yourpoolname"
attempt to index global 'joker' (a nil value)"
```that gives this error tho
joker was a generic name i gave the joker object you need whatever is called in the place you are using it
i assume context.other_joker
well i already said its like baseball card
so its pretty fair to assume if you ask me
why are you arguing with me on this 😭
ok?
my localisation isnt fully working and im unsure how to fix it
jokers work fine, as do decks and blinds and such
its just the consumables specifically where it falls apart
the consumables themselves are fully functional, it looks like the file isnt calling to the correct localisation is all
its the same for divine cards
here is the current en-us.lua file
here is main.lua and the respective consumable files if that helps
how do you remove the edition off a card
if context.end_of_round and context.game_over == false and context.main_eval then -- Devolution
if card.ability.extra.energy <= 0 then
G.E_MANAGER:add_event(Event({ -- Devolve Effect
trigger = 'after',
delay = 0.4,
func = function()
local evolution = card
play_sound('timpani')
card:set_ability("j_hatch_hatchet") -- The Original Joker
card:set_edition()
card:juice_up(0.3, 0.5)
return true
end
}))
return { -- Devolve Message
message = "Reverted!",
colour = G.C.BLUE
}
else -- Losing Energy...
card.ability.extra.energy = card.ability.extra.energy - 1
return {
message = "Losing energy...",
colour = G.C.BLUE
}
end
end
end
})
I dont have the source code available but check the copy_card function it strips edition with Invisible Joker
o oke
function copy_card(other, new_card, card_scale, playing_card, strip_edition)
card:set_edition()
oke
please use a localization file instead
oh you can do that
loc_txt lets you do like pretty much all text thats required
i was gonna say once you use a loc file you can put it at misc.labels.modprefix_devour_seal = "Devour Seal"
:<
nvm fixed it
and _seal after (unless in the seal's definition you just put "devour" as the key)
like modprefix_sealkey_seal
it's whatever you put there in your json
Blue Card: Gain +50 Chips if no purchases are made in shop.
how would i track if there are no purchases made in shop
then idk 😶
is it prefix_ or m_prefix_
you typo it
it say marm when should be mar
I fixed that one
o
context.buying_card is when you buy any card but a booster
context.open_booster happens when you open a booster, that could happen from other sources but idk if you can track specifically buying a booster
you can check these 2 and if they happen then something was bought
nvm if im wrong about _seal being at the end
(If that's the case that's stupid as hell
yeah seals are modprefix_sealkey_seal
le code
lizzie was right, it's without _seal at the end
I looked at another mod that adds seals
oh i was looking at some code, but not the right part, oop
How do I just make a deck get rid of every Spade?
add an event in its apply function that goes through your deck and deletes all spades
How do I do that?
which part
Remove the spades. Like, would it be like how Abanoned deck does no_Faces = true, Or do i have to do something else?
apply = function(self)
G.E_MANAGER:add_event(Event({
func = function()
local to_destroy = {}
for _, v in pairs(G.deck.cards) do
if v:is_suit("Spades") then
to_destroy[#to_destroy+1] = v
end
end
SMODS.destroy_cards(to_destroy)
return true
end
}))
end
thank you
just my aura im afraid
don't be afraid
Be not afraid
key = "lenny",
config = {
extra = {
}
},
loc_txt = {
['name'] = 'Lenny Leonard',
['text'] = {
[1] = 'If {C:attention}Glass Card{} breaks in {C:legendary}The Eye{}{} {C:attention}Boss Blind{},',
[2] = 'Create a {C:dark_edition}Negative{} {C:attention}Diet Cola{} or {C:attention}Seltzer{}.',
[3] = '',
[4] = '{C:inactive,s:1.2}(Ow my eye, I’m not supposed to get {C:attention,s:1.2}[Glass Card]{}{C:inactive,s:1.2} in it!){}'
},
['unlock'] = {
[1] = 'Unlocked by default.'
}
},
pos = { x = 0, y = 0 },
cost = 20,
rarity = 4,
blueprint_compat = false,
eternal_compat = true,
perishable_compat = true,
unlocked = true,
discovered = true,
atlas = 'lennybg',
pools = { ["shit"] = true },
soul_atlas = 'lenny',
soul_pos = { x = 0, y = 0 },
in_pool = function(self, args)
return (
not args
or args.source ~= 'sho'
or args.source == 'buf' or args.source == 'jud' or args.source == 'rif' or args.source == 'rta' or args.source == 'sou' or args.source == 'uta' or args.source == 'wra'
)
and true
end,
calculate = function(self, card, context)
if context.remove_playing_cards then
if SMODS.get_enhancements["m_glass"] == true and to_big(G.GAME.blind.config.blind.key) == to_big("bl_eye") then
return {
func = function()
if #G.jokers.cards + G.GAME.joker_buffer < G.jokers.config.card_limit then
G.GAME.joker_buffer = G.GAME.joker_buffer + 1
G.E_MANAGER:add_event(Event({
trigger = 'after',
delay = 0.4,
func = function()
play_sound('timpani')
SMODS.add_card { key = "shit_lennypool" }
card:juice_up(0.3, 0.5)
return true
end
}))
end
return true
end
}
end
end
end
}```
uhhh
cryptid
no that's just the one joker
i mean the deck/sleeve
Tried to change it to activate when the card is scored so that it actually copies the card after midas mask and Hurtbreak Wonderland (If the first played hand is a single, editionless 8/Ace, adds a random edition) an so it could have synergy with retriggers, and now it's doing that
where did I fuck it up
bump
how would i create a specific card with SMODS.add_card
SMODS.add_card({key=key})
how to make a deck that spawns one random card from a pool on start?
SMODS.add_card({set=poolkey})
remember to do it in an event if it's a deck
do i need the prefix
and it needs an area
G.E_MANAGER:add_event(Event({
func = function()
SMODS.add_card({ set = 'tavern'})
return true
end
}))
end```
smth wrong 😭 i might be an idiot
if you're making a specific card, does SMODS.add_card() actually require a "set" value?
It does not
no, but it will crash if something bans the card
does it not create anything
does it not do that with a "set" set
if add_card has the set it fallsback to it if the card is banned
if not it crashes
i personally dont care but i have gotten crash reports
is there a way to detect if a certain card is banned
G.GAME.banned_keys[key]
i just noticed something in vremade that might be wrong
key = "nano",
loc_txt = {
name = "Nano Shinonome",
text = "nano nano nano nano"
},
atlas = 'bwaaajoker',
pos = {x = 2, y = 0},
soul_pos = {x = 3, y = 0},
rarity = 1,
cost = 1
}``` not sure what i did wrong but it's crashing the game
the crash is in [#⚙・modding-support](/guild/1116389027176787968/channel/1456641579346297053/)
cartomancer uses G.C.PURPLE for the +tarot message, but it should use G.C.SECONDARY_SET.Tarot
unless purple is what the game actually uses, in which case some other effects use the wrong one ig
and the traceback
wait nvm
the error wasnt specific
turns out the text needs to be a table
is this the base game's thing for this?
cause its inconsistent in vremade as to which color it uses
It doesn't.
😭
bc i'm trying to make a rare card equivalent for my custom card type
(not to be confused with consumable type)
i have at least noticed that it stops it from appearing naturally in boosters
You would have to hook create_card and check for it manually.
ah
i may just
make the weight very low
what's the weight for rare spectrals normally?
..how do i set a card's weight?
You would enable the object_weights optional feature then do weight = number
ty
would 0.05 be reasonable?
considering its ability
how could I make a booster pack that contains only seal spectral cards? including modded ones?
bump
You would create a pool then you would do this: lua local oldsmodsinjectitems = SMODS.injectItems function SMODS.injectItems() local g = oldsmodsinjectitems() for k, v in pairs(G.P_CENTERS) do if v.set == 'Spectral' then local description = table.concat(localize({type = 'raw_descriptions', key = v.key, set = 'Spectral', vars = {}}), ' ') if description:match('^Add a (.-) ?Seal to (.+) selected cards? in your hand$') then SMODS.insert_pool(G.P_CENTER_POOLS['poolkey'], v) end end end return g end Then you would do return {set = 'poolkey', skip_materialize = true, key_append = self.key}
I'll definitely take a look at this
wdym you can select parts of a description holy moly
So 2 questions:
How do you detect if an achievement is earned and if a specific blind is defeated?
you could also check for context.money_altered and context.from_shop and context.amount < 0
if you want to count "spending money" as buying something from shop
this would make it include rerolls and not include discounted items tho
trying to get my mod icon to appear. is there anything else i have to do aside from putting this in metadata.json? (i have the sprite in both 1x and 2x with the right pixel count)
No.
and so if it's not showing up ... skill issue? lmao
What is your SMODS version?
1.0.0 beta 1503a
Update SMODS
works now, thanks!
I am pretty sure that weights won’t be what you’re after here, they work within an object type, but I’m not 100% on how your cards appear in the shop
whenever a joker is ankhed in my mod, its atlas seems to be missing. what is going on? is this a common issue
(ignore the bad crop/screenshot)
Code?
wouldnt it be an atlas issue? it might happen with all jokers, i cant test im playuing multiplayer with my friends
send the atlas code
and also the joker code
is there a way to tell if the game state is that a hand is currently being played
iirc yes lemme check
wait i think i just wrote the code wrong
i checked just G.STATES.HAND_PLAYED instead of G.STATE == G.STATES.HAND_PLAYED
ahh lol
ooooh ok :o
Bumping this
You're missing context.cardarea == G.play
AltTexture{ -- Aure Spectral
key = 'aure', -- alt_tex key
set = 'Spectral', -- set to act upon
path = 'aure_spectral.png', -- path of sprites
keys = { -- keys of objects to change
'c_aura'
},
soul_keys = { -- keys of objects to add floating sprites to
'c_aura'
},
localization = { -- keys of objects with new localizations
'c_aura'
}
}
TexturePack{ -- Aure
key = 'aure', -- texpack key
textures = { -- keys of AltTextures in this TexturePack
'aure_spec_aure'
}
}
Example of single card replacement here
Found it out dw
How do I add a new card enhancement
great example icl
is there a context for checking if the card is debuffed during calculate?
there isn't a context for that, you can check if a card is currently debuffed with card.debuff
so how can i check if a playing card is debuffed in scoring?
you can check if a card is currently debuffed with
card.debuff
so if context.cardarea == G.play and card.debuff?
That depends on what source is checking for it - a Joker, an enhancement...
i want to make a joker that gives mult for every debuffed card played
context.joker_main, iterate over played cards and add up mult per debuffed card played.
debuffed cards are not iterated on like other cards are
so you need to do what ali said
and how do i iterate over played cards?
im sorry im still really new to modding
https://github.com/nh6574/VanillaRemade/wiki#how-do-i-get-if-the-player-has-a-certain-card
read the first playing card example
(for the entire played hand it's context.full_hand)
what do yall think would be a good. number of jokers for a first release of a mod. like 30?
so would this work?
playing_card.debuff
it's not a function
also if you return it will only count the first one
you need to return after you count them
375
okay so only card:debuff right?
Man I wonder who made this
playing_card.debuff
aaah okay
so how do it put it?
i mean where does the return go?
in the loop you need to count the cards, after the loop you return mult * count
and do i count them with local card_count = #G.playing_cards?
what the fuck .
if add_to_deck() is how you add a new playing card to the deck, i'd assume remove_from_deck() would remove a card from the deck, right?
counting like
local counter = 0
for _, value in ipairs(array) do
if value == something then
counter = counter + 1
end
end
print(counter)
yes, removing for what tho
i'm trying my hand at making a custom deck, and i only want certain cards to appear
then you need to destroy it not remove it
ah ok
card:remove()
how does that differ from SMODS.destroy_cards?
destroy_cards does an animation and it counts it for playing_card_destroyed
if you are setting up the starting deck you likely don't want those to happen
remove_playing_card?
i dont remember the name
initial_deck in SMODS.Back allows you to set what ranks and/or suits you start with.
-- Roulette
SMODS.Joker {
key = "roulette",
config = { extra = { dollars = 8 } },
pos = { x = 3, y = 2 },
cost = 7,
rarity = 2,
blueprint_compat = true,
eternal_compat = true,
perishable_compat = true,
unlocked = true,
discovered = false,
atlas = 'HatchetJokers',
loc_vars = function(self, info_queue, card)
local suit = (G.GAME.current_round.vremade_castle_card or {}).suit or 'Spades'
return { vars = { card.ability.extra.dollars, localize(suit, 'suits_singular'), colours = { G.C.SUITS[suit] } } }
end,
calculate = function(self, card, context)
if context.before and not context.blueprint and next(context.poker_hands['Flush']) and
not context.other_card.debuff and context.other_card:is_suit(G.GAME.current_round.vremade_castle_card.suit) then
return {
dollars = card.ability.extra.dollars,
remove = true,
delay = 0.45
}
end
end
}```
the code here is a little rough - it seems to not know what the "other_card" thing is
how can i fix it
Context before doesn’t have other card
That also doesn’t
What is your effect?
Why do you need other card for this
G.E_MANAGER:add_event(Event({
func = function()
for k, v in pairs(G.playing_cards) do
local rank_number = v:get_id()
if rank_number <= 8 then
v:remove()
elseif rank_number >= 9 then
local copy_card = v
copy_card:add_to_deck()
end
end
return true
end
}))
end```
not sure how this code results in just the even numbered cards being removed but ok 💀
you can't copy a card by adding it twice to deck
i removed the return true because idk why that was there and now all the cards i wanted to be removed are gone
and the game is stuck?
ahh, so i'd need to make a new card with that same suit and rank
remove = true should not be there oops
yeah, no cards have been drawn
ah ok
you need to loop through all the cards in context.scoring_hand until you find the suit
ah okay, so similar to what i did for seven sisters then
G.E_MANAGER:add_event(Event({
func = function()
for k, v in pairs(G.playing_cards) do
local rank_number = v:get_id()
if rank_number <= 8 then
v:remove()
elseif rank_number >= 9 then
local suit = v.base.suit
local copy_card = {rank_number, suit}
copy_card:add_to_deck()
end
end
return true
end
}))
end```
would something like this be better?
ohhh okay
no lmao
im sorry it's very funny to declare a card like that
i would look into SMODS.add_card and the vanillaremade jokers that add playing cards
i'm using dna as a reference
that works
but copying is a little bit complicated at the moment which might get better in the next smods
iterate backwards
-- Roulette
SMODS.Joker {
key = "roulette",
config = { extra = { dollars = 8 } },
pos = { x = 3, y = 2 },
cost = 7,
rarity = 2,
blueprint_compat = true,
eternal_compat = true,
perishable_compat = true,
unlocked = true,
discovered = false,
atlas = 'HatchetJokers',
loc_vars = function(self, info_queue, card)
local suit = (G.GAME.current_round.vremade_roulette_card or {}).suit or 'Spades'
return { vars = { card.ability.extra.dollars, localize(suit, 'suits_singular'), colours = { G.C.SUITS[suit] } } }
end,
calculate = function(self, card, context)
if context.joker_main and not context.blueprint and next(context.poker_hands['Flush']) then
local passed = true
for k, v in pairs(context.full_hand) do
if v:is_suit() ~= G.GAME.current_round.vremade_roulette_card.suit then
passed = false
end
end
if passed then
return {
dollars = card.ability.extra.dollars,
delay = 0.45
}
end
end
end
}
-- Roulette Functions
local function reset_vremade_roulette_card()
G.GAME.current_round.vremade_roulette_card = { suit = 'Spades' }
local valid_roulette_cards = {}
for _, playing_card in ipairs(G.playing_cards) do
if not SMODS.has_no_suit(playing_card) then
valid_roulette_cards[#valid_roulette_cards + 1] = playing_card
end
end
local roulette_card = pseudorandom_element(valid_roulette_cards,
'j_hatch_roulette' .. G.GAME.round_resets.ante)
if roulette_card then
G.GAME.current_round.vremade_roulette_card.suit = roulette_card.base.suit
end
end
function SMODS.current_mod.reset_game_globals(run_start)
reset_vremade_roulette_card()
end
would this work
oh yeah also this
if not v:is_suit(G.GAME blah blah) then
tbf it doesnt seem like it would be a problem at first
since v still exists after calling v:remove()
oke thabnkies
it should work
calling remove on a card removes it from G.playing_cards iirc
but due to how remove work, the card still exists
just the UI is gone and card.REMOVED is true
i'm just so confused 💀
SMODS.add_card{ set = "Base", rank = "14", suit = "S", area = "G.deck" }
without the quotes
oh yeah
rank = "Ace" or rank = 14
string moment
or rank = "A"
wait does suit S work
yeah
ive always used Spades
neat
because im smart and cool and added all the ways
i searched smods.add_card in the discord server and just inspected how other people used it
suit = "♤"
there are docs 😭
there are like a million examples in vremade
and the vremade wiki
maybe it's just my own incompetancy but i have a hard time navigating the docs to find what i'm looking for
ctrl f
but it's all on different pages
well you can eliminate all the game object pages
that's why vremade wiki is all 1 page
my code is so broken i've accidentally remade erratic deck 💀
can u send it
G.E_MANAGER:add_event(Event({
func = function()
for k, v in pairs(G.playing_cards) do
local rank_number = v:get_id()
if rank_number <= 8 then
v:remove()
elseif rank_number >= 9 then
SMODS.add_card{ set = "Base", rank = 14 , suit = "S", area = G.deck }
end
end
return true
end
}))
end```
what this code should do is go through all the playing cards in the deck and remove all the cards of rank 8 or below and then add in an extra ace of spades for every card of rank 9 or above. this is not what's happening in the slightest though
we're just doing whatever ig lmao
does it consistently look like this
try rank = "Ace", suit = "Spades"
is it because i'm adding cards while looping through the deck? is that the problem?
also you should loop with ipairs
ah 14 doesnt work
thats the problem
like will for i = 1, #t do t[#t + 1] = 1 end be infinite
and for some reason the suit is not being respected, that seems like an smods bug
wait that won't matter nvm
fuck
okay try this
i removed the part of the code that adds cards, and so it should just remove the 8 or below cards. i guess odd numbers are exempt from that
try iterating backwards
it's not good practice to remove things in a table as youre iterating
forwards at least
G.E_MANAGER:add_event(Event({
func = function()
for i = #G.playing_cards, 1, -1 do
local v = G.playing_cards[i]
local rank_number = v:get_id()
if rank_number <= 8 then
v:remove()
elseif rank_number >= 9 then
SMODS.add_card{ set = "Base", rank = "Ace" , suit = "Spades", area = G.deck }
end
end
return true
end
}))
end```
since yall probably need adamantite.lua
now when you say iterate backwards, what does that mean?
do what i sent
eyyy that works
now, can you explain to me why that works?
i see we're creating a new variable that's just a copy of the deck
when you call v:remove(), it removes the current index from G.playing_cards
when you remove something from a table you're making it smaller so it keeps skipping steps basically
ahhh
when you destroy the 2 of hearts
the 3 goes into the spot
tland then you go to the next spot
that does make sense
now let me fix the smods bug lol
also if you ever getting random suits and ranks out of create card it means the rank or suit key is wrong
yeah it does
it doesnt
oh
rank is wrong but doesnt respect the suit
misunderstood you
-- Fireworks
SMODS.Joker {
key = "fireworks",
config = { extra = { xmult = 3, type = 'Straight' } },
pos = { x = 5, y = 2 },
cost = 9,
rarity = 3,
blueprint_compat = true,
eternal_compat = true,
perishable_compat = true,
unlocked = true,
discovered = false,
atlas = 'HatchetJokers',
loc_vars = function(self, info_queue, card)
return { vars = { card.ability.extra.xmult, card.ability.extra.type } }
end,
calculate = function(self, card, context)
local activation = false
if context.pre_discard and next(context.poker_hands['Straight']) then
activation = true
return {
message = localize('k_active_ex'),
colour = G.C.MULT
}
else
activation = false
end
if context.joker_main and activation == true then
return {
xmult = card.ability.extra.xmult
}
end
end
}```
how do i make this work
im guessing i need to have it so the discarded hand is recognised as a straight
what do
if discarded hand contains a straight, this joker will give X3 mult upon use
it'll say "active" then do the thing
im wondering if i have to use G.hand.highlighted
yeah you need to evaluate the poker hand with the function
context.full_hand will work instead of highlighted too
the key for ace is "Ace"
it's Ace or A
yeah im taking a look at burnt joker specifically
do you need use button code?
no
you should reword that then lmao
oe
-- Fireworks
SMODS.Joker {
key = "fireworks",
config = { extra = { xmult = 3, type = 'Straight' } },
pos = { x = 5, y = 2 },
cost = 9,
rarity = 3,
blueprint_compat = true,
eternal_compat = true,
perishable_compat = true,
unlocked = true,
discovered = false,
atlas = 'HatchetJokers',
loc_vars = function(self, info_queue, card)
return { vars = { card.ability.extra.xmult, card.ability.extra.type, 'poker_hands' } }
end,
calculate = function(self, card, context)
local passed = true
if context.pre_discard then
for k, v in pairs(context.full_hand) do
if v:next(context.poker_hands[card.ability.extra.type]) then
passed = false
end
end
if passed == true then
local eval = function() return context.end_of_round and not G.RESET_JIGGLES end
juice_card_until(card, eval, true)
return {
localize('k_active_ex')
}
end
end
if passed == true and context.joker_main then
return {
mult = card.ability.extra.mult
}
end
end
}
