#💻・modding-dev

1 messages · Page 170 of 1

gusty sequoia
#

But I'm struggling greatly with that process

teal estuary
#

smods has example jokers that you can look at

gusty sequoia
#

Oh neat

teal estuary
#

....am i blind? wheres like, all the example stuff on the github raisedcateyebrow

gusty sequoia
#

I don't know ;-;

fallen pelican
teal estuary
#

oh, well

#

in there

gusty sequoia
#

Thank you!

teal estuary
wintry solar
#

I should double check that jokers file for new calc stuff

fallen pelican
#

the examples there use mult_mod balatrojoker

frosty dock
#

at the very least it needs to be adjusted for new calc best practices

wintry solar
#

yeah I'll comb through it now

frosty dock
#

such as getting rid of manual card_eval_status_text and xyz_mod+message

fallen pelican
#

how does the boss blind trigger its discards after a hand is sent? I used G.FUNCS.discard_cards_from_highlighted() in context.before and it just queued the discard to happen after the whole scoring process, after which the game itself bugged out and drew twice as many cards as the hand size

wintry solar
#

oh god there are a lot of comments in here that would need editting

#

😭

frosty dock
#

yeah context.before is far too late for that

#

i think there's been thoughts of providing calculation interfaces for blind functions

fallen pelican
#

aw, so there's no workaround for now?

frosty dock
#

as of now you'd have to hook/patch Blind:press_play()

fallen pelican
frosty dock
wary ivy
#

What do I do

#
Syntax error: game.lua:2723: duplicate label 'continue'


Additional Context:
Balatro Version: 1.0.1n-FULL (best guess)
Modded Version: 1.0.0~ALPHA-1304a-STEAMODDED
LÖVE Version: 11.5.0
Lovely Version: 0.7.1
Platform: Windows

Stack Traceback
===============
(3)  C function 'function: 0x1cb0ce58'
(4) global C function 'require'
(5) main chunk of file 'main.lua' at line 1728
(6) global C function 'require'
(7) LÖVE function at file 'boot.lua:323' (best guess)
Local variables:
 c = table: 0x1cb0d938  {identity:false, version:11.5, accelerometerjoystick:true, modules:table: 0x1cb0cd30 (more...)}
 openedconsole = boolean: false
 confok = boolean: true
 conferr = nil
(8) global C function 'xpcall'
(9) LÖVE function at file 'boot.lua:362' (best guess)
Local variables:
 result = boolean: true
(10) global C function 'xpcall'
(11) LÖVE function at file 'boot.lua:377' (best guess)
Local variables:
 func = Lua function '(LÖVE Function)' (defined at line 355 of chunk [love "boot.lua"])
 inerror = boolean: true
 deferErrhand = Lua function '(LÖVE Function)' (defined at line 348 of chunk [love "boot.lua"])
 earlyinit = Lua function '(LÖVE Function)' (defined at line 355 of chunk [love "boot.lua"])
#

@paper zealot

sullen fern
#

i'm not actually going to make EVERY word in the toki pona lexicon a joker

#

i'm just putting them here so i can remove the ones i don't think will work and leave only the ones i think will work

south folio
#

Oh Wow

gusty sequoia
#

Does anybody know how I'd code a joker to give +1 Chip?

south folio
gusty sequoia
#

Interesting

sullen fern
gusty sequoia
sullen fern
#

lili and suwi will have different sized cards kinda like wee joker

#

lili will be small and suli will be big

#

(because that's what they mean)

south folio
#

Ok I've managed to make it act like a DNA joker but for Every round, now just need to make it duplicate the card twice and make it only for face cards

    if context.before then
            G.playing_card = (G.playing_card and G.playing_card + 1) or 1
            local _card = copy_card(context.full_hand[1], nil, nil, G.playing_card)
            _card:add_to_deck()
            G.deck.config.card_limit = G.deck.config.card_limit + 1
            table.insert(G.playing_cards, _card)
            G.hand:emplace(_card)
            _card.states.visible = nil

            G.E_MANAGER:add_event(Event({
                func = function()
                    _card:start_materialize()
                    return true
                end
            }))

            return {
                message = localize('k_copied_ex'),
                colour = G.C.CHIPS,
                playing_cards_created = {true},
            }
        end
    end```
gusty sequoia
#

I got my joker to show +nil Chips :D

#

Which is progress... I guess?

south folio
#

yay!

gusty sequoia
#

Now I just gotta find out how to make it give a singular chip

normal crest
#

if context.joker_main then return { chips = 1 } end

sullen fern
#

if you have any other ideas please let me know

#

i WILL accept toki pona words beyond pu and ku

gusty sequoia
normal crest
#

what's your code

smoky talon
#

how do i change the player's money?

#

im trying to make a joker that either doubles it or loses it all

tepid crow
#

ease_dollars* I think?

normal crest
#

ease_dollars

tepid crow
#

oh yup just double checked it's ease_dollars

#

spelling is off the charts today

gusty sequoia
# normal crest what's your code

`SMODS.Atlas{
key = 'Jokers',
path = 'jokers.png',
px = 1207,
py = 1615
}

SMODS.Joker{
key = 'Timbo',
loc_txt ={
name = 'Timbo the Test Joker',
text = {
'{C:chips}+#1#{} Chip'
}
},
atlas = 'Jokers',
pos = {x = 0, y = 0},
rarity = 1,
config = {
extra = {
Chip = 1
}
},
calculate = function(self, card, context) return
if context.joker_main then return {chips = 1}
end
}`

#

I know it's not the best, this is because I'm incredibly bad at Lua

void pecan
wintry solar
#

you can just return dollars in calculation

gusty sequoia
wintry solar
#

you have an extra return

gusty sequoia
#

I see

#

It still broke because of an unexpected symbol near } on line 38 :(

#

And line 38 is the last line... with nothing near it ;-;

frosty dock
gusty sequoia
#

It's still coded in Lua though

frosty dock
#

get a lua extension or something

#

it'll show you syntax errors while you write code instead of finding them when you try to run it

gusty sequoia
#

Well that's cool

frosty dock
#

anyways your calculate function is missing an end

gusty sequoia
#

Thank you

#

:D

#

Anddddd it still says +nil chips... back to the drawing board?

normal crest
frosty dock
#

you don't have a loc_vars function

gusty sequoia
#

Ah

grand sage
#

my game keeps giving me this error when i try to load my mod yet i have an lua file that's named correctly can someone help me?

normal crest
grand sage
normal crest
#

do you have a "GoldFinger.png" file in both assets/1x and assets/2x

graceful magnet
#

I'm planning on making a card-copying Joker effect, can I get a bit of a rundown on what each piece of this is doing so I have a better understanding of how and what I'll want to use? (Ping when replying, I might not be looking here)

obtuse silo
#

you're using notepad to write code?

stray warren
#

Flash bang warning next time please

grand sage
frosty dock
#

🔦 ‼️

gusty sequoia
graceful magnet
normal crest
#

make sure your mod is at Mods/mod name/<entry file>.lua

stray warren
#

sublime text is very simple and worlds better than notepad

obtuse silo
#

at least use something like notepad++ so you don't have it stuck in light mode

grand sage
obtuse silo
#

pfft-

normal crest
#

you still have nested folders

wicked spire
#

Is there a list of all the color options available any where (i.e. {C:inactive})?

grand sage
stray warren
#

yes, definitely make sure you are downloading VSCode and not Visual Studio. Completely different

gusty sequoia
smoky talon
stray warren
#

ease_dollars(0)

smoky talon
#

ah lol

stray warren
#

although that doesn't do anything lol

normal crest
#

if you want to set money to zero probably do ease_dollars(-G.GAME.dollars)

stray warren
#

And you can always check what that one boss blind does that sets your money to zero on playing your most played hand

smoky talon
#

that worked

normal crest
#

dunno what the 2nd argument is for

#

"instant"

smoky talon
#

now i just need to find out how to multiply it

stray warren
#

If you want to double it, just do ease_dollars(G.GAME.dollars). Triple it, just do ease_dollars(2 * G.GAME.dollars), etc...

smoky talon
#

perfect

graceful magnet
smoky talon
#

only thing i need now is figuring out how to make the probability in the card description update with opps all sixes

#

so that its accurate like all the other base game ones

stray warren
#

That value is G.GAME.probabilities.normal

#

It updates automatically with Oops

smoky talon
#

and how do i set it to a specific starting value?

stray warren
#

You multiply that value by whatever you want your starting value to be

#

so 2 would be 2 * G.GAME.probabilities.normal

void pecan
#

if I want to add an image to a singular card, do I still need a card map or just a singular picture of the card (for 1x and 2x)

graceful magnet
prisma loom
#

why my game crashes when I add these 2 atlases?

#

(upper 2)

void pecan
#

because my game doesn't crash and no errors but my image isn't in the game for my tarot card

smoky talon
#

im sure im just being an idiot lol

stray warren
#

Can i see the code

violet void
prisma loom
gusty sequoia
#

I am once again asking how to make my joker give +1 chip (it keeps displaying as +nil & doesn't do anything)

smoky talon
#

this is how i have it right now, but ive tried otehr variations too

prisma loom
#

here

stray warren
#

That's a literal string

smoky talon
#

ah lol

violet void
prisma loom
tepid crow
prisma loom
#

I need a hanged man emote rn

#

Game works but noting in the collection

#

thats some progress!

smoky talon
tepid crow
violet void
void pecan
#

I think I messed up on my atlas guys, bad

stray warren
violet void
graceful magnet
smoky talon
#

i know how to make the function, just not how to declare the probability

violet void
prisma loom
#

yes

#

both

#

oh right I need to import

gusty sequoia
#

Is this part of my code even doing anything?
config = { extra = { Chip = 1 } },

(It then goes to the loc_vars & calculate things)

smoky talon
#

ok i think i have the loc_vars function, how do i call to it in the description?

stray warren
#

You can use it however you like

void pecan
# violet void probably the x and y position
SMODS.Atlas{
    key = 'sigma',
    path = 'Tarot.png',
    px = 0,
    py = 0
}

local tarotCard = SMODS.Consumable({
    key = "tarot_card_joker_effect",
    set = 'Tarot',
    atlas = 'sigma', pos = { x = 0, y = 0 },
    cost = 0,
    loc_txt = {
        name = 'Balance',
        text = { '50% chance to turn every joker polychrome',  '50% chance every joker is destroyed', '(Not affected by dice)'} --Would also appreciate help on colors, couldn't find it on docs
    },
    unlocked = true,
    discovered = true
})```

pic is my tarot (just for reference)
violet void
gusty sequoia
void pecan
prisma loom
#

is this correct?

violet void
stray warren
violet void
prisma loom
void pecan
prisma loom
#

:D

violet void
stray warren
#

71x95

void pecan
violet void
stray warren
#

yeah

violet void
#

I thought they would have less width

stray warren
#

Nope. But they do have more transparent pixels on the sides, so that's probably what you mean

void pecan
#

yeahhh probably

violet void
stray warren
prisma loom
stray warren
#

So the card is centered between transparency, if that makes sense

smoky talon
#

it works, but it doubles the second number, meaning the probability goes down instead of up

void pecan
smoky talon
#

if i put the 8x first it would be an 8 in whatever chance

void pecan
stray warren
#

No, pix is 71x95 total. But some of that space is transparent

violet void
# prisma loom

are you sure you have a seals folder with a lua file called black_seal in it

stray warren
#

You can reference how the base game's spritesheet is organized to get a visual

smoky talon
#

wait i think i figured it out

violet void
#

thats what the error says

#

also its in a "object" folder

#

why is that

prisma loom
#

I used Ortalabs structure

#

iirc

#

or Cryptid's

#

what's default?

violet void
#

you need to include that for the import then

#

'objects/seals/' ..

wintry solar
#

he just blanket copied the structure I linked him without taking a moment to try and udnerstand it

void pecan
#

idk why it looks fuzzy, or if its supposed to

prisma loom
stray warren
void pecan
violet void
stray warren
#

I know that GIMP automatically applies some anti-aliasing that you have to disable, but I'm not sure with photoshop

void pecan
prisma loom
#

should I just remove loc vars?

violet void
#

no, can you paste your localization file too

gusty sequoia
#

Balck Seal?

prisma loom
#

but thats not the issue I think

gusty sequoia
void pecan
violet void
gusty sequoia
#

Tbh I'm just waiting for the other issues to be dealt with so I can ask about mine

stray warren
#

You can extract the Balatro.exe and find it in the assets folder

void pecan
stray warren
#

Isn't that what you are looking for?

violet void
void pecan
violet void
#

Voucher as well

#

and probably spectral im not sure about that one

prisma loom
#

it works now

#

holy moly

#

finally

stray warren
#

That's probably how you're gonna have to do it, since it's the only way they are stored in the base game

prisma loom
#

Now, how do I import spectral card?

void pecan
prisma loom
#

my rough assumption (nvm)

stray warren
#

You'd probably be fine either way, but personally editing and just deleting the rest sounds safer so the lineup is preserved

edgy mountain
#

can anyone help me here?
im doing a bunch of random checks separately
but for some reason they dont ever return more than on positive

#

only one check at most succeds every time

normal crest
#

a function can only return once

prisma loom
#

@violet void should I do the same for spectral card?

normal crest
edgy mountain
normal crest
#

you could accumulate effects

prisma loom
#

engrish is hard

#

ngl

normal crest
#

modify a local variable that is returned at the end

edgy mountain
prisma loom
#

whats the prefix for spectral cards in localization file?

#

s_ ?

normal crest
#

where'd you get that it's s_

#

it's c_

prisma loom
#

I just assumed

stray warren
#

c for consumable

#

j for joker

normal crest
#

it's in the vanilla localization file

prisma loom
#

Can someone explain where I should pay my attention to understand what causes error while reading this report?

#

this is correct, right?

lilac tide
#

Howdy, new here! Just was wanting to ask if anyone has good resources to look at as far as adding a new booster pack. I can add consumable types easy but the part I haven't figured out yet is adding the new packs haha

#

Also very happy to go over any docs, rn just crawling through source code to piece things together one at a time

stray warren
#

If you haven't checked the SMODS wiki, it provides a lot of the information that you would need

#

it's on the repo

scarlet spire
#

is there a function or something that lets me manually trigger/score a specific card?

wicked spire
#

My Joker (Uncommon, $6)
This Joker gains +? Mult every 7 [7] cards played and scored
(Currently +0 Mult)

I'm designing this Joker, do you guys think it should be +1 or +2 Mult per 7 scored cards? It's Uncommon so I don't want it to be too OP

long sun
#

i'm reading through the documentation for sound effects on the SMODS repo, but i don't quite get it — i have a sound called fling.ogg in assets/sounds, how would i play it?

crisp coral
#

play_sound('prefix_key', pitch, volume)

long sun
#

thanks!! :D

#

is normal pitch = 1?

lilac tide
scarlet spire
#

I am realizing that was a little vague, yeah, basically I want to be able to make a certain card in your hand score (alongside its enhancement), even if it wasn't played

prisma loom
#

Is everything correct here?

#

something causes a crash

scarlet spire
#

have you given the atlas a key?

prisma loom
#

its 'tarot'

scarlet spire
#

atlas should = "tarot" then

#

because it's pointing to the key

prisma loom
#

but why my seal uses the name of the file as atlas then?

#

(and it works)

#

actual key for atlas here is 'enhancer'

scarlet spire
#

that's odd? it shouldn't, I don't think

#

you've tested it in game and it appears correctly?

prisma loom
#

but it no longer crashes

#

but this one cuases a crash

#

Oh nvm!

#

that fixed it

#

thanksrPepelove

long sun
#

what does this error mean?

nova finch
#

i know there's a way to check if a hand was played the current round, but is there a way to check if a hand was played before in the current ante?

marble flint
#

or that they're different aspect ratios

long sun
#

oh. ohhhhhh thanks, my 2X was still called Phanta =w=

lilac tide
#

Actually I was just messing around with some mod that has a similar joker to this haha I can dig through the code and see how that one works

long sun
#

okay got a new one!

marble flint
marble flint
nova finch
long sun
#

suresure! i'm not sure i ever used the prefix...?

#

oh well there was one use in the sound name

marble flint
#

you didn't update the atlas key in the joker

nova finch
#

teh atlas should be the key in your smods.atlas

long sun
#

oh. whoops. =w=

nova finch
#

for atlas =

marble flint
#

us when copy paste:

long sun
#

more silly mistakes with GhostSalt :P

#

i suspect this error's happening because i haven't registered my sound yet, how do i go about doing that?

nova finch
prisma loom
#

What should I add to vars for this part of code?

sharp gate
#

Anyone know how lovely works? Like how it patches the actual game?

scarlet spire
scarlet spire
#

I know this is a bit of an odd thing to do in the first place, but i'm having issues with this joker effect? do I need to do more to correctly upgrade a poker hand?

#

doesn't display hand names when upgrading them, and sometimes shows negative numbers? the outcome is correct but the display is completely messed up

zealous glen
graceful magnet
#

So in my attempts to use modified DNA code (completely unsuccessful atm), my current iteration:

        if context.playing_card_added then
            G.playing_card = (G.playing_card and G.playing_card + 1) or 1
            local _card = copy_card(card, nil, nil, G.playing_card)
            _card:add_to_deck()
            G.deck.config.card_limit = G.deck.config.card_limit + 1
            table.insert(G.playing_cards, _card)
            G.deck:emplace(_card)
            _card.states.visible = nil
            return {
                message = localize('k_copied_ex'),
                colour = G.C.CHIPS,
                card = self,
                playing_cards_created = {true}
            }
        end
    end```

produces a stack overflow, and I've determined I need to do something with `copy_card(*card*`, because changing that changes the error.

But what should I change it to?
zealous glen
graceful magnet
#

yes

zealous glen
#

That's your problem

graceful magnet
#

riiiight, it needs to have some sort of stop on it

stray wing
#

Is it possible to edit the config field of a deck during a game? Specifically, I'd like to have a deck that gains a joker slot after defeating each boss blind, but I can't find a mod doing something like that

graceful magnet
hexed briar
#

How do people get into modding, is there any documentation?

normal crest
#

self is not a card

zealous glen
stray wing
hexed briar
#

Thanks

zealous glen
graceful magnet
stray wing
normal crest
graceful magnet
#

right

stray wing
#

I could always just set the deck to have a ton of slots to begin with, but if there's a way to increase the joker slots that would be best

#

I found plenty of mods with stuff happening after boss blind defeated

graceful magnet
normal crest
normal crest
#

and trying to make it into a playing card

graceful magnet
#

I figured

stray wing
normal crest
#

you can alwyas change the amount of slots by increasing G.jokers.config.card_limit

#

works for any card area

zealous glen
graceful magnet
zealous glen
#

Also Antimatter Voucher does it too

stray wing
normal crest
graceful magnet
normal crest
#

maybe

#

the wiki isn't clear enough on whether it's a single card or a list of cards

graceful magnet
normal crest
#

well the wiki is wrong

#

it's context.cards not card

graceful magnet
normal crest
#

then do context.cards[1], it's a list

#

presumably it's a list

graceful magnet
#

IT WORKED ALKJSHDLAKJS

#

but it only works once

normal crest
graceful magnet
#
    loc_vars = function(self, info_queue, card)
        return { vars = { card.ability.extra.copied } }
    end,
    calculate = function(self, card, context)
            if context.playing_card_added and card.ability.extra.copied == false then
                    G.playing_card = (G.playing_card and G.playing_card + 1) or 1
                    local _card = copy_card(context.cards[1], nil, nil, G.playing_card)
            _card:add_to_deck()
            G.deck.config.card_limit = G.deck.config.card_limit + 1
            table.insert(G.playing_cards, _card)
            G.deck:emplace(_card)
            _card.states.visible = nil
            card.ability.extra.copied = true
            return {
                message = localize('k_copied_ex'),
                colour = G.C.CHIPS,
                --card = self,
                playing_cards_created = {true}
            }        
        elseif context.post_trigger then
            card.ability.extra.copied = false
        end
    end```

I thought the post_trigger would be sufficient to reset it but apparently not
normal crest
#

presumably context.playing_card_added happens only once, and you get all the cards added in context.cards

graceful magnet
#

okay so I just shouldn't need it, gotcha

graceful magnet
normal crest
#

what's your code now

graceful magnet
#
    loc_vars = function(self, info_queue, card)
        return { vars = { card.ability.extra.copied } }
    end,
    calculate = function(self, card, context)
            if context.playing_card_added then
                    G.playing_card = (G.playing_card and G.playing_card + 1) or 1
                    local _card = copy_card(context.cards[1], nil, nil, G.playing_card)
            _card:add_to_deck()
            G.deck.config.card_limit = G.deck.config.card_limit + 1
            table.insert(G.playing_cards, _card)
            G.deck:emplace(_card)
            _card.states.visible = nil
            card.ability.extra.copied = true
            return {
                message = localize('k_copied_ex'),
                colour = G.C.CHIPS,
                --card = self,
                playing_cards_created = {true}
            }        
        end
    end```
sweet nimbus
#

Sorry if this is a basic quesiton but I'm a complete novice

I'm making a mod which adds a deck, I am trying to get it to randomly pick half the cards in the deck and apply a seal to them

any help would be appreciated

normal crest
graceful magnet
#

YES!

#

THANK YOU!

I am

aldkjfhlakdshjf

graceful magnet
normal crest
sweet nimbus
#

For extra context the deck actually applies silver seals to the entire deck, I am trying to implement the Card Sleeves mod and there's a different deck that forces all cards to have a pink seal, so I'm trying to get this new Card Sleeve to apply silver seals to only half the deck


    CardSleeves.Sleeve {
        name = "reverencesleeve",
        key = "reverencesleeve",
        atlas = "sleeves",
        pos = { x = 0, y = 0 },
        config = {},
        unlocked = true,
        apply = function(self)
            local key, vars
            if self.get_current_deck_key() ~= "b_reve_reverence" then
                key = self.key               
                if self.get_current_deck_key() == "b_poke_obituarydeck" then
                        XXXXXXXXXXXXXX
                    G.E_MANAGER:add_event(Event({func = function()
                        G.consumeables.config.card_limit = G.consumeables.config.card_limit + 5
                        return true 
                    end }))
                else
                    G.GAME.modifiers.poke_force_seal = "poke_silver"
                end
            else
                G.E_MANAGER:add_event(Event({func = function()
                    G.consumeables.config.card_limit = G.consumeables.config.card_limit + 2
                    return true end }))
                
            end
        end,
    }
end

the XXXXXXX is where I want the whole "half the deck gets seals" thing to apply

graceful magnet
sweet nimbus
#

ok i dont know how to format code blocks lmao sorry

graceful magnet
#
    loc_vars = function(self, info_queue, card)
        return { vars = { card.ability.extra.copied } }
    end,
    calculate = function(self, card, context)
            if context.playing_card_added then
                    G.playing_card = (G.playing_card and G.playing_card + 1) or 1
                    local _card = copy_card(context.cards[1], nil, nil, G.playing_card)
            _card:add_to_deck()
            G.deck.config.card_limit = G.deck.config.card_limit + 1
            table.insert(G.playing_cards, _card)
            G.deck:emplace(_card)
            return {
                message = localize('k_copied_ex'),
                colour = G.C.CHIPS,
            }        
        end
    end```
normal crest
graceful magnet
graceful magnet
normal crest
#

as in, wrong in steamodded

graceful magnet
#

Hologram uses that context

normal crest
#

add that additional check then

#

and context.cards and context.cards[1]

#

i guess this isn't a steamodded context then

graceful magnet
#

if context.playing_card_added and context.cards and context.cards[1] then yeah?

normal crest
#

yes

graceful magnet
#
            if context.playing_card_added and context.cards and context.cards[1] then
                    G.playing_card = (G.playing_card and G.playing_card + 1) or 1
                    local _card = copy_card(context.cards[1], nil, nil, G.playing_card)
            _card:add_to_deck()
            G.deck.config.card_limit = G.deck.config.card_limit + 1
            table.insert(G.playing_cards, _card)
            G.deck:emplace(_card)
            return {
                message = localize('k_copied_ex'),
                colour = G.C.CHIPS,
            }        
        end
    end```
normal crest
#

copy the hologram's code return too maybe

#

return { your stuff like it is here }, true

#

actually that probably does nothing, but doesn't hurt to try

graceful magnet
#

how much of the stuff, what all should be in it

normal crest
#

just add , true after your closing }

graceful magnet
normal crest
#

otherwise, I guess you're just not getting the cards that were added through your context

graceful magnet
#
            if context.playing_card_added and context.cards and context.cards[1] then
                    G.playing_card = (G.playing_card and G.playing_card + 1) or 1
                    local _card = copy_card(context.cards[1], nil, nil, G.playing_card)
            _card:add_to_deck()
            G.deck.config.card_limit = G.deck.config.card_limit + 1
            table.insert(G.playing_cards, _card)
            G.deck:emplace(_card)
            return {
                message = localize('k_copied_ex'),
                colour = G.C.CHIPS,
            }, true
        end
    end```
normal crest
#

you're just getting sent how many were added and the exception is standard packs

graceful magnet
#

lemme actually check the Spectral cards too, hadn't checked those yet

#

yeah okay they also error

normal crest
#

cryptid should work, looking at the code

graceful magnet
#

it does!

#

only copies one I think?

normal crest
#

well that one is on your code

graceful magnet
#

yeah only copies one of the copies

normal crest
#

anyway you're dealing with localthunk's code here

#

and it seems like there isn't a consistent way for you to get the playing cards added in every situation

graceful magnet
normal crest
#

yes you'd loop through context.cards

#

certificate, marble joker and DNA are the ones that don't seem to send what cards they added to the context

rugged star
#

how does riff-raff generate common jokers only? i see it has the key 'rif' when generating but i don't see how that accomplishes anything

normal crest
#

0 in this case

crisp coral
#

with SMODS.create_card you can pass a string instead of a rarity in case custom rarities mess with it

normal crest
#

yes you can do something like SMODS.add_card { set = 'Joker', rarity = 'Common' }

graceful magnet
# normal crest yes you'd loop through context.cards
            if context.playing_card_added and context.cards then
            for i = 1, #context.cards, 1
            do
                        G.playing_card = (G.playing_card and G.playing_card + 1) or 1
                        local _card = copy_card(context.cards[1], nil, nil, G.playing_card)
                _card:add_to_deck()
                G.deck.config.card_limit = G.deck.config.card_limit + 1
                table.insert(G.playing_cards, _card)
                G.deck:emplace(_card)
                return {
                    message = localize('k_copied_ex'),
                    colour = G.C.CHIPS,
                }, true
            end
        end
    end```
Still only added 1 but I'm 90% I probably just wrote it wrong
normal crest
graceful magnet
#

yeah

#

oop wait

#

lmao I see my blunder

stray wing
graceful magnet
#

needs to be context.cards[i] oops

stray wing
#

thanks for your help Victin, much appreciated 🙂

graceful magnet
normal crest
#

Looks fine, you can skip the , 1 after the loop, pretty sure the default is 1

graceful magnet
#

still only copied once instead of each time

#

yeah, two Cryptid usages, 2 Hearts in deck instead of the desired 4

rugged star
#

is there a function like find_card but it returns every joker corresponding to that key instead of just ones that are currently owned?

normal crest
normal crest
rugged star
#

every joker currently in the game, i mean

#

or in the current pool

normal crest
#

you can do get_current_pool('Joker') and that will be a list of all the jokers in the pool currently

graceful magnet
normal crest
normal crest
#

but I wouldn't know for sure

#

that's the only difference you have from vanilla code

graceful magnet
#

nooope still just makes the one

#

makes the animation play though

#

that's nice

gilded narwhal
#

(barely functional)

#

I'll fix the button placement later btw

#

I know it's shit

graceful magnet
#

might just

#

have to make this one do something else

#

it's a crash hazard right now and doesn't even fully function in the places where it works

normal crest
#

in that list you're supposed to pass the list of cards your joker created

#

so you should store them in a list as you create them and then pass that to the return

normal crest
#

but then it'll just ignore the cards from the types that currently crash the game

graceful magnet
# normal crest yeah... you will either need to make patches to modify the game code, or add a c...
            if context.playing_card_added and context.cards then
            for i = 1, #context.cards
            do
                if type(context.cards[i]) == "table" then
                            G.playing_card = (G.playing_card and G.playing_card + 1) or 1
                            local _card = copy_card(context.cards[i], nil, nil, G.playing_card)
                    _card:add_to_deck()
                    G.deck.config.card_limit = G.deck.config.card_limit + 1
                    table.insert(G.playing_cards, _card)
                    G.deck:emplace(_card)
                    G.E_MANAGER:add_event(Event({
                        func = function()
                            _card:start_materialize()
                            return true
                        end
                    }))
                    return {
                        message = localize('k_copied_ex'),
                        colour = G.C.CHIPS,
                        playing_cards_created = {_card}
                    }, true
                end
            end
        end
    end```

In trying to implement that, definitely did it wrong, it instantly fully closed the game
normal crest
#

your return statement should be outside the for loop and after it

graceful magnet
#

oop nope

normal crest
#

or else you will always return in the first iteration of the loop

graceful magnet
#

just changing {_card} to {true} fixed the crash, yeah definitely not a smart move, running on low though

graceful magnet
#

no crash message, just game closure

normal crest
#

also you can remove the , true that was just to test

graceful magnet
#

moving the return to outside of the for loop also does that apparently

normal crest
#

can you resend what your current code looks like

graceful magnet
#
            if context.playing_card_added and context.cards then
            for i = 1, #context.cards
            do
                if type(context.cards[i]) == "table" then
                            G.playing_card = (G.playing_card and G.playing_card + 1) or 1
                            local _card = copy_card(context.cards[i], nil, nil, G.playing_card)
                    _card:add_to_deck()
                    G.deck.config.card_limit = G.deck.config.card_limit + 1
                    table.insert(G.playing_cards, _card)
                    G.deck:emplace(_card)
                    G.E_MANAGER:add_event(Event({
                        func = function()
                            _card:start_materialize()
                            return true
                        end
                    }))
                    
                end
            end
            return {
                message = localize('k_copied_ex'),
                colour = G.C.CHIPS,
                playing_cards_created = {true}
            }
        end
    end```
normal crest
#

i assume that doesn't crash

graceful magnet
#

it does when a pack card is added

#

about to test other methods

#

Cryptid yes

#

and DNA yeah

#

everything causes total game closure

#

moving the return back into the for loop eliminates the crashes

normal crest
#

I fail to see why that'd be happening, especially with no crash logs

graceful magnet
#

I suspect like an infinite for loop is happening or something

normal crest
#

ah yes, you're right, your joker is recursively triggering itself on every card added

#

what is the specific effect of your joker

#

the description

graceful magnet
#

"Creates an additional copy of each card added to your hand or deck"

normal crest
#

you'll just have to find a way to prevent it from copying the cards it is adding

woeful tundra
#

save a list of the cards you need to copy, then copy the ones in that list, so it doesnt keep adding the newly made ones to the list

normal crest
#

maybe mark the cards with some flag that you can look for before trying to copy

dapper sun
#

what is the text colour used by dna?

fallen pelican
dapper sun
#

ty

graceful magnet
#

it does also work with Magic Trick so that's something at least

smoky talon
#

how do i make a joker play a song? kinda like jimball. Im trying to look at the cryptid code but its a mess

#

i found and adapted the part to declare where the song is in files but dont know how to call it

SMODS.Sound({
key = "music_ksi",
path = "music_ksi.ogg",
sync = false,
pitch = 1,
select_music_track = function()
return next(find_joker("j_gcbm_ksi"))
end,
})

#

this could very well be wrong, just my best guess

#

also dont ask why im making a ksi joker

marble flint
#

well if you're going to draw attention to it, why are you making a ksi joker 👀

gaunt thistle
smoky talon
#

my friend made the art for it and now i feel obligated lmao

gaunt thistle
#

smods wires is all up for you in the background

smoky talon
#

ok i got it to work, just need to know how to make it loop

#

better idea

#

im just gonna loop the song for 10 hours lmao

nova finch
#

I'm trying to make a joker that triggers when the played hand is played for the first time in hte round. Can anyone help? I have no idea what I'm doing at all lmao
i'm copying from card sharp rn and it just does nothing witht his code

woeful tundra
#

I think your calculate function needs to be calculate = function(self, card, context)

dapper sun
#

how do i make a joker do something after the hand is finished playing?

nova finch
void pecan
#

How can I change a color of text in a description of a consumable?

nova finch
dapper sun
stray warren
#

context.after

nova finch
dapper sun
dapper sun
#

does if context.after and context.first_hand_drawn then work?

last badger
#

hey howdy!! brand new to modding in general and lua. trying to write a joker that scales its mult based on how many copies of itself you have. how can i make that happen?

#

taking a peek at the source code is not revealing much. I'm seeing a (find-joker('jokerName')) type deal but not 100% sure what to do with that

#

please @ me, i'm in a lot of servers and i don't mind :)

nova finch
void pecan
dapper sun
#

how do i check how many cards are being played?

stray warren
#

#G.play.cards

dapper sun
#

ty

#

how do i destroy a card?

woven vortex
#

I'm wanting to get into making modded cards, is there somewhere that the lua code for the base game jokers is that I can look at

stray warren
#

I don't remember off the top of my head, but you can look at the code for the hanged man or madness, for example

dapper sun
#

where do i find the code for the vanilla cards?

woeful tundra
#

an easy way is to do card:start_dissolve()

stray warren
#

If you extract the Balatro.exe, you can find the entire source code

woeful tundra
#

but that wont count for card destroyed effects i thinnk

stray warren
#

Yeah, there's more to it than just that for full compatibility

dapper sun
stray warren
#

all of that stuff is under card.lua

#

and most function calls that aren't in that file will be under misc_functions or related files

#

common_events.lua for example

dapper sun
#

ok

dapper sun
void pecan
#

does anyone know how to stop Gimp from doing this? I want it to just be a hard pixel line, no gradient or anything

stray warren
#

Use the pencil tool, not the paintbrush

crisp coral
dapper sun
#

if you want something free, try libresprite

nova finch
#

i'm trying to make a card that gains sell value like egg but it does this rn 😭 can anyone help me?

woeful tundra
#

calling it in the wrong context

last badger
#

If you'd like to, Krita is another great FOSS option.

nova finch
stray warren
woeful tundra
#

if context.end_of_round and context.cardarea == G.jokers then

last badger
#

I don't work with GIMP; my bad.

stray warren
nova finch
nova finch
woeful tundra
stray warren
#

The SMODS wiki docs should probably be pinned in this channel lol

#

It's mentioned about 80 times a day

woeful tundra
#

yeah, lol

paper zealot
nova finch
red flower
dapper sun
#

how do i make it only destroy 1 card?

red flower
#

You want to check if context.destroy_card is the card you want to destroy

novel drum
#

hey, does anyone know if it's possible to activate a joker only when another joker activates?

woeful tundra
#

if context.other_joker then
{
    full_hand = G.play.cards,
    scoring_hand = scoring_hand,
    scoring_name = text,
    poker_hands = poker_hands,
    other_joker = card, --changes to other_consumeable as it iterates over consumeables
}```
#

check to make sure context.other_joker is the specific joker you are looking to trigger off of, then put anything it needs to do as normal

dapper sun
#

what's a better way to test my joker than repeatedly starting runs and hoping to get it from the first store?

gaunt thistle
#

DebugPlus is the way to go

novel drum
#

there's a debug plugin that lets you spawn jokers

gaunt thistle
#

that'll give you save states as well

woeful tundra
#

I just made a deck, and then have it add the joker to my deck

stray warren
#

and item remover to remove items from the pool

novel drum
woeful tundra
#

that gets a bit tricky, but you could try to take ownership of the joker, then give them a new ability variable that only gets set to true when it triggered, then have your new joker check that old jokers variable to see if its true, then set the other jokers triggered variable back to false

#

I have not done this before, but that would be my approach, and is prob not the best way either

#

so something like card.ability.extra.triggered

#

then have the new joker you make check card.ability.extra.triggered in the context i mentioned and only trigger that new joker if its true

runic pecan
#

How do I check if a joker is a food joker other than adding valid food jokers to a list one-by-one?

stray warren
#

That's the neat part - you don't

woeful tundra
#

could take ownership of the existing ones and give them a variabvle like i mentioned above, but that wont work the best for other mods that may add food jokers

void pecan
#

how can I make that text grey?

stray warren
#

C:inactive

dapper sun
#

what am i doing wrong?

calculate = function(self, card, context)
    if context.destroy_card and context.first_hand_drawn and not context.blueprint and #G.play.cards == 1 then
        card.ability.extra.Xmult = card.ability.extra.Xmult + card.ability.extra.Xmult_mod
        return { true }
    end
    if context.joker_main then
        return {
            Xmult = card.ability.extra.Xmult
        }
    end
end```
void pecan
# stray warren `C:inactive`

I feel very dumb...
But where would I put that?

text = { '50% chance to turn every joker polychrome',  '50% chance every joker is destroyed', (this text ->)'(Not affected by dice)'}
south folio
#

Hey guys, I don't know why but when I put context.full_hand:is_face() it keeps crashing if context.before and #context.full_hand == 1 and context.full_hand:is_face() then

scarlet spire
stray warren
#

text = { '50% chance to turn every joker polychrome', '50% chance every joker is destroyed', (this text ->)'{C:inactive}(Not affected by dice)'}

#

You don't technically have to close it there, but it's best practice

scarlet spire
#

true

#

hmm, how do I get all cards from the booster under context.open_booster?

red flower
void pecan
stray warren
#

if context.before and #context.full_hand == 1 and context.full_hand[1]:is_face() then

south folio
stray warren
red flower
#

^

south folio
#

Ohhhhh ok

#

if context.before and context.full_hand[1]:is_face() then like this?

stray warren
#

It's not in the docs, but the balatro source code

#

(I guess it could be in the docs. I haven't checked)

keen coral
#

does there exist a video on how someone created a balatro mod? i tend to work realy well with videos where i can see how ppl navigate the directories of the game (i get so lot all the time in directories LMFAO), so i'd love to watch

paper zealot
#

Any UI geniuses know what's preventing juice_up on my UIBox?

function SystemClock.update_config_panel()
    local panelContents = G.OVERLAY_MENU:get_UIE_by_ID('sysclock_config_panel')
    if not panelContents then return end

    panelContents.config.object:remove()
    panelContents.config.object = UIBox{
        config = {offset = {x = 0, y = 0}, parent = panelContents, juice = true},
        definition = SystemClock.config_panel()
      }
    panelContents.UIBox:recalculate()

    panelContents.UIBox:juice_up(0.5, 0.5)                    --does nothing
    panelContents.config.object:juice_up(0.5, 0.5)            --does nothing
    Moveable.juice_up(panelContents.config.object, 0.5, 0.5)  --does nothing
end

function SystemClock.config_panel()
    return {
        n = G.UIT.ROOT,
        config = { align = 'cm', minw = 11, r = 0.1, emboss = 0.1, colour = G.C.GREY },
        nodes = {
  ---Contains a bunch of child nodes, option_cycles and sliders
        }
    }
end
stray warren
south folio
#

Ahh I see. Thanks! Also uhhh how do I trigger something twice?

void pecan
#

just C doesnt work either

stray warren
woeful tundra
#

in text its dfiferent its gonna be C:color

#

so for you C:gold

nova finch
woeful tundra
#

try a couple print statements, what does context.scoring_name show?

red flower
nova finch
woeful tundra
#

in the console that should open with the modded client

#

should have the game and a console window when it opens

nova finch
#

nothing is printed

woeful tundra
#

can you post the code for the entire joker?

nova finch
woeful tundra
#

puit the print statement before that if statement

#

it seems like the second if statement isnt p[passing the check

scarlet spire
#

I can't seem to figure out how to actually get the cards generated by a booster pack

nova finch
woeful tundra
#

does it make empty lines in the conole? or just nothing happens in the console

west wing
#

Why is my json file broken? What am I doing wrong? what is happening? where am I? I am in the swirly void

west wing
scarlet spire
west wing
#

Wait.

#

Wait, lemme try something

scarlet spire
#

though, let me take a look, I might be doing it wrong

red flower
west wing
#

WHO CHANGED THE DEPENDECY METADATA WHEN I WASN'T LOOKING

#

uuuuuuuughhhhhhhhhh

#

that's how it USED To be written me and my friend have been BASHING our heads against the wall for 48 HOURS WONDERING "why does the thing not thing" why is it because the dependency format changed. dammit

#

sorry, i am angry

plush cove
west wing
#

CURSE YOU DOOFENSHMIRTZZZZZZZZZ

#

genuinely so miffed

#

ughhhh

red flower
# nova finch

I think context.individual never has context.cardarea == G.jokers, do you want it to trigger on every playing card?

timid parrot
#

Seriously tho, what was wrong with the old dependency metadata?

nova finch
woeful tundra
#

so you dont need individual

red flower
#

I think it should be on context.joker_main

nova finch
#

thank you

south folio
#
                G.playing_card = (G.playing_card and G.playing_card + 1) or 1
                local _card = copy_card(context.full_hand[1], nil, nil, G.playing_card)
                _card:add_to_deck()
                G.deck.config.card_limit = G.deck.config.card_limit + 1
                table.insert(G.playing_cards, _card)
                G.hand:emplace(_card)
                _card.states.visible = nil

                G.E_MANAGER:add_event(Event({
                    func = function()
                        _card:start_materialize()
                        return true
                    end
                }))

                return {
                    message = localize('k_copied_ex'),
                    colour = G.C.CHIPS,
                    playing_cards_created = {true},
                }
        end
    end```

How....do I make this copy the card twice?
woeful tundra
#

just do the copy section 2 times 😛

#
                _card:add_to_deck()
                G.deck.config.card_limit = G.deck.config.card_limit + 1
                table.insert(G.playing_cards, _card)
                G.hand:emplace(_card)
                _card.states.visible = nil```
south folio
void pecan
#

anyone know where in the source code the way the wheel works is shown?
I'm making something similar to it but want to get a reference.

woeful tundra
paper zealot
woeful tundra
#

could make it look nicer and do a loop, but honestly dont need to if you only wanna do it 2 times

scarlet spire
#

is there a context for choosing a card from a booster pack? I want to have a joker do something specifically when you do that

#

actually I can probably just check for context.playing_card_added or context.using_consumeable and context.open_booster

south folio
# woeful tundra it should

Ok this kinda works? but it just kinda leaves this hole in the middle that's supposed to be the copied card?

#

it shows up in the full deck, but you can't see it or pick it up

woeful tundra
#

copuld be, try removing: _card.states.visible = nil

void pecan
south folio
woeful tundra
#

these contexts likely dont overlap

scarlet spire
#

yeah, I figured

woeful tundra
#

does it count as buying a card when you pick it from a booster pack

scarlet spire
#

I have no clue

woeful tundra
#

these are the only ones related to boosters/shop

red flower
scarlet spire
#

basically what I'm trying to do is give the player a negative copy of any card they take from a booster pack

red flower
#

I had to lovely patch into G.FUNCS.use_card to do something when picking from boosters

#

maybe you can add your own context there

scarlet spire
#

welp

#

guess i'm finally learning how to lovely patch

void pecan
#
function tarotCard:use(self, card, area, copier)
    for _, c in ipairs(player.inventory) do
        if c.key == 'joker' then
            c:remove_from_deck(self, card, from_debuff)
        end
    end
end

this is just a test, but I am SO confused on the layout of things.
The docs tell me what to use but I don't know how to use them

scarlet spire
red flower
#

button_callbacks

#

try this

[[patches]]
[patches.regex]
target = "functions/button_callbacks.lua"
pattern = '''elseif card.ability.set == 'Joker' then'''
position = 'after'
match_indent = true
payload = '''
SMODS.calculate_context({picking_from_booster = true, card = card})
'''
scarlet spire
#

oh, thanks!

frozen iron
#

greetings fellow balatro enthusiasts, can anyone tell me why it insists I should close my brace here when uh... no I don't think I should?
thanks
(I know this code shouldn't particularly do anything currently other than essentially add a dummy gold stake, I'm just trying to get it to load in the first place before I start tinkering with actually having it do things.)

red flower
#

i think you're missing a couple commas

void pecan
#

how do I check if the player has any jokers?

frozen iron
#

double checked, you're totally right, completely missed at least one at the color line, thanks

scarlet spire
#

it's always the missing commas

#

I miss so many commas

void pecan
plush cove
scarlet spire
#

this might just be an issue with my smods.add_card syntax because I've never used the function before

plush cove
void pecan
plush cove
#

G.jokers.cards is the variable you want

void pecan
plush cove
#

if you mean in terms of joker count

void pecan
plush cove
#

if #G.jokers.cards != 0 then

#

or, if you wanna be more secure, then
if #G.jokers.cards > 0 then

red flower
scarlet spire
#

ah right, that'd be it

red flower
#

had a bunch of these same problems today so I'm glad to reshare the knowledge lol

void pecan
scarlet spire
#

.......well, it works!

#

I should fix this

plush cove
nova finch
#

trying to make a joker that upgrades when an enhanced heart card is scored, would context.check_enhancement work for finding if the card has an enhancement?

void pecan
scarlet spire
red flower
red flower
#

this is that part of the code

scarlet spire
#

hmm, just inserting the same picking_from_booster context after the playing card check gives me some scary featureless playing cards in my joker slot

red flower
#

lol

#

are you using SMODS.add_card?

scarlet spire
#

yeah, is that a bad idea?

#

should it be create_card

red flower
#

it doesn't work with playing cards I'm pretty sure

scarlet spire
#

ah

red flower
#

so you should do add_cards for jokers and consumables and I think it's create_playing_card (no SMODS) for playing cards

nova finch
#

am I checking for enhancements correctly? it's not doing anything rn

red flower
#

shouldn't card.ability.set also be context.other_card.ability.set?

nova finch
#

i'll try that

scarlet spire
#

so create_playing_card is the only way to create a playing card? I have no idea how this works and it isn't documented anywhere

void pecan
#
for key, c in pairs(G.jokers.cards) do
   --how do I destroy the jokers? c:remove_from_deck()?
end
random sleet
#

this is from my Tribute spectral card (destroy all jokers +1 joker slot)

scarlet spire
#

okay, I have this, but I have no clue how i'd make it copy the card, currently it's just random

red flower
#

maybe copy_card is what you actually want but I have never used either so I have no idea

#

Death uses copy_card

scarlet spire
#

oh, that works perfectly

sullen fern
#

scary featureless joker

scarlet spire
#

is this the wrong way to set the card's edition?

scarlet spire
sullen fern
#

keep it until ante 8 for a suprise

scarlet spire
#

would be really funny if it rarely triggered during scoring to keep you confused on what it does

sullen fern
#

yesssss…

void pecan
#

How do I make the tarot say something when used?

sullen fern
#

like the “nope!” when you fail wheel?

void pecan
sullen fern
#

i’m not really well versed in coding but you could ask someone else

chrome widget
#

So I'm gonna work on this more tomorrow, but I thought I might as well ask if anyone has suggestions:

I'm basically a shader noob, but I've followed some basic tutorials before such as when I was using ShaderGraph in Unity. I want to enable a bloom/glow shader on cards contextually. The only shader related stuff I've managed to do so far is add a patch for Card:draw() to use the negative shader for something else when I set a property on a card, but I seem to constantly be running into issues trying to get a new, fresh shader to actually render on something with SMODS

#

The example I found for SMODS is for editions. Am I able to just set a "shader" property on jokers and have it draw that shader the same way, or are editions special in that regard?

scarlet spire
#

this is how i've been drawing shaders on non-editions

scarlet spire
#

when referring to the key it should have your mod prefix

chrome widget
#

Okay yeah I did the defining it but, guh, I forgot to use the prefix

#

And when defining that draw function, is that just in the joker definition?

scarlet spire
#

yep

chrome widget
#

Oh, neat. I didn't know it was that easy, though obv I was handicapping myself accidentally

#

I attempted something similar before but kept getting nil for draw_shader, but I don't think I was calling it from children.center

scarlet spire
#

I havent tried it on jokers yet but it should work exactly the same since it's just a base function

void pecan
#

how do I make my tarot say something like wheel of fortune 7771ahhhh
Anyone know

chrome widget
#

Okay this is a decent start, I'll see if I can try this again tomorrow. Thank you!!

chrome widget
#

So the code for this in the vanilla game is basically this:

    trigger = 'after', 
    delay = 0.4, 
    func = function()
    attention_text({
        text = localize([put localization string here]),
        scale = 1.3, 
        hold = 1.4,
        major = card,
        backdrop_colour = G.C.SECONDARY_SET.Tarot,
        align = (G.STATE == G.STATES.TAROT_PACK or G.STATE == G.STATES.SPECTRAL_PACK) and 'tm' or 'cm',
        offset = {x = 0, y = (G.STATE == G.STATES.TAROT_PACK or G.STATE == G.STATES.SPECTRAL_PACK) and -0.2 or 0},
        silent = true
        })
    G.E_MANAGER:add_event(Event({
        trigger = 'after',
        delay = 0.06 * G.SETTINGS.GAMESPEED,
        blockable = false,
        blocking = false, 
        func = function()
            play_sound('tarot2', 0.76, 0.4);
        return true end}))
    play_sound('tarot2', 1, 0.4)
    card:juice_up(0.3, 0.5)
return true end }))```
#

Basically it just uses the attention_text() function with a bunch of values, with align and offset differing based on whether or not it's being used from the pack or directly from its current position, and then it nests another function for the sound in it for some reason

#

So

  • attention_text() with your localization string
  • play_sound('tarot2')
  • card:juice_up()
chrome widget
#

It's what causes cards to shake when you do things with them

plush cove
#

i.e. when Invisible Joker is ready to sell, or when DNA is ready to copy

#

or Trading Card is ready to destroy

void pecan
#

so I would do

function tarotCard:use(card)
    chance = math.random(1,2)
    if chance == 1 then
        for key, c in pairs(G.jokers.cards) do
            c:set_edition({polychrome = true})
        end
    else
        for key, c in pairs(G.jokers.cards) do
            attention_text(text = localize([not sure what you mean here, like any string?]), scale = 1.3
            c:start_dissolve()
        end
    end
end
#

I forgot the juice up

plush cove
scarlet spire
#

localize([ ]) is for is you have stuff in localization files

#

to just use a string replace all of that with ''

chrome widget
#

So like I'm not developing in multiple languages or anything, but yeah I have all my stuff stored in en-us.lua, and most of the card effect strings are k_[something]

scarlet spire
#

(text = 'text here')

chrome widget
#

I.E. k_nope_ex is WoF's

gaunt thistle
# scarlet spire oh, thanks!

test to make sure that you can replace that with a normal pattern patch. regex patches are slower and have more footguns.

#

it looks like a normal pattern patch will do just fine

scarlet spire
#

I did notice that, but was afraid to touch it

#

will check

#

just replace regex with pattern?

gaunt thistle
#

ya

#

[patch.pattern]

#

that patch has pattern fields anyways, it shouldn't be a regex

scarlet spire
#

I am actually having one more issue with it that I'm unsure how to fix

#

the patch works perfectly for jokers and playing cards, when injecting that line here and here

#

doing this successfully adds contexts for getting jokers and playing cards from booster packs

void pecan
#

what did i do sadHamster

scarlet spire
#

but doing the same for consumables (under if card.ability.consumeable then) causes it to trigger when any consumable is used while you're in a booster pack menu (and it seems to do it twice??) even if the consumable is in a consumable slot

chrome widget
#

attention_text takes a table as its parameter, not individual parameters

#

Add braces around the two values you passed in

void pecan
chrome widget
#

Yeah

void pecan
frosty dock
void pecan
#

THE SECOND I saved it went away

scarlet spire
#

I am way in over my head trying to figure this out

#

I'm not entirely sure why the consumables act differently but I guess it's just because they're consumable

chrome widget
#

Lo and behold, it is doing... something

#

It's drawing it a second time for the shader effect at the very least, which is progress

#

Thank you Wheat!

#

the only other shader related thing I've managed was screwing around with using the default dissolve shader to make this, but actually applying a unique shader rather than leveraging existing ones is much harder

#

Work for tomorrow

scarlet spire
#

ooh that's neat

void pecan
#

how can I give myself my tarot card? Is it possible? Using DebugPlus

scarlet spire
#

go into the collection and press 3 while hovering over it

scarlet spire
#

actually I think you might need to enable the base game's debug menu (which debugplus also has a bunch of additions to) in order for those binds to work?

void pecan
#
function tarotCard:use(card)
    chance = math.random(1,2)
    if chance == 1 then
        for key, c in pairs(G.jokers.cards) do
            attention_text({text = "Accepted", scale = 1.3, hold = 1.4})
            play_sound('tarot2')
            c:juice_up()
            c:set_edition({polychrome = true})
        end
    else
        for key, c in pairs(G.jokers.cards) do
            attention_text({text = "Rejected", scale = 1.3, hold = 1.4})
            play_sound('tarot2')
            c:juice_up()
            c:start_dissolve()
        end
    end
end

My tarot card doesn't say anything, but no errors.
It kind just skips all of that somehow and immediately either destroys or turns all cards poly

scarlet spire
#

does anything point to this function?

chrome widget
# sullen fern thats cool actually

It works well for what it is! Now I'm just trying to get a simple bloom shader up and running so I can make some jokers glow because somebody requested it. I hate shaders I hate shaders I hate shaders

void pecan
scarlet spire
#

the way to calculate stuff when using a tarot card is

        (code here)
void pecan
scarlet spire
#

so it sets polychrome sometimes?

void pecan
#

it will still be a 50/50 of destroy and poly, card just doesn't speak

scarlet spire
#

I would still try restructuring it as ```lua
SMODS.Consumable {
---everything else here---
use = function(self, card, area, copier)
chance = math.random(1,2)
if chance == 1 then
for key, c in pairs(G.jokers.cards) do
attention_text({text = "Accepted", scale = 1.3, hold = 1.4})
play_sound('tarot2')
c:juice_up()
c:set_edition({polychrome = true})
end
else
for key, c in pairs(G.jokers.cards) do
attention_text({text = "Rejected", scale = 1.3, hold = 1.4})
play_sound('tarot2')
c:juice_up()
c:start_dissolve()
end
end
end
}

violet void
scarlet spire
#

that could be it too

#

your play sound and juice up functions are missing parameters too, I think that just means they'll be nil, unsure if that's a big deal or not

void pecan
#
local tarotCard = SMODS.Consumable({
    key = "tarot_card_joker_effect",
    set = 'Tarot',
    atlas = 'sigma', pos = { x = 0, y = 0 },
    cost = 0,
    loc_txt = {
        name = 'Balance',
        text = { '{C:green}50% {}chance to turn every {C:gold}Joker{} {C:dark_edition}polychrome',  '{C:green}50% {}chance every {C:gold}Joker{} is {C:red}destroyed', '{C:inactive}(Not affected by dice)'} --Would also appreciate help on colors, couldn't find it on docs
    },
    unlocked = true,
    discovered = true,

    
    can_use = function(self, card)
        if #G.jokers.cards > 0 then
            return true
        else
            return false
        end
    

    use = function(self, card, area, copier)
        chance = math.random(1,2)
        if chance == 1 then
            for key, c in pairs(G.jokers.cards) do
                attention_text({text = "Accepted", scale = 1.3, hold = 1.4})
                play_sound('tarot2')
                c:juice_up()
                c:set_edition({polychrome = true})
            end
        else
            for key, c in pairs(G.jokers.cards) do
                attention_text({text = "Rejected", scale = 1.3, hold = 1.4})
                play_sound('tarot2')
                c:juice_up()
                c:start_dissolve()
            end
        end
    end
})

wrefgougf3w4eiroyugbw3ree4gewGQ

#

nvm forgot end and comma

#

perfect

#

Very first tarot done, it was simple but very good for learning

normal crest
#

can_use can be simplified to return #G.jokers.cards > 0

scarlet spire
#

I'm actually getting quite confused by this code (which is for pulling cards from booster packs)

#

the latter two elseifs I understand

#

well, actually, hm

#

what I'm trying to do is patch this so that it has a context specifically for using one from a booster pack

#

but it seems there's no distinction logically from using one that came from a booster pack and just using a consumable you already had in your consumable slot, while in the booster pack interface

normal crest
#

you might be able to check if card.added_to_deck

scarlet spire
#

that's true, I can't think of any circumstances where a consumable activating without being in your deck isn't from a booster pack

normal crest
#

you can also check card.area ~= G.consumeables

#

i haven't tried it tho

#

hope it works

#

good luck

scarlet spire
#

I tried it as just card.area too and it did the same thing

#

would it be card.config.area? maybe?

#

nope

wintry solar
#

context.consumeable.area iirc

scarlet spire
#

oh huh, I see

wintry solar
#

I’d check if it was equal to G.pack_cards otherwise shop uses would trigger too

normal crest
#

yeah it's passed as context.consumeable

scarlet spire
#

ah that's true too, good catch

void pecan
plush cove
#

pseudorandom is what's used for actual randomization in vanilla balatro

#

and it plays better with seeded runs

scarlet spire
#

but consumables just act normally and never trigger this

normal crest
#

If you don't, then you can just reset the game forever until you get the desired outcome

#

And seeded runs will not work with it

crystal perch
#

quick question anyone know the colour tag of whatever ecto uses for the negative text?

normal crest
#

dark_edition

crystal perch
#

thank you that worked balatroheart

scarlet spire
#

this is getting really confusing?

#

oops, bad crop

#

if I go back to the old thing of just checking if it isnt in the consumables slot

#

it suddenly works, but now always triggers, even when in the consumable slot

#

which makes absolutely no sense

normal crest
#

Maybe they get removed from their area before being used, which would make this more difficult

scarlet spire
#

checking if it's in g.pack_cards causes it to never occur even if it's in a pack, and checking if it's not in the g.consumeables causes it to always occur even if in the consumables slot

#

so... it's going somewhere else regardless of where it came from

#

just what I needed

normal crest
#

do you have debug plus

scarlet spire
#

yep

normal crest
#

Try print(blahblah.area) right after the context check

scarlet spire
#

just prints an empty line

#

so... it just removes it from anything?

#

great

normal crest
#

I guess, you'd have to look at the use consumeable function to see exactly what it's doing

wintry solar
#

It might be in G.play

scarlet spire
#

ah yeah literally right before the calculate

normal crest
#

Bruh

wintry solar
#

Oh that’s a pain

scarlet spire
#

I wonder what would happen if I literally just patched this line out

#

lets try!

normal crest
#

I don't know if removing the line is a good solution

wintry solar
#

Just patch a last area value before it

scarlet spire
#

probably not but i'm curious what'll happen so I can't not try

#

wait smods actually patches this line with something else already

normal crest
#

You should look at Mods/lovely/dump

#

For the code after all lovely patched were applied

worthy anchor
#

given a standard playing card what's the best way to get it's rank, suit, enhancement, ability, and seal?

and worse: not just get the in game values, but the actual words used for them, like "spades" and "steel" and "red seal"

scarlet spire
#

ah I didn't know about that, thanks

crystal perch
#

i thinks

normal crest
#

And you can get the text form of them by doing card.base.value for rank and card.base.suit

#

If you're going to display that text I strongly recommend localizing it by paasing it to localize with "ranks" or "suits_plural" (or singular) as the 2nd argument

plush cove
#

heya! so I've coded this blind called "The Journey" and it's meant to function so that each consecutive hand must not have a lower base score than the last one

however, I've discovered that if one was to: play a hand, close the game, then re-open it and load back into the save, their hands were no longer debuffed, essentially ruining the entire point of the blind

is there a fix for this so that the score requirement carries through even after the game is closed?

scarlet spire
# wintry solar Just patch a last area value before it

this is working, but there's one last, extremely odd issue. here's my patch
origin is the original area value, and i'm passing it through the context for debugging purposes
for some reason, consumables that are bought directly from the shop appear to pass this check, meaning origin == G.pack_cards (somehow??)
but then, once you open any booster pack, consumables from the shop will no longer pass this check, and everything works as intended

wintry solar
#

How are you checking they pass?

plush cove
scarlet spire
#

then later on, checking if origin == G.pack_cards, and if so, setting the consumable_from_booster context to true

wintry solar
#

I'd just do something like

if card.area == G.pack_cards then card.from_pack = true end```
scarlet spire
#

hmm, true

wintry solar
#

then in your calculate check for

if context.consumeable.from_pack then```
crystal perch
#

trying to make my custom consumables all use a shader at all times by injecting through lovely, but it isn't working. any help?

[manifest]
version = "1.0.0"
dump_lua = true
priority = 0

[[patches]] #   CHAK
[patches.pattern]
target = "card"
pattern = '''function Card:draw(layer)'''
position = "at"
payload = '''
--  CHAK START
local card_drawref = Card.draw
function Card:draw(layer)
    local card_drawref = card_drawref(self, layer)
    if (layer == 'card' or layer == 'both') then
        if card.sprite_facing == 'front' then
            if card.consumable.set == 'ChakraConsumableType' then
                card.children.center:draw_shader('booster', nil, card.ARGS.send_to_shader)
            end
        end
    end
    return card_drawref
-- CHAK END
'''
match_indent = true
wintry solar
#

why are you trying to insert a hook over the definition of card draw?

crystal perch
#

imma be so fr it is 5:37 in the morning i am not liable for being stupid

#

i jus wanna get this done

#

but yeah i'll move it to within card draw, see what happens

wintry solar
#

either way, you want a patch like this

## Mythos Draw Shader
[[patches]]
[patches.pattern]
target = 'card.lua'
pattern = '''if (self.ability.set == 'Voucher' or self.config.center.demo) and (self.ability.name ~= 'Antimatter' or not (self.config.center.discovered or self.bypass_discovery_center)) then'''
position = 'before'
match_indent = true
payload = '''
if self.ability.set == 'Mythos' then
    self.children.center:draw_shader('ortalab_mythos', nil, self.ARGS.send_to_shader)
end
'''
crystal perch
#

thanks i'll try this code out, i got the majority of the other code from somewhere else in the server

scarlet spire
wintry solar
#

specifically shop consumables?

scarlet spire
#

yes

#

for some reason, card.area == G.pack_card for consumables in shop until you use a booster pack

#

but also that can't be true??

#

I don't know

plush cove
crystal perch
#

you're my goat

fallen pelican
#

is update the only method to live update variables like these in a joker?

crisp coral
#

without hooking to the save and load functions, these are (two of) the few variable names that get saved

wintry solar
crisp coral
#

i think when you buy it from shop the area is saved as G.shop_jokers, which gets nil'd after the shop ends while G.pack_card is also nil when not opening a pack

scarlet spire
#

so, I should have an or card.area ~= G.shop_jokers in the if statement?

crisp coral
#

card.area will be G.consumeables after being bought/taken from pack

#

so that doesnt make sense

wintry solar
#

we're looking at being used though

crisp coral
#

o

#

buy and use?

wintry solar
#

if you use a card from the shop, it has area of pack_card until you've opened a booster

#

or at least, in the use function it does

crisp coral
#

qhar...

scarlet spire
#

the idea I'm implementing is that if you use a consumable from a booster pack, you get a negative copy of it

plush cove
scarlet spire
#

this logic works correctly only after you've already opened a booster pack, if you haven't done that yet, card.area == G.pack_cards will be true even if it's in the shop

#

but, not if it's in the consumables slots, that works fine

#

only the shop

wintry solar
#

let me check something

crisp coral
#

huhh

scarlet spire
crisp coral
#

yeah when used from shop the card's area is nil

#

wait no

#

fuck

#

eval dp.hovered doesnt work because the card cant be hovered

wintry solar
crisp coral
#

awful

wintry solar
#

where the fuck does it go after you use a booster

plush cove
scarlet spire
#

using a consumable always sets its area to nil, so i'm saving whether or not it was in a booster pack in card.from_pack before it ever sets as nil

plush cove
#

so i'm stuck with it being spaghetti

wintry solar
#

why does it think it's from a booster until you open a booster

random sleet
#

oh damn is that why an oddity was being weird with buy and use earlier

wintry solar
#

how is this possible

scarlet spire
#

????

violet void
# wintry solar o_O

are you flipping, selecting, unflipping and unselecting to make them jump like that

wintry solar
violet void
#

very creative

scarlet spire
#

ooh that is a very satisfying flip